libsemanage: use libcil for compiling modules

Also finally removes the concept of a "base" module and special "_base" handling.

Signed-off-by: Steve Lawrence <slawrence@tresys.com>
This commit is contained in:
Steve Lawrence 2011-11-17 13:31:30 -05:00
parent 416f150f1a
commit ddaa6e6eca
4 changed files with 136 additions and 421 deletions

View File

@ -21,6 +21,7 @@
#include <sepol/module.h>
#include <sepol/handle.h>
#include <sepol/cil/cil.h>
#include <selinux/selinux.h>
#include <assert.h>
@ -525,51 +526,26 @@ static int write_file(semanage_handle_t * sh,
return 0;
}
/* Writes a module (or a base) to the file given by a fully-qualified
* 'filename'. Returns 0 on success, -1 if file could not be written.
*/
static int semanage_write_module(semanage_handle_t * sh,
const char *filename,
sepol_module_package_t * package)
static int semanage_direct_update_user_extra(semanage_handle_t * sh, cil_db_t *cildb, sepol_policydb_t *policydb)
{
struct sepol_policy_file *pf;
FILE *outfile;
int retval;
if (sepol_policy_file_create(&pf)) {
ERR(sh, "Out of memory!");
return -1;
}
if ((outfile = fopen(filename, "wb")) == NULL) {
sepol_policy_file_free(pf);
ERR(sh, "Could not open %s for writing.", filename);
return -1;
}
__fsetlocking(outfile, FSETLOCKING_BYCALLER);
sepol_policy_file_set_fp(pf, outfile);
sepol_policy_file_set_handle(pf, sh->sepolh);
retval = sepol_module_package_write(package, pf);
fclose(outfile);
sepol_policy_file_free(pf);
if (retval == -1) {
ERR(sh, "Error while writing module to %s.", filename);
return -1;
}
return 0;
}
static int semanage_direct_update_user_extra(semanage_handle_t * sh, sepol_module_package_t *base ) {
const char *ofilename = NULL;
int retval = -1;
char *data = NULL;
size_t size = 0;
dbase_config_t *pusers_extra = semanage_user_extra_dbase_policy(sh);
if (sepol_module_package_get_user_extra_len(base)) {
retval = cil_userprefixes_to_string(cildb, policydb, &data, &size);
if (retval != SEPOL_OK) {
goto cleanup;
}
if (size > 0) {
ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA);
if (ofilename == NULL) {
return retval;
}
retval = write_file(sh, ofilename,
sepol_module_package_get_user_extra(base),
sepol_module_package_get_user_extra_len(base));
retval = write_file(sh, ofilename, data, size);
if (retval < 0)
return retval;
@ -579,34 +555,41 @@ static int semanage_direct_update_user_extra(semanage_handle_t * sh, sepol_modul
retval = pusers_extra->dtable->clear(sh, pusers_extra->dbase);
}
cleanup:
free(data);
return retval;
}
static int semanage_direct_update_seuser(semanage_handle_t * sh, sepol_module_package_t *base ) {
static int semanage_direct_update_seuser(semanage_handle_t * sh, cil_db_t *cildb, sepol_policydb_t *policydb)
{
const char *ofilename = NULL;
int retval = -1;
char *data = NULL;
size_t size = 0;
dbase_config_t *pseusers = semanage_seuser_dbase_policy(sh);
if (sepol_module_package_get_seusers_len(base)) {
ofilename = semanage_final_path(SEMANAGE_FINAL_TMP,
SEMANAGE_SEUSERS);
retval = cil_selinuxusers_to_string(cildb, policydb, &data, &size);
if (retval != SEPOL_OK) {
goto cleanup;
}
if (size > 0) {
ofilename = semanage_final_path(SEMANAGE_FINAL_TMP, SEMANAGE_SEUSERS);
if (ofilename == NULL) {
return -1;
}
retval = write_file(sh, ofilename,
sepol_module_package_get_seusers(base),
sepol_module_package_get_seusers_len(base));
if (retval < 0)
return retval;
retval = write_file(sh, ofilename, data, size);
pseusers->dtable->drop_cache(pseusers->dbase);
} else {
retval = pseusers->dtable->clear(sh, pseusers->dbase);
}
cleanup:
free(data);
return retval;
}
@ -618,17 +601,19 @@ static int semanage_direct_update_seuser(semanage_handle_t * sh, sepol_module_pa
static int semanage_direct_commit(semanage_handle_t * sh)
{
char **mod_filenames = NULL;
char *sorted_fc_buffer = NULL, *sorted_nc_buffer = NULL;
size_t sorted_fc_buffer_len = 0, sorted_nc_buffer_len = 0;
const char *linked_filename = NULL, *ofilename = NULL, *path;
sepol_module_package_t *base = NULL;
char *fc_buffer = NULL;
size_t fc_buffer_len = 0;
const char *ofilename = NULL;
const char *path;
int retval = -1, num_modfiles = 0, i;
sepol_policydb_t *out = NULL;
struct cil_db *cildb = NULL;
/* Declare some variables */
int modified = 0, fcontexts_modified, ports_modified,
seusers_modified, users_extra_modified, dontaudit_modified,
preserve_tunables_modified, bools_modified;
preserve_tunables_modified, bools_modified,
disable_dontaudit, preserve_tunables;
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);
@ -712,6 +697,8 @@ static int semanage_direct_commit(semanage_handle_t * sh)
bools_modified = bools->dtable->is_modified(bools->dbase);
modified = sh->modules_modified;
modified |= seusers_modified;
modified |= users_extra_modified;
modified |= ports_modified;
modified |= users->dtable->is_modified(users_base->dbase);
modified |= ifaces->dtable->is_modified(ifaces->dbase);
@ -721,74 +708,62 @@ static int semanage_direct_commit(semanage_handle_t * sh)
/* 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 */
retval = semanage_get_modules_names(sh, &mod_filenames, &num_modfiles);
if (retval < 0)
goto cleanup;
if (num_modfiles == 0) {
ERR(sh, "No active modules.\n");
goto cleanup;
}
retval = semanage_verify_modules(sh, mod_filenames, num_modfiles);
if (retval < 0)
goto cleanup;
retval = semanage_link_sandbox(sh, &base);
cil_db_init(&cildb);
disable_dontaudit = sepol_get_disable_dontaudit(sh->sepolh);
preserve_tunables = sepol_get_preserve_tunables(sh->sepolh);
cil_set_disable_dontaudit(cildb, disable_dontaudit);
cil_set_disable_neverallow(cildb, !(sh->conf->expand_check));
cil_set_preserve_tunables(cildb, preserve_tunables);
if (sh->conf->handle_unknown != -1) {
cil_set_handle_unknown(cildb, sh->conf->handle_unknown);
}
retval = semanage_load_files(sh, cildb, mod_filenames, num_modfiles);
if (retval < 0) {
goto cleanup;
}
sepol_policydb_create(&out);
out->p.policy_type = POLICY_KERN;
sepol_policydb_set_vers(out, sh->conf->policyvers);
sepol_policydb_set_target_platform(out, sh->conf->target_platform);
retval = cil_compile(cildb, out);
if (retval < 0)
goto cleanup;
/* write the linked base if we want to save or we have a
* verification program that wants it. */
linked_filename = semanage_path(SEMANAGE_TMP, SEMANAGE_LINKED);
if (linked_filename == NULL) {
retval = -1;
retval = cil_build_policydb(cildb, out);
if (retval < 0)
goto cleanup;
}
if (sh->conf->save_linked || sh->conf->linked_prog) {
retval = semanage_write_module(sh, linked_filename, base);
if (retval < 0)
goto cleanup;
retval = semanage_verify_linked(sh);
if (retval < 0)
goto cleanup;
/* remove the linked policy if we only wrote it for the
* verification program. */
if (!sh->conf->save_linked) {
retval = unlink(linked_filename);
if (retval < 0) {
ERR(sh, "could not remove linked base %s",
linked_filename);
goto cleanup;
}
}
} else {
/* Try to delete the linked copy - this is needed if
* the save_link option has changed to prevent the
* old linked copy from being copied forever. No error
* checking is done because this is likely to fail because
* the file does not exist - which is not an error. */
unlink(linked_filename);
errno = 0;
}
/* ==================== File-backed ================== */
/* File Contexts */
/* Sort the file contexts. */
retval = semanage_fc_sort(sh, sepol_module_package_get_file_contexts(base),
sepol_module_package_get_file_contexts_len(base),
&sorted_fc_buffer, &sorted_fc_buffer_len);
retval = cil_filecons_to_string(cildb, out, &fc_buffer, &fc_buffer_len);
if (retval < 0)
goto cleanup;
/* Write the contexts (including template contexts) to a single file.
* The buffer returned by the sort function has a trailing \0 character,
* which we do NOT want to write out to disk, so we pass sorted_fc_buffer_len-1. */
/* Write the contexts (including template contexts) to a single file. */
ofilename = semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL);
if (ofilename == NULL) {
retval = -1;
goto cleanup;
}
retval = write_file(sh, ofilename, sorted_fc_buffer,
sorted_fc_buffer_len - 1);
retval = write_file(sh, ofilename, fc_buffer, fc_buffer_len);
if (retval < 0)
goto cleanup;
@ -799,44 +774,18 @@ static int semanage_direct_commit(semanage_handle_t * sh)
pfcontexts->dtable->drop_cache(pfcontexts->dbase);
retval = semanage_direct_update_seuser(sh, base );
/* SEUsers */
retval = semanage_direct_update_seuser(sh, cildb, out);
if (retval < 0)
goto cleanup;
retval = semanage_direct_update_user_extra(sh, base );
/* User Extra */
retval = semanage_direct_update_user_extra(sh, cildb, out);
if (retval < 0)
goto cleanup;
/* Netfilter Contexts */
/* Sort the netfilter contexts. */
retval = semanage_nc_sort
(sh, sepol_module_package_get_netfilter_contexts(base),
sepol_module_package_get_netfilter_contexts_len(base),
&sorted_nc_buffer, &sorted_nc_buffer_len);
if (retval < 0)
goto cleanup;
/* Write the contexts to a single file. The buffer returned by
* the sort function has a trailing \0 character, which we do
* NOT want to write out to disk, so we pass sorted_fc_buffer_len-1. */
ofilename = semanage_final_path(SEMANAGE_FINAL_TMP,
SEMANAGE_NC);
retval = write_file
(sh, ofilename, sorted_nc_buffer, sorted_nc_buffer_len - 1);
if (retval < 0)
goto cleanup;
/* ==================== Policydb-backed ================ */
/* Create new policy object */
retval = semanage_expand_sandbox(sh, base, &out);
if (retval < 0)
goto cleanup;
cil_db_destroy(&cildb);
sepol_module_package_free(base);
base = NULL;
} else {
/* Load already linked policy */
retval = sepol_policydb_create(&out);
@ -850,8 +799,7 @@ static int semanage_direct_commit(semanage_handle_t * sh)
if (sh->do_rebuild || modified || bools_modified) {
/* Attach to policy databases that work with a policydb. */
dbase_policydb_attach((dbase_policydb_t *) pusers_base->dbase,
out);
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);
@ -871,33 +819,11 @@ static int semanage_direct_commit(semanage_handle_t * sh)
if (retval < 0)
goto cleanup;
} else {
/* Changes to non-kernel policy configurations only. */
if (seusers_modified || users_extra_modified) {
retval = semanage_link_base(sh, &base);
if (retval < 0)
goto cleanup;
if (seusers_modified) {
retval = semanage_direct_update_seuser(sh, base );
if (retval < 0)
goto cleanup;
}
if (users_extra_modified) {
/* Users_extra */
retval = semanage_direct_update_user_extra(sh, base );
if (retval < 0)
goto cleanup;
}
sepol_module_package_free(base);
base = NULL;
}
retval = semanage_base_merge_components(sh);
if (retval < 0)
goto cleanup;
goto cleanup;
}
/* ======= Post-process: Validate non-policydb components ===== */
/* Validate local modifications to file contexts.
@ -918,7 +844,7 @@ static int semanage_direct_commit(semanage_handle_t * sh)
}
/* Validate local ports for overlap */
if (sh->do_rebuild || ports_modified) {
if (sh->do_rebuild || modified || ports_modified) {
retval = semanage_port_validate_local(sh);
if (retval < 0)
goto cleanup;
@ -950,8 +876,12 @@ static int semanage_direct_commit(semanage_handle_t * sh)
sepol_policydb_free(out);
out = NULL;
if (sh->do_rebuild || modified || bools_modified ||
seusers_modified || fcontexts_modified || users_extra_modified) {
/* remove files that are automatically generated and no longer needed */
unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_FC_TMPL));
unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_HOMEDIR_TMPL));
unlink(semanage_path(SEMANAGE_TMP, SEMANAGE_USERS_EXTRA));
if (sh->do_rebuild || modified || bools_modified || fcontexts_modified) {
retval = semanage_install_sandbox(sh);
}
@ -971,10 +901,10 @@ static int semanage_direct_commit(semanage_handle_t * sh)
free(mod_filenames);
sepol_policydb_free(out);
cil_db_destroy(&cildb);
semanage_release_trans_lock(sh);
free(sorted_fc_buffer);
free(sorted_nc_buffer);
free(fc_buffer);
/* regardless if the commit was successful or not, remove the
sandbox if it is still there */

View File

@ -994,7 +994,6 @@ int semanage_module_validate_priority(uint16_t priority)
* to be considered valid:
*
* ^[a-zA-Z](\.?[a-zA-Z0-9_-])*$
* ^_base$
*
* returns -1 if name is not valid, returns 0 otherwise
*/
@ -1007,10 +1006,6 @@ int semanage_module_validate_name(const char * name)
goto exit;
}
if (strcmp(name, "_base") == 0) {
goto exit;
}
if (!isalpha(*name)) {
status = -1;
goto exit;

View File

@ -505,67 +505,6 @@ char *semanage_conf_path(void)
return semanage_conf;
}
/* Locates the highest priority enabled base module
* and fills @path in with that value. @path must be
* pre-allocated with size @len.
*
* Returns 0 on success and -1 on error.
*/
int semanage_base_path(semanage_handle_t *sh,
char *path,
size_t len)
{
assert(sh);
assert(path);
int status = 0;
int ret = 0;
semanage_module_info_t *base = NULL;
/* set key for getting base module */
semanage_module_key_t modkey;
ret = semanage_module_key_init(sh, &modkey);
if (ret != 0) {
status = -1;
goto cleanup;
}
ret = semanage_module_key_set_name(sh, &modkey, "_base");
if (ret != 0) {
status = -1;
goto cleanup;
}
/* get highest priority base module */
ret = semanage_module_get_module_info(sh, &modkey, &base);
if (ret != 0) {
/* no base module found */
status = -1;
goto cleanup;
}
/* get the highest priority base module path */
ret = semanage_module_get_path(
sh,
base,
SEMANAGE_MODULE_PATH_HLL,
path,
len);
if (ret != 0) {
status = -1;
goto cleanup;
}
cleanup:
semanage_module_key_destroy(sh, &modkey);
semanage_module_info_destroy(sh, base);
free(base);
return status;
}
/**************** functions that create module store ***************/
/* Check that the semanage store exists. If 'create' is non-zero then
@ -2032,200 +1971,67 @@ int semanage_direct_get_serial(semanage_handle_t * sh)
/* HIGHER LEVEL COMMIT FUNCTIONS */
/* Loads a module (or a base) from a fully-qualified 'filename' into a
* newly allocated sepol_module_package_t structure and returns it in
* '*package'. Caller is responsible for destroying it afterwards via
* sepol_module_package_destroy(). Returns 0 on success, -1 on error.
*/
static int semanage_load_module(semanage_handle_t * sh, const char *filename,
sepol_module_package_t ** package)
int semanage_load_files(semanage_handle_t * sh, cil_db_t *cildb, char **filenames, int numfiles)
{
int retval = 0;
FILE *fp;
struct sepol_policy_file *pf = NULL;
*package = NULL;
if (sepol_module_package_create(package) == -1) {
ERR(sh, "Out of memory!");
return -1;
}
if (sepol_policy_file_create(&pf)) {
ERR(sh, "Out of memory!");
goto cleanup;
}
if ((fp = fopen(filename, "rb")) == NULL) {
ERR(sh, "Could not open module file %s for reading.", filename);
goto cleanup;
}
ssize_t size;
char *data = NULL;
char *filename;
int i;
if ((size = bunzip(sh, fp, &data)) > 0) {
sepol_policy_file_set_mem(pf, data, size);
} else {
rewind(fp);
__fsetlocking(fp, FSETLOCKING_BYCALLER);
sepol_policy_file_set_fp(pf, fp);
}
sepol_policy_file_set_handle(pf, sh->sepolh);
if (sepol_module_package_read(*package, pf, 0) == -1) {
ERR(sh, "Error while reading from module file %s.", filename);
fclose(fp);
free(data);
goto cleanup;
}
sepol_policy_file_free(pf);
fclose(fp);
free(data);
return retval;
for (i = 0; i < numfiles; i++) {
filename = filenames[i];
cleanup:
sepol_module_package_free(*package);
*package = NULL;
sepol_policy_file_free(pf);
return -1;
}
/* Links all of the modules within the sandbox into the base module.
* '*base' will point to the module package that contains everything
* linked together (caller must call sepol_module_package_destroy() on
* it afterwards). '*mods' will be a list of module packages and
* '*num_modules' will be the number of elements within '*mods'
* (caller must destroy each element as well as the pointer itself.)
* Both '*base' and '*mods' will be set to NULL upon entering this
* function. Returns 0 on success, -1 on error.
*/
int semanage_link_sandbox(semanage_handle_t * sh,
sepol_module_package_t ** base)
{
char base_filename[PATH_MAX];
char **module_filenames = NULL;
int retval = -1, i;
int num_modules = 0;
sepol_module_package_t **mods = NULL;
*base = NULL;
/* first make sure that base module is readable */
if (semanage_base_path(sh, base_filename, sizeof(base_filename)) != 0) {
goto cleanup;
}
if (access(base_filename, R_OK) == -1) {
ERR(sh, "Could not access sandbox base file %s.",
base_filename);
goto cleanup;
}
/* get list of modules and load them */
if (semanage_get_modules_names(sh, &module_filenames, &num_modules) ==
-1 || semanage_load_module(sh, base_filename, base) == -1) {
goto cleanup;
}
if ((mods = calloc(num_modules, sizeof(*mods))) == NULL) {
ERR(sh, "Out of memory!");
num_modules = 0;
goto cleanup;
}
for (i = 0; i < num_modules; i++) {
if (semanage_load_module(sh, module_filenames[i], mods + i) ==
-1) {
if ((fp = fopen(filename, "rb")) == NULL) {
ERR(sh, "Could not open module file %s for reading.", filename);
goto cleanup;
}
if ((size = bunzip(sh, fp, &data)) <= 0) {
rewind(fp);
__fsetlocking(fp, FSETLOCKING_BYCALLER);
if (fseek(fp, 0, SEEK_END) != 0) {
ERR(sh, "Failed to determine size of file %s.", filename);
goto cleanup;
}
size = ftell(fp);
rewind(fp);
data = malloc(size);
if (fread(data, size, 1, fp) != 1) {
ERR(sh, "Failed to read file %s.", filename);
goto cleanup;
}
}
fclose(fp);
fp = NULL;
retval = cil_add_file(cildb, filename, data, size);
if (retval != SEPOL_OK) {
ERR(sh, "Error while reading from file %s.", filename);
goto cleanup;
}
free(data);
data = NULL;
}
if (sepol_link_packages(sh->sepolh, *base, mods, num_modules, 0) != 0) {
ERR(sh, "Link packages failed");
goto cleanup;
}
retval = 0;
return retval;
cleanup:
for (i = 0; module_filenames != NULL && i < num_modules; i++) {
free(module_filenames[i]);
if (fp != NULL) {
fclose(fp);
}
free(module_filenames);
for (i = 0; mods != NULL && i < num_modules; i++) {
sepol_module_package_free(mods[i]);
}
free(mods);
return retval;
}
/* Links only the base module within the sandbox into the base module.
* '*base' will point to the module package that contains everything
* linked together (caller must call sepol_module_package_destroy() on
* it afterwards). '*base' will be set to NULL upon entering this
* function. Returns 0 on success, -1 on error.
*/
int semanage_link_base(semanage_handle_t * sh,
sepol_module_package_t ** base)
{
char base_filename[PATH_MAX];
int retval = -1;
*base = NULL;
/* first make sure that base module is readable */
if (semanage_base_path(sh, base_filename, sizeof(base_filename)) != 0) {
goto cleanup;
}
if (access(base_filename, R_OK) == -1) {
ERR(sh, "Could not access sandbox base file %s.",
base_filename);
goto cleanup;
}
if (semanage_load_module(sh, base_filename, base) == -1) {
goto cleanup;
}
retval = 0;
cleanup:
return retval;
free(data);
return -1;
}
/*
* Expands the policy contained within *base
*/
int semanage_expand_sandbox(semanage_handle_t * sh,
sepol_module_package_t * base,
sepol_policydb_t ** policydb)
{
struct sepol_policydb *out = NULL;
int policyvers = sh->conf->policyvers;
int expand_check = sh->conf->expand_check ? sh->modules_modified : 0;
if (sepol_policydb_create(&out))
goto err;
sepol_set_expand_consume_base(sh->sepolh, 1);
if (sepol_expand_module(sh->sepolh,
sepol_module_package_get_policy(base), out, 0,
expand_check)
== -1) {
ERR(sh, "Expand module failed");
goto err;
}
if (sepol_policydb_set_vers(out, policyvers)) {
ERR(sh, "Unknown/Invalid policy version %d.", policyvers);
goto err;
}
if (sh->conf->handle_unknown >= 0)
sepol_policydb_set_handle_unknown(out, sh->conf->handle_unknown);
*policydb = out;
return STATUS_SUCCESS;
err:
sepol_policydb_free(out);
return STATUS_ERR;
}
/**
* Read the policy from the sandbox (kernel)

View File

@ -26,6 +26,7 @@
#include <sys/time.h>
#include <sepol/module.h>
#include <sepol/cil/cil.h>
#include "handle.h"
enum semanage_store_defs {
@ -119,15 +120,8 @@ void semanage_release_trans_lock(semanage_handle_t * sh);
void semanage_release_active_lock(semanage_handle_t * sh);
int semanage_direct_get_serial(semanage_handle_t * sh);
int semanage_link_sandbox(semanage_handle_t * sh,
sepol_module_package_t ** base);
int semanage_link_base(semanage_handle_t * sh,
sepol_module_package_t ** base);
int semanage_expand_sandbox(semanage_handle_t * sh,
sepol_module_package_t * base,
sepol_policydb_t ** policydb);
int semanage_load_files(semanage_handle_t * sh,
cil_db_t *cildb, char **filenames, int num_modules);
int semanage_read_policydb(semanage_handle_t * sh,
sepol_policydb_t * policydb);
@ -156,14 +150,4 @@ int semanage_nc_sort(semanage_handle_t * sh,
size_t buf_len,
char **sorted_buf, size_t * sorted_buf_len);
/* Locates the highest priority enabled base module
* and fills @path in with that value. @path must be
* pre-allocated with size @len.
*
* Returns 0 on success and -1 on error.
*/
int semanage_base_path(semanage_handle_t *sh,
char *path,
size_t len);
#endif