Example #1
0
int main(int argc, char **argv)
{
	char *basename, *outname;
	int ch, ret, show_version = 0, verbose = 0;
	struct sepol_policy_file *pf;
	sepol_module_package_t *base;
	sepol_policydb_t *out, *p;
	FILE *fp, *outfile;
	int check_assertions = 1;
	sepol_handle_t *handle;

	while ((ch = getopt(argc, argv, "c:Vva")) != EOF) {
		switch (ch) {
		case 'V':
			show_version = 1;
			break;
		case 'v':
			verbose = 1;
			break;
		case 'c':{
				long int n = strtol(optarg, NULL, 10);
				if (errno) {
					fprintf(stderr,
						"%s:  Invalid policyvers specified: %s\n",
						argv[0], optarg);
					usage(argv[0]);
					exit(1);
				}
				if (n < sepol_policy_kern_vers_min()
				    || n > sepol_policy_kern_vers_max()) {
					fprintf(stderr,
						"%s:  policyvers value %ld not in range %d-%d\n",
						argv[0], n,
						sepol_policy_kern_vers_min(),
						sepol_policy_kern_vers_max());
					usage(argv[0]);
					exit(1);
				}
				policyvers = n;
				break;
			}
		case 'a':{
				check_assertions = 0;
				break;
			}
		default:
			usage(argv[0]);
		}
	}

	if (verbose) {
		if (policyvers)
			printf("Building version %d policy\n", policyvers);
	}

	if (show_version) {
		printf("%s\n", EXPANDPOLICY_VERSION);
		exit(0);
	}

	/* check args */
	if (argc < 3 || !(optind != (argc - 1))) {
		fprintf(stderr,
			"%s:  You must provide the base module package and output filename\n",
			argv[0]);
		usage(argv[0]);
	}

	basename = argv[optind++];
	outname = argv[optind];

	handle = sepol_handle_create();
	if (!handle)
		exit(1);

	if (sepol_policy_file_create(&pf)) {
		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
		exit(1);
	}

	/* read the base module */
	if (sepol_module_package_create(&base)) {
		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
		exit(1);
	}
	fp = fopen(basename, "r");
	if (!fp) {
		fprintf(stderr, "%s:  Can't open '%s':  %s\n",
			argv[0], basename, strerror(errno));
		exit(1);
	}
	sepol_policy_file_set_fp(pf, fp);
	ret = sepol_module_package_read(base, pf, 0);
	if (ret) {
		fprintf(stderr, "%s:  Error in reading package from %s\n",
			argv[0], basename);
		exit(1);
	}
	fclose(fp);

	/* linking the base takes care of enabling optional avrules */
	p = sepol_module_package_get_policy(base);
	if (sepol_link_modules(handle, p, NULL, 0, 0)) {
		fprintf(stderr, "%s:  Error while enabling avrules\n", argv[0]);
		exit(1);
	}

	/* create the output policy */

	if (sepol_policydb_create(&out)) {
		fprintf(stderr, "%s:  Out of memory\n", argv[0]);
		exit(1);
	}

	sepol_set_expand_consume_base(handle, 1);

	if (sepol_expand_module(handle, p, out, verbose, check_assertions)) {
		fprintf(stderr, "%s:  Error while expanding policy\n", argv[0]);
		exit(1);
	}

	if (policyvers) {
		if (sepol_policydb_set_vers(out, policyvers)) {
			fprintf(stderr, "%s:  Invalid version %d\n", argv[0],
				policyvers);
			exit(1);
		}
	}

	sepol_module_package_free(base);

	outfile = fopen(outname, "w");
	if (!outfile) {
		perror(outname);
		exit(1);
	}

	sepol_policy_file_set_fp(pf, outfile);
	ret = sepol_policydb_write(out, pf);
	if (ret) {
		fprintf(stderr,
			"%s:  Error while writing expanded policy to %s\n",
			argv[0], outname);
		exit(1);
	}
	fclose(outfile);
	sepol_handle_destroy(handle);
	sepol_policydb_free(out);
	sepol_policy_file_free(pf);

	return 0;
}
Example #2
0
/* Commits all changes in sandbox to the actual kernel policy.
 * Returns commit number on success, -1 on error.
 */
