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; }
/* 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; }