static sepol_module_package_t *load_module(char *filename) { int ret; FILE *fp = NULL; struct sepol_policy_file *pf = NULL; sepol_module_package_t *p = NULL; if (sepol_module_package_create(&p)) { fprintf(stderr, "%s: Out of memory\n", progname); goto bad; } if (sepol_policy_file_create(&pf)) { fprintf(stderr, "%s: Out of memory\n", progname); goto bad; } fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "%s: Could not open package %s: %s", progname, filename, strerror(errno)); goto bad; } sepol_policy_file_set_fp(pf, fp); printf("%s: loading package from file %s\n", progname, filename); ret = sepol_module_package_read(p, pf, 0); if (ret) { fprintf(stderr, "%s: Error while reading package from %s\n", progname, filename); goto bad; } fclose(fp); sepol_policy_file_free(pf); return p; bad: sepol_module_package_free(p); sepol_policy_file_free(pf); if (fp) fclose(fp); return NULL; }
int main(int argc, char **argv) { struct sepol_module_package *pkg; struct sepol_policy_file *mod, *out; char *module = NULL, *file_contexts = NULL, *seusers = NULL, *user_extra = NULL; char *fcdata = NULL, *outfile = NULL, *seusersdata = NULL, *user_extradata = NULL; size_t fclen = 0, seuserslen = 0, user_extralen = 0; int i; static struct option opts [] = { {"module", required_argument, NULL, 'm'}, {"fc", required_argument, NULL, 'f'}, {"seuser", required_argument, NULL, 's'}, {"user_extra", required_argument, NULL, 'u'}, {"outfile", required_argument, NULL, 'o'}, {"help", 0, NULL, 'h'}, {NULL, 0, NULL, 0} }; while ((i = getopt_long(argc, argv, "m:f:s:u:o:h", opts, NULL)) != -1) { switch (i) { case 'h': usage(argv[0]); exit(0); case 'm': if (module) { fprintf(stderr, "May not specify more than one module\n"); exit(1); } module = strdup(optarg); if (!module) exit(1); break; case 'f': if (file_contexts) { fprintf(stderr, "May not specify more than one file context file\n"); exit(1); } file_contexts = strdup(optarg); if (!file_contexts) exit(1); break; case 'o': if (outfile) { fprintf(stderr, "May not specify more than one output file\n"); exit(1); } outfile = strdup(optarg); if (!outfile) exit(1); break; case 's': if (seusers) { fprintf(stderr, "May not specify more than one seuser file\n"); exit(1); } seusers = strdup(optarg); if (!seusers) exit(1); break; case 'u': if (user_extra) { fprintf(stderr, "May not specify more than one user_extra file\n"); exit(1); } user_extra = strdup(optarg); if (!user_extra) exit(1); } } progname = argv[0]; if (!module || !outfile) { usage(argv[0]); exit(0); } if (file_contexts) { if (file_to_data(file_contexts, &fcdata, &fclen)) exit(1); } if (seusers) { if (file_to_data(seusers, &seusersdata, &seuserslen)) exit(1); } if (user_extra) { if (file_to_data(user_extra, &user_extradata, &user_extralen)) exit(1); } if (file_to_policy_file(module, &mod, "r")) exit(1); if (sepol_module_package_create(&pkg)) { fprintf(stderr, "%s: Out of memory\n", argv[0]); exit(1); } if (sepol_policydb_read(sepol_module_package_get_policy(pkg), mod)) { fprintf(stderr, "%s: Error while reading policy module from %s\n", argv[0], module); exit(1); } if (fclen) sepol_module_package_set_file_contexts(pkg, fcdata, fclen); if (seuserslen) sepol_module_package_set_seusers(pkg, seusersdata, seuserslen); if (user_extra) sepol_module_package_set_user_extra(pkg, user_extradata, user_extralen); if (file_to_policy_file(outfile, &out, "w")) exit(1); if (sepol_module_package_write(pkg, out)) { fprintf(stderr, "%s: Error while writing module package to %s\n", argv[0], argv[1]); exit(1); } if (fclen) munmap(fcdata, fclen); sepol_policy_file_free(mod); sepol_policy_file_free(out); sepol_module_package_free(pkg); free(file_contexts); free(outfile); free(module); exit(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; }
int sepol_module_package_info(struct sepol_policy_file *spf, int *type, char **name, char **version) { struct policy_file *file = &spf->pf; sepol_module_package_t *mod = NULL; uint32_t *buf, len, nsec; size_t *offsets = NULL; unsigned i, seen = 0; if (sepol_module_package_create(&mod)) return -1; if (module_package_read_offsets(mod, file, &offsets, &nsec)) { goto cleanup; } for (i = 0; i < nsec; i++ ) { if (policy_file_seek(file, offsets[i])) { ERR(file->handle, "error seeking to offset " "%zu for module package section %u", offsets[i], i); goto cleanup; } len = offsets[i + 1] - offsets[i]; if (len < sizeof(uint32_t)) { ERR(file->handle, "module package section %u has too small length %u", i, len); goto cleanup; } /* read the magic number, so that we know which function to call */ buf = next_entry(file, sizeof(uint32_t) * 2); if (!buf) { ERR(file->handle, "module package section %u truncated, lacks magic number", i); goto cleanup; } switch(le32_to_cpu(buf[0])) { case SEPOL_PACKAGE_SECTION_FC: /* skip file contexts */ if (seen & SEEN_FC) { ERR(file->handle, "found multiple file contexts sections in module package (at section %u)", i); goto cleanup; } seen |= SEEN_FC; break; case SEPOL_PACKAGE_SECTION_SEUSER: /* skip seuser */ if (seen & SEEN_SEUSER) { ERR(file->handle, "found seuser sections in module package (at section %u)", i); goto cleanup; } seen |= SEEN_SEUSER; break; case SEPOL_PACKAGE_SECTION_USER_EXTRA: /* skip user_extra*/ if (seen & SEEN_USER_EXTRA) { ERR(file->handle, "found user_extra sections in module package (at section %u)", i); goto cleanup; } seen |= SEEN_USER_EXTRA; break; case POLICYDB_MOD_MAGIC: if (seen & SEEN_MOD) { ERR(file->handle, "found multiple module sections in module package (at section %u)", i); goto cleanup; } len = le32_to_cpu(buf[1]); if (len != strlen(POLICYDB_MOD_STRING)) { ERR(file->handle, "module string length is wrong (at section %u)", i); goto cleanup; } /* skip id */ buf = next_entry(file, len); if (!buf) { ERR(file->handle, "cannot get module string (at section %u)", i); goto cleanup; } buf = next_entry(file, sizeof(uint32_t)* 5); if (!buf) { ERR(file->handle, "cannot get module header (at section %u)", i); goto cleanup; } *type = le32_to_cpu(buf[0]); /* if base - we're done */ if (*type == POLICY_BASE) { *name = NULL; *version = NULL; seen |= SEEN_MOD; break; } else if (*type != POLICY_MOD) { ERR(file->handle, "module has invalid type %d (at section %u)", *type, i); goto cleanup; } /* read the name and version */ buf = next_entry(file, sizeof(uint32_t)); if (!buf) { ERR(file->handle, "cannot get module name len (at section %u)", i); goto cleanup; } len = le32_to_cpu(buf[0]); buf = next_entry(file, len); if (!buf) { ERR(file->handle, "cannot get module name string (at section %u)", i); goto cleanup; } *name = malloc(len + 1); if (!*name) { ERR(file->handle, "out of memory"); goto cleanup; } memcpy(*name, buf, len); (*name)[len] = '\0'; buf = next_entry(file, sizeof(uint32_t)); if (!buf) { ERR(file->handle, "cannot get module version len (at section %u)", i); goto cleanup; } len = le32_to_cpu(buf[0]); buf = next_entry(file, len); if (!buf) { ERR(file->handle, "cannot get module version string (at section %u)", i); goto cleanup; } *version = malloc(len + 1); if (!*version) { ERR(file->handle, "out of memory"); goto cleanup; } memcpy(*version, buf, len); (*version)[len] = '\0'; seen |= SEEN_MOD; break; default: break; } } if ((seen & SEEN_MOD) == 0) { ERR(file->handle, "missing module in module package"); goto cleanup; } sepol_module_package_free(mod); free(offsets); return 0; cleanup: sepol_module_package_free(mod); free(offsets); return -1; }
int main(int argc, char **argv) { int ch, i, show_version = 0, verbose = 0, num_mods; char *basename, *outname = NULL; sepol_module_package_t *base, **mods; FILE *outfile; struct sepol_policy_file *pf; progname = argv[0]; while ((ch = getopt(argc, argv, "o:V")) != EOF) { switch (ch) { case 'V': show_version = 1; break; case 'v': verbose = 1; break; case 'o': outname = optarg; break; default: usage(argv[0]); } } if (show_version) { printf("%s\n", LINKPOLICY_VERSION); exit(0); } /* check args */ if (argc < 3 || !(optind != (argc - 1))) { fprintf(stderr, "%s: You must provide the base module package and at least one other module package\n", argv[0]); usage(argv[0]); } basename = argv[optind++]; base = load_module(basename); if (!base) { fprintf(stderr, "%s: Could not load base module from file %s\n", argv[0], basename); exit(1); } num_mods = argc - optind; mods = (sepol_module_package_t**)malloc(sizeof(sepol_module_package_t*) * num_mods); if (!mods) { fprintf(stderr, "%s: Out of memory\n", argv[0]); exit(1); } memset(mods, 0, sizeof(sepol_module_package_t*) * num_mods); for (i = 0; optind < argc; optind++, i++) { mods[i] = load_module(argv[optind]); if (!mods[i]) { fprintf(stderr, "%s: Could not load module from file %s\n", argv[0], argv[optind]); exit(1); } } if (sepol_link_packages(NULL, base, mods, num_mods, verbose)) { fprintf(stderr, "%s: Error while linking packages\n", argv[0]); exit(1); } if (outname) { outfile = fopen(outname, "w"); if (!outfile) { perror(outname); exit(1); } if (sepol_policy_file_create(&pf)) { fprintf(stderr, "%s: Out of memory\n", argv[0]); exit(1); } sepol_policy_file_set_fp(pf, outfile); if (sepol_module_package_write(base, pf)) { fprintf(stderr, "%s: Error writing linked package.\n", argv[0]); exit(1); } sepol_policy_file_free(pf); } sepol_module_package_free(base); for (i = 0; i < num_mods; i++) sepol_module_package_free(mods[i]); exit(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; }