static int semanage_direct_commit(semanage_handle_t *sh) {
	char **mod_filenames = NULL;
	const char *linked_filename = NULL, *ofilename = NULL;
	sepol_module_package_t *base = NULL;
	int retval = -1, num_modfiles = 0, i;
	sepol_policydb_t* out = NULL;

	/* Declare some variables */
	int modified, fcontexts_modified, ports_modified, 
		seusers_modified, users_extra_modified;
	dbase_config_t* users = semanage_user_dbase_local(sh);
	dbase_config_t* users_base = semanage_user_base_dbase_local(sh);
	dbase_config_t* pusers_base = semanage_user_base_dbase_policy(sh);
	dbase_config_t* users_extra = semanage_user_extra_dbase_local(sh);
	dbase_config_t* pusers_extra = semanage_user_extra_dbase_policy(sh);
	dbase_config_t* ports = semanage_port_dbase_local(sh);
	dbase_config_t* pports = semanage_port_dbase_policy(sh);
	dbase_config_t* bools = semanage_bool_dbase_local(sh);
	dbase_config_t* pbools = semanage_bool_dbase_policy(sh);
	dbase_config_t* ifaces = semanage_iface_dbase_local(sh);
	dbase_config_t* pifaces = semanage_iface_dbase_policy(sh);
	dbase_config_t* nodes = semanage_node_dbase_local(sh);
	dbase_config_t* pnodes = semanage_node_dbase_policy(sh);
	dbase_config_t* fcontexts = semanage_fcontext_dbase_local(sh);
	dbase_config_t* pfcontexts = semanage_fcontext_dbase_policy(sh);
	dbase_config_t* seusers = semanage_seuser_dbase_local(sh);
	dbase_config_t* pseusers = semanage_seuser_dbase_policy(sh);

	/* Before we do anything else, flush the join to its component parts.
	 * This *does not* flush to disk automatically */
	if (users->dtable->is_modified(users->dbase) &&
	    users->dtable->flush(sh, users->dbase) < 0)
		goto cleanup;

	/* Decide if anything was modified */
	fcontexts_modified = fcontexts->dtable->is_modified(fcontexts->dbase);
	seusers_modified = seusers->dtable->is_modified(seusers->dbase);
	users_extra_modified = users_extra->dtable->is_modified(users_extra->dbase);
	ports_modified = ports->dtable->is_modified(ports->dbase);

	modified = sh->modules_modified;
	modified |= ports_modified;
	modified |= users->dtable->is_modified(users_base->dbase);
	modified |= bools->dtable->is_modified(bools->dbase);
	modified |= ifaces->dtable->is_modified(ifaces->dbase);
	modified |= nodes->dtable->is_modified(nodes->dbase);

	/* FIXME: get rid of these, once we support loading the existing policy,
	 * instead of rebuilding it */
	modified |= seusers_modified;
	modified |= fcontexts_modified;
	modified |= users_extra_modified;

	/* If there were policy changes, or explicitly requested, rebuild the policy */
	if (sh->do_rebuild || modified) {

		/* =================== Module expansion =============== */

		/* link all modules in the sandbox to the base module */
		if (semanage_get_modules_names(sh, &mod_filenames, &num_modfiles) != 0 ||
		    semanage_verify_modules(sh, mod_filenames, num_modfiles) == -1 ||
		    semanage_link_sandbox(sh, &base) < 0) {
			goto cleanup;
		}
	
		/* write the linked base */
		if ((linked_filename = semanage_path(SEMANAGE_TMP, SEMANAGE_LINKED)) == NULL ||
		    semanage_write_module(sh, linked_filename, base) == -1 ||
		    semanage_verify_linked(sh) != 0) {
			goto cleanup;
		}

		/* ==================== File-backed ================== */

		/* File Contexts */
		if ((ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL)) == NULL ||
		    write_file(sh, ofilename, sepol_module_package_get_file_contexts(base), 
				sepol_module_package_get_file_contexts_len(base)) == -1) {
			goto cleanup;
		}

		if (semanage_split_fc(sh)) 
			goto cleanup;

		pfcontexts->dtable->drop_cache(pfcontexts->dbase);

		/* Seusers */
		if (sepol_module_package_get_seusers_len(base)) {
			if ((ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_SEUSERS)) == NULL ||
			    write_file(sh, ofilename, sepol_module_package_get_seusers(base), 
					sepol_module_package_get_seusers_len(base)) == -1) {
				goto cleanup;
			}
			pseusers->dtable->drop_cache(pseusers->dbase);

		} else {
			if (pseusers->dtable->clear(sh, pseusers->dbase) < 0)
				goto cleanup;
		}

		/* Users_extra */
		if (sepol_module_package_get_user_extra_len(base)) {
			if ((ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA)) == NULL ||
			    write_file(sh, ofilename, sepol_module_package_get_user_extra(base), 
					sepol_module_package_get_user_extra_len(base)) == -1) {
				goto cleanup;
			}
			pusers_extra->dtable->drop_cache(pusers_extra->dbase);

		} else {
			if (pusers_extra->dtable->clear(sh, pusers_extra->dbase) < 0)
				goto cleanup;
		}

		/* ==================== Policydb-backed ================ */

		/* Create new policy object, then attach to policy databases
		 * that work with a policydb */
		if (semanage_expand_sandbox(sh, base, &out) < 0)
			goto cleanup;

		dbase_policydb_attach((dbase_policydb_t*) pusers_base->dbase, out);
		dbase_policydb_attach((dbase_policydb_t*) pports->dbase, out);
		dbase_policydb_attach((dbase_policydb_t*) pifaces->dbase, out);
		dbase_policydb_attach((dbase_policydb_t*) pbools->dbase, out);
		dbase_policydb_attach((dbase_policydb_t*) pnodes->dbase, out);

		/* ============= Apply changes, and verify  =============== */

		if (semanage_base_merge_components(sh) < 0)
			goto cleanup;

		if (semanage_write_policydb(sh, out) < 0)
			goto cleanup;

		if (semanage_verify_kernel(sh) != 0)
			goto cleanup;
	}

	/* FIXME: else if !modified, but seusers_modified, 
	 * load the existing policy instead of rebuilding */

	/* ======= Post-process: Validate non-policydb components ===== */

	/* Validate local modifications to file contexts.
	 * Note: those are still cached, even though they've been 
	 * merged into the main file_contexts. We won't check the 
	 * large file_contexts - checked at compile time */
	if (sh->do_rebuild || modified || fcontexts_modified) {
		if (semanage_fcontext_validate_local(sh, out) < 0)
			goto cleanup;
	}

	/* Validate local seusers against policy */
	if (sh->do_rebuild || modified || seusers_modified) {
		if (semanage_seuser_validate_local(sh, out) < 0) 
			goto cleanup;
	}

	/* Validate local ports for overlap */
	if (sh->do_rebuild || ports_modified) {
		if (semanage_port_validate_local(sh) < 0)
			goto cleanup;
	}

	/* ================== Write non-policydb components ========= */

	/* Commit changes to components */
	if (semanage_commit_components(sh) < 0)
		goto cleanup;

	retval = semanage_install_sandbox(sh);

 cleanup:
	for (i = 0; mod_filenames != NULL && i < num_modfiles; i++) {
		free(mod_filenames[i]);
	}

	/* Detach from policydb, so it can be freed */
	dbase_policydb_detach((dbase_policydb_t*) pusers_base->dbase);
	dbase_policydb_detach((dbase_policydb_t*) pports->dbase);
	dbase_policydb_detach((dbase_policydb_t*) pifaces->dbase);
	dbase_policydb_detach((dbase_policydb_t*) pnodes->dbase);
	dbase_policydb_detach((dbase_policydb_t*) pbools->dbase);

	free(mod_filenames);
	sepol_module_package_free(base);
	sepol_policydb_free(out);
	semanage_release_trans_lock(sh);

	/* regardless if the commit was successful or not, remove the
	   sandbox if it is still there */
	semanage_remove_directory(semanage_path(SEMANAGE_TMP, SEMANAGE_TOPLEVEL));
	return retval;
}