* [Patch 2/3] Loadable policy module infrastructure
@ 2005-05-26 17:27 Joshua Brindle
2005-06-01 12:25 ` Stephen Smalley
0 siblings, 1 reply; 3+ messages in thread
From: Joshua Brindle @ 2005-05-26 17:27 UTC (permalink / raw)
To: selinux; +Cc: selinux-dev
diff -burNd a1/libsepol/src/expand.c b/libsepol/src/expand.c
--- a1/libsepol/src/expand.c 1969-12-31 19:00:00.000000000 -0500
+++ b/libsepol/src/expand.c 2005-05-25 13:11:19.526055000 -0400
@@ -0,0 +1,1746 @@
+/* Authors: Karl MacMillan <kmacmillan@tresys.com>
+ * Jason Tang <jtang@tresys.com>
+ * Joshua Brindle <jbrindle@tresys.com>
+ *
+ * Copyright (C) 2004-5 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include <sepol/context.h>
+#include <sepol/policydb.h>
+#include <sepol/conditional.h>
+#include <sepol/hashtab.h>
+#include <sepol/expand.h>
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+typedef struct expand_state {
+ int verbose;
+ uint32_t *typemap;
+ policydb_t *base;
+ policydb_t *out;
+ char *error_buf;
+ size_t error_buf_size;
+} expand_state_t;
+
+/* Write an error message to the current error buffer, up to the
+ * buffer's specified size. */
+static void write_error (expand_state_t *state, char *fmt, ...) {
+ va_list ap;
+ if (state->error_buf == NULL) {
+ return;
+ }
+ va_start (ap, fmt);
+ (void) vsnprintf (state->error_buf, state->error_buf_size, fmt, ap);
+ va_end (ap);
+}
+
+static int type_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ char *id, *new_id;
+ type_datum_t *type, *new_type;
+ expand_state_t *state;
+
+ id = (char *)key;
+ type = (type_datum_t *)datum;
+ state = (expand_state_t*)data;
+
+ if (!type->primary) {
+ /* aliases are handled later */
+ return 0;
+ }
+
+ if (state->verbose)
+ printf("copying type or attribute %s\n", id);
+
+ new_id = strdup(id);
+ if (new_id == NULL) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ new_type = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!new_type) {
+ write_error (state, "Out of memory!\n");
+ free (new_id);
+ return -ENOMEM;
+ }
+ memset(new_type, 0, sizeof(type_datum_t));
+
+ new_type->isattr = type->isattr;
+ if (!type->isattr) {
+ new_type->value = ++state->out->p_types.nprim;
+ /* FIX ME: temp fix here */
+ new_type->value = type->order;
+ new_type->primary = 1;
+ }
+ else {
+ /* lookups of attributes should never occur, so
+ * explicitly set it to a blatantly illegal value
+ * here */
+ new_type->value = -1;
+ }
+ state->typemap[type->value - 1] = new_type->value;
+
+ ret = hashtab_insert(state->out->p_types.table,
+ (hashtab_key_t)new_id, (hashtab_datum_t)new_type);
+ if (ret) {
+ free (new_id);
+ free (new_type);
+ write_error (state, "hashtab overflow");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int perm_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ char *id, *new_id;
+ symtab_t *s;
+ perm_datum_t *perm, *new_perm;
+
+ id = key;
+ perm = (perm_datum_t*)datum;
+ s = (symtab_t*)data;
+
+ new_perm = (perm_datum_t*)malloc(sizeof(perm_datum_t));
+ if (!new_perm) {
+ return -1;
+ }
+ memset(new_perm, 0, sizeof(perm_datum_t));
+
+ new_id = strdup(id);
+ if (!new_id) {
+ free (new_perm);
+ return -1;
+ }
+
+ new_perm->value = perm->value;
+ s->nprim++;
+
+ ret = hashtab_insert(s->table, new_id, (hashtab_datum_t*)new_perm);
+ if (ret) {
+ free (new_id);
+ free (new_perm);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int common_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ char *id, *new_id;
+ common_datum_t *common, *new_common;
+ expand_state_t *state;
+
+ id = (char *)key;
+ common = (common_datum_t *)datum;
+ state = (expand_state_t*)data;
+
+ if (state->verbose)
+ printf("copying common %s\n", id);
+
+ new_common = (common_datum_t*)malloc(sizeof(common_datum_t));
+ if (!new_common) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(new_common, 0, sizeof(common_datum_t));
+ if (symtab_init(&new_common->permissions, PERM_SYMTAB_SIZE)) {
+ write_error (state, "Out of memory!");
+ free (new_common);
+ return -1;
+ }
+
+ new_id = strdup(id);
+ if (!new_id) {
+ write_error (state, "Out of memory!");
+ free (new_common);
+ return -1;
+ }
+
+ new_common->value = common->value;
+ state->out->p_commons.nprim++;
+
+ ret = hashtab_insert(state->out->p_commons.table, new_id, (hashtab_datum_t*)new_common);
+ if (ret) {
+ write_error (state, "hashtab overflow");
+ free (new_common);
+ free (new_id);
+ return -1;
+ }
+
+ if (hashtab_map(common->permissions.table, perm_copy_callback, &new_common->permissions)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int constraint_node_clone(constraint_node_t **dst, constraint_node_t *src, expand_state_t *state)
+{
+ constraint_node_t *new_con, *last_new_con = NULL;
+ *dst = NULL;
+ while (src != NULL) {
+ constraint_expr_t *expr, *new_expr, *expr_l = NULL;
+ new_con = (constraint_node_t*)malloc(sizeof(constraint_node_t));
+ if (!new_con) {
+ goto out_of_mem;
+ }
+ memset(new_con, 0, sizeof(constraint_node_t));
+ new_con->permissions = src->permissions;
+ for (expr = src->expr; expr; expr = expr->next) {
+ new_expr = (constraint_expr_t*)malloc(sizeof(constraint_expr_t));
+ if (!new_expr) {
+ goto out_of_mem;
+ }
+ memset(new_expr, 0, sizeof(constraint_expr_t));
+ ebitmap_init(&new_expr->names);
+
+ new_expr->expr_type = expr->expr_type;
+ new_expr->attr = expr->attr;
+ new_expr->op = expr->op;
+ /* If the constraint expression indicates a
+ type name, remap the corresponding 'names'
+ bitmap from old to new by way of the
+ typemap. Note that if a name is actually
+ an attribute, one needs to remap the
+ /components/ of that attribute as well. */
+ if (new_expr->expr_type == CEXPR_NAMES) {
+ int i, j;
+ for (i = ebitmap_startbit(&expr->names); i < ebitmap_length(&expr->names); i++) {
+ if (!ebitmap_get_bit(&expr->names, i))
+ continue;
+ if (new_expr->attr & CEXPR_TYPE) {
+ if (state->base->type_val_to_struct[i]->isattr) {
+ ebitmap_t *attr = &state->base->type_val_to_struct[i]->types;
+ for (j = ebitmap_startbit(attr); j < ebitmap_length(attr); j++) {
+ if (!ebitmap_get_bit(attr, j))
+ continue;
+ if (ebitmap_set_bit(&new_expr->names, state->typemap[j] - 1, 1))
+ goto out_of_mem;
+ }
+ } else {
+ if (ebitmap_set_bit(&new_expr->names, state->typemap[i] - 1, 1)) {
+ goto out_of_mem;
+ }
+ }
+ } else {
+ if (ebitmap_set_bit(&new_expr->names, i, 1)) {
+ goto out_of_mem;
+ }
+ }
+ }
+ }
+ if (expr_l) {
+ expr_l->next = new_expr;
+ } else {
+ new_con->expr = new_expr;
+ }
+ expr_l = new_expr;
+ }
+ if (last_new_con == NULL) {
+ *dst = new_con;
+ }
+ else {
+ last_new_con->next = new_con;
+ }
+ last_new_con = new_con;
+ src = src->next;
+ }
+
+ return 0;
+ out_of_mem:
+ write_error(state, "Out of memory!");
+ return -1;
+}
+
+static int class_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ char *id, *new_id;
+ class_datum_t *class, *new_class;
+ expand_state_t *state;
+
+ id = (char *)key;
+ class = (class_datum_t *)datum;
+ state = (expand_state_t*)data;
+
+ if (state->verbose)
+ printf("copying class %s\n", id);
+
+ new_class = (class_datum_t*)malloc(sizeof(class_datum_t));
+ if (!new_class) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(new_class, 0, sizeof(class_datum_t));
+ if (symtab_init(&new_class->permissions, PERM_SYMTAB_SIZE)) {
+ write_error (state, "Out of memory!");
+ free (new_class);
+ return -1;
+ }
+
+ new_class->value = class->value;
+ state->out->p_classes.nprim++;
+
+ new_id = strdup(id);
+ if (!new_id) {
+ write_error (state, "Out of memory!");
+ free (new_class);
+ return -1;
+ }
+
+ ret = hashtab_insert(state->out->p_classes.table, new_id, (hashtab_datum_t*)new_class);
+ if (ret) {
+ write_error (state, "hashtab overflow");
+ free (new_class);
+ free (new_id);
+ return -1;
+ }
+
+ if (hashtab_map(class->permissions.table, perm_copy_callback, &new_class->permissions)) {
+ write_error (state, "hashtab overflow");
+ return -1;
+ }
+
+ if (class->comkey) {
+ new_class->comkey = strdup(class->comkey);
+ if (!new_class->comkey)
+ {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ new_class->comdatum = hashtab_search(state->out->p_commons.table, new_class->comkey);
+ if (!new_class->comdatum)
+ {
+ write_error (state, "could not find common datum %s\n", new_class->comkey);
+ return -1;
+ }
+ new_class->permissions.nprim += new_class->comdatum->permissions.nprim;
+ }
+
+ /* constraints */
+ if (constraint_node_clone(&new_class->constraints, class->constraints, state) == -1 ||
+ constraint_node_clone(&new_class->validatetrans, class->validatetrans, state) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+/* The aliases have to be copied after the types and attributes to be certain that
+ * the out symbol table will have the type that the alias refers. Otherwise, we
+ * won't be able to find the type value for the alias. We can't depend on the
+ * declaration ordering because of the hash table.
+ */
+static int alias_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ char *id, *new_id;
+ type_datum_t *alias, *new_alias;
+ expand_state_t *state;
+
+ id = (char *)key;
+ alias = (type_datum_t *)datum;
+ state = (expand_state_t*)data;
+
+ /* ignore types and attributes */
+ if (alias->primary || alias->isattr) {
+ return 0;
+ }
+
+ if (state->verbose)
+ printf("copying alias %s\n", id);
+
+ new_id = strdup(id);
+ if (!new_id) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ new_alias = (type_datum_t *) malloc(sizeof(type_datum_t));
+ if (!new_alias) {
+ write_error (state, "Out of memory!");
+ return -ENOMEM;
+ }
+ memset(new_alias, 0, sizeof(type_datum_t));
+ new_alias->value = state->typemap[alias->value - 1];
+
+ ret = hashtab_insert(state->out->p_types.table,
+ (hashtab_key_t)new_id, (hashtab_datum_t) new_alias);
+
+ if (ret) {
+ write_error (state, "hashtab overflow");
+ free(new_alias);
+ free(new_id);
+ return -1;
+ }
+
+ state->typemap[alias->value - 1] = new_alias->value;
+ return 0;
+}
+
+static int role_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ char *id, *new_id;
+ role_datum_t *role;
+ role_datum_t *new_role;
+ expand_state_t *state;
+
+ id = key;
+ role = (role_datum_t*)datum;
+ state = (expand_state_t*)data;
+
+ if (strcmp(id, OBJECT_R) == 0)
+ return 0;
+
+ if (state->verbose)
+ printf("copying role %s\n", id);
+
+ new_role = (role_datum_t *) malloc(sizeof(role_datum_t));
+ if (!new_role) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(new_role, 0, sizeof(role_datum_t));
+
+ new_id = strdup(id);
+ if (!new_id) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ new_role->value = role->value;
+ state->out->p_roles.nprim++;
+ ret = hashtab_insert(state->out->p_roles.table,
+ (hashtab_key_t) new_id, (hashtab_datum_t) new_role);
+
+ if (ret) {
+ write_error (state, "hashtab overflow");
+ free(new_role);
+ free(new_id);
+ return -1;
+ }
+
+ if (ebitmap_cpy(&new_role->dominates, &role->dominates)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ if (expand_convert_type_set(state->base, state->typemap, &role->types, &new_role->types.types)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mls_level_clone(mls_level_t *dst, mls_level_t *src) {
+ dst->sens = src->sens;
+ if (ebitmap_cpy(&dst->cat, &src->cat)) {
+ return -1;
+ }
+ return 0;
+}
+
+static int user_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ expand_state_t *state;
+ user_datum_t *user;
+ user_datum_t *new_user;
+ char *id, *new_id;
+
+ id = key;
+ user = (user_datum_t *)datum;
+ state = (expand_state_t*)data;
+
+ if (state->verbose)
+ printf("copying user %s\n", id);
+
+ new_user = (user_datum_t *) malloc(sizeof(user_datum_t));
+ if (!new_user) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(new_user, 0, sizeof(user_datum_t));
+
+ new_user->value = user->value;
+ state->out->p_users.nprim++;
+
+ new_id = strdup(id);
+ if (!new_id) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ ret = hashtab_insert(state->out->p_users.table,
+ (hashtab_key_t)new_id, (hashtab_datum_t)new_user);
+ if (ret) {
+ write_error (state, "hashtab overflow");
+ user_datum_destroy(NULL, new_user, NULL);
+ free(new_user);
+ free(new_id);
+ return -1;
+ }
+
+ if (role_set_expand(&user->roles, &new_user->roles.roles, state->base)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ /* clone MLS stuff */
+ if (mls_level_clone(&new_user->range.level[0], &user->range.level[0]) == -1 ||
+ mls_level_clone(&new_user->range.level[1], &user->range.level[1]) == -1 ||
+ mls_level_clone(&new_user->dfltlevel, &user->dfltlevel) == -1) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ new_user->defined = user->defined;
+ return 0;
+}
+
+
+static int bool_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ int ret;
+ expand_state_t *state;
+ cond_bool_datum_t *bool, *new_bool;
+ char *id, *new_id;
+
+ id = key;
+ bool = (cond_bool_datum_t *)datum;
+ state = (expand_state_t*)data;
+
+ if (state->verbose)
+ printf("copying boolean %s\n", id);
+
+ new_bool = (cond_bool_datum_t*)malloc(sizeof(cond_bool_datum_t));
+ if (!new_bool) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ new_id = strdup(id);
+ if (!new_id) {
+ write_error (state, "Out of memory!");
+ free (new_bool);
+ return -1;
+ }
+
+ new_bool->value = bool->value;
+ state->out->p_bools.nprim++;
+
+ ret = hashtab_insert(state->out->p_bools.table,
+ (hashtab_key_t)new_id, (hashtab_datum_t)new_bool);
+ if (ret) {
+ write_error (state, "hashtab overflow");
+ free(new_bool);
+ free(new_id);
+ return -1;
+ }
+
+ new_bool->state = bool->state;
+
+ return 0;
+}
+
+static int sens_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t*)data;
+ level_datum_t *level = (level_datum_t *)datum, *new_level = NULL;
+ char *id = (char *) key, *new_id = NULL;
+
+ if (state->verbose)
+ printf("copying senitivity level %s\n", id);
+
+ if ((new_level = (level_datum_t*)calloc(1, sizeof(*new_level))) == NULL ||
+ (new_level->level = (mls_level_t *)calloc(1, sizeof(mls_level_t))) == NULL ||
+ (new_id = strdup(id)) == NULL) {
+ goto out_of_mem;
+ }
+
+ if (mls_level_clone(new_level->level, level->level)) {
+ goto out_of_mem;
+ }
+ new_level->isalias = level->isalias;
+ state->out->p_levels.nprim++;
+
+ if (hashtab_insert(state->out->p_levels.table,
+ (hashtab_key_t)new_id, (hashtab_datum_t)new_level)) {
+ goto out_of_mem;
+ }
+ return 0;
+
+ out_of_mem:
+ write_error(state, "Out of memory!");
+ if (new_level != NULL) {
+ ebitmap_destroy(&new_level->level->cat);
+ free(new_level->level);
+ }
+ free(new_level);
+ free(new_id);
+ return -1;
+}
+
+static int cats_copy_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+ expand_state_t *state = (expand_state_t*)data;
+ cat_datum_t *cat = (cat_datum_t *)datum, *new_cat = NULL;
+ char *id = (char *)key, *new_id = NULL;
+
+ if (state->verbose)
+ printf("copying category attribute %s\n", id);
+
+ if ((new_cat = (cat_datum_t*)calloc(1, sizeof(*new_cat))) == NULL ||
+ (new_id = strdup(id)) == NULL) {
+ goto out_of_mem;
+ }
+
+ new_cat->value = cat->value;
+ new_cat->isalias = cat->isalias;
+ state->out->p_cats.nprim++;
+ if (hashtab_insert(state->out->p_cats.table,
+ (hashtab_key_t)new_id, (hashtab_datum_t)new_cat)) {
+ goto out_of_mem;
+ }
+
+ return 0;
+
+ out_of_mem:
+ write_error(state, "Out of memory!");
+ free(new_cat);
+ free(new_id);
+ return -1;
+}
+
+
+static int copy_role_allows(expand_state_t *state)
+{
+ int i, j;
+ role_allow_t *cur_allow, *n, *l;
+ role_allow_rule_t *cur;
+ ebitmap_t roles, new_roles;
+
+ l = NULL;
+ cur = state->base->role_allow_rules;
+ while (cur) {
+ ebitmap_init(&roles);
+ ebitmap_init(&new_roles);
+
+ if (role_set_expand(&cur->roles, &roles, state->out)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ if (role_set_expand(&cur->new_roles, &new_roles, state->out)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ for (i = ebitmap_startbit(&roles); i < ebitmap_length(&roles); i++) {
+ if (!ebitmap_get_bit(&roles, i))
+ continue;
+ for (j = ebitmap_startbit(&new_roles); j < ebitmap_length(&new_roles); j++) {
+ if (!ebitmap_get_bit(&new_roles, j))
+ continue;
+ /* check for duplicates */
+ cur_allow = state->out->role_allow;
+ while (cur_allow) {
+ if ((cur_allow->role == i + 1) &&
+ (cur_allow->new_role == j + 1))
+ break;
+ cur_allow = cur_allow->next;
+ }
+ if (cur_allow)
+ continue;
+ n = (role_allow_t*)malloc(sizeof(role_allow_t));
+ if (!n) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(role_allow_t));
+ n->role = i + 1;
+ n->new_role = j + 1;
+ if (l) {
+ l->next = n;
+ } else {
+ state->out->role_allow = n;
+ }
+ l = n;
+ }
+ }
+
+ ebitmap_destroy(&roles);
+ ebitmap_destroy(&new_roles);
+
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+static int copy_role_trans(expand_state_t *state)
+{
+ int i, j;
+ role_trans_t *n, *l, *cur_trans;
+ role_trans_rule_t *cur;
+ ebitmap_t roles, types;
+
+ l = NULL;
+ cur = state->base->role_tr_rules;
+ while (cur) {
+ ebitmap_init(&roles);
+ ebitmap_init(&types);
+
+ if (role_set_expand(&cur->roles, &roles, state->out)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ if (expand_convert_type_set(state->base, state->typemap, &cur->types, &types)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ for (i = ebitmap_startbit(&roles); i < ebitmap_length(&roles); i++) {
+ if (!ebitmap_get_bit(&roles, i))
+ continue;
+ for (j = ebitmap_startbit(&types); j < ebitmap_length(&types); j++) {
+ if (!ebitmap_get_bit(&types, j))
+ continue;
+
+ cur_trans = state->out->role_tr;
+ while (cur_trans) {
+ if ((cur_trans->role == i + 1) &&
+ (cur_trans->type == j + 1)) {
+ if (cur_trans->new_role == cur->new_role) {
+ break;
+ } else {
+ write_error (state, "Conflicting role trans rule %s %s : %s",
+ state->out->p_role_val_to_name[i],
+ state->out->p_type_val_to_name[j],
+ state->out->p_role_val_to_name[cur->new_role - 1]);
+ return -1;
+ }
+ }
+ cur_trans = cur_trans->next;
+ }
+ if (cur_trans)
+ continue;
+
+ n = (role_trans_t*)malloc(sizeof(role_trans_t));
+ if (!n) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(role_trans_t));
+ n->role = i + 1;
+ n->type = j + 1;
+ n->new_role = cur->new_role;
+ if (l) {
+ l->next = n;
+ } else {
+ state->out->role_tr = n;
+ }
+ l = n;
+ }
+ }
+
+ ebitmap_destroy(&roles);
+ ebitmap_destroy(&types);
+
+ cur = cur->next;
+ }
+ return 0;
+}
+
+/* Search for an AV tab node within a hash table with the given key.
+ * If the node does not exist, create it and return it; otherwise
+ * return the pre-existing one.
+ *
+ * When looking for the existing node, use 'lookup_specified' as part
+ * of the lookup key. If doesn't exist, then create it, but instead
+ * set the node's specified field to 'real_specified'.
+*/
+static avtab_ptr_t find_avtab_node(avtab_t *avtab, avtab_key_t *key,
+ uint32_t lookup_specified, uint32_t real_specified,
+ cond_av_list_t **cond)
+{
+ avtab_ptr_t node;
+ avtab_datum_t avdatum;
+ cond_av_list_t *nl;
+
+ node = avtab_search_node(avtab, key, lookup_specified);
+
+ /* If this is for conditional policies, keep searching in case
+ the node is part of my conditional avtab. */
+ if (cond) {
+ while (node) {
+ if (node->parse_context == cond)
+ break;
+ node = avtab_search_node_next(node, lookup_specified);
+ }
+ }
+
+ if (!node) {
+ memset(&avdatum, 0, sizeof avdatum);
+ avdatum.specified = real_specified;
+ /* this is used to get the node - insertion is actually unique */
+ node = avtab_insert_nonunique(avtab, key, &avdatum);
+ if (!node) {
+ fprintf(stderr, "hash table overflow");
+ return NULL;
+ }
+ if (cond) {
+ node->parse_context = cond;
+ nl = (cond_av_list_t*)malloc(sizeof(cond_av_list_t));
+ if (!nl) {
+ fprintf(stderr, "Memory error\n");
+ return NULL;
+ }
+ memset(nl, 0, sizeof(cond_av_list_t));
+ nl->node = node;
+ nl->next = *cond;
+ *cond = nl;
+ }
+ }
+
+ return node;
+}
+
+static int expand_terule_helper(policydb_t *p, uint32_t *typemap, uint32_t specified,
+ cond_av_list_t **cond, cond_av_list_t **other,
+ uint32_t stype, uint32_t ttype, class_perm_node_t *perms,
+ avtab_t *avtab, int enabled, char **error_msg)
+{
+ avtab_key_t avkey;
+ avtab_datum_t *avdatump;
+ avtab_ptr_t node;
+ class_perm_node_t *cur;
+ int conflict;
+ uint32_t oldtype = 0, spec = 0;
+
+ if (specified & AVRULE_TRANSITION) {
+ spec = AVTAB_TRANSITION;
+ } else if (specified & AVRULE_MEMBER) {
+ spec = AVTAB_MEMBER;
+ } else if (specified & AVRULE_CHANGE) {
+ spec = AVTAB_CHANGE;
+ } else {
+ assert(0); /* unreachable */
+ }
+
+ cur = perms;
+ while (cur) {
+ uint32_t remapped_data = typemap ? typemap[cur->data - 1] : cur->data;
+ avkey.source_type = stype + 1;
+ avkey.target_type = ttype + 1;
+ avkey.target_class = cur->class;
+
+ conflict = 0;
+ /* check to see if the expanded TE already exists --
+ * either in the global scope or in another
+ * conditional AV tab */
+ node = avtab_search_node(&p->te_avtab, &avkey, spec);
+ if (node) {
+ conflict = 1;
+ } else {
+ node = avtab_search_node(&p->te_cond_avtab, &avkey, spec);
+ if (node && node->parse_context != other) {
+ conflict = 2;
+ }
+ }
+
+ if (conflict) {
+ avdatump = &node->datum;
+ if (specified & AVRULE_TRANSITION) {
+ oldtype = avtab_transition(avdatump);
+ } else if (specified & AVRULE_MEMBER) {
+ oldtype = avtab_member(avdatump);
+ } else if (specified & AVRULE_CHANGE) {
+ oldtype = avtab_change(avdatump);
+ }
+ /* ignore duplicates */
+
+ if (oldtype == remapped_data)
+ return 1;
+ if (error_msg) {
+ *error_msg = (char*)malloc(4096);
+ if (!*error_msg) {
+ fprintf(stderr, "Memory error\n");
+ return -1;
+ }
+ snprintf(*error_msg, 4096, "conflicting TE rule for (%s, %s:%s): default was %s, new is %s\n",
+ p->p_type_val_to_name[avkey.source_type - 1],
+ p->p_type_val_to_name[avkey.target_type - 1],
+ p->p_class_val_to_name[avkey.target_class - 1],
+ p->p_type_val_to_name[oldtype - 1],
+ p->p_type_val_to_name[remapped_data]);
+ /* This should probably return a
+ failure but the current compiler
+ doesn't do this so we won't but we
+ will print the error which would
+ normally get passed back to the
+ caller */
+ fprintf(stderr, "%s\n",*error_msg);
+ }
+ /* to maintain the behavior of the upstream
+ compiler, if the rule is in a conditional
+ and is conflicting with the unconditional
+ rule then we bail */
+ if (cond && conflict == 1)
+ return 0;
+ }
+
+ /* the upstream compiler does not collapse multiple AV
+ rules into a single one for those given within
+ conditionals */
+ node = find_avtab_node(avtab, &avkey,
+ (cond == NULL ? AVTAB_TYPE : spec),
+ spec, cond);
+ if (!node)
+ return -1;
+ avdatump = &node->datum;
+ if (enabled) {
+ avdatump->specified |= AVTAB_ENABLED;
+ }
+ else {
+ avdatump->specified &= ~AVTAB_ENABLED;
+ }
+
+ if (specified & AVRULE_TRANSITION) {
+ avtab_transition(avdatump) = remapped_data;
+ } else if (specified & AVRULE_MEMBER) {
+ avtab_member(avdatump) = remapped_data;
+ } else if (specified & AVRULE_CHANGE) {
+ avtab_change(avdatump) = remapped_data;
+ } else {
+ assert(0); /* should never occur */
+ }
+
+ cur = cur->next;
+ }
+
+ return 1;
+}
+
+static int expand_avrule_helper(uint32_t specified,
+ cond_av_list_t **cond,
+ uint32_t stype, uint32_t ttype, class_perm_node_t *perms,
+ avtab_t *avtab, int enabled)
+{
+ avtab_key_t avkey;
+ avtab_datum_t *avdatump;
+ avtab_ptr_t node;
+ class_perm_node_t *cur;
+ uint32_t spec = 0;
+
+ if (specified & AVRULE_ALLOWED) {
+ spec = AVTAB_ALLOWED;
+ } else if (specified & AVRULE_AUDITALLOW) {
+ spec = AVTAB_AUDITALLOW;
+ } else if (specified & AVRULE_AUDITDENY) {
+ spec = AVTAB_AUDITDENY;
+ } else if (specified & AVRULE_DONTAUDIT) {
+ spec = AVTAB_AUDITDENY;
+ } else {
+ assert(0); /* unreachable */
+ }
+
+ cur = perms;
+ while (cur) {
+ avkey.source_type = stype + 1;
+ avkey.target_type = ttype + 1;
+ avkey.target_class = cur->class;
+
+ /* the upstream compiler does not collapse multiple AV
+ rules into a single one for those given within
+ conditionals */
+ node = find_avtab_node(avtab, &avkey,
+ (cond == NULL ? AVTAB_AV : spec),
+ spec, cond);
+ if (!node)
+ return -1;
+ avdatump = &node->datum;
+ avdatump->specified |= spec;
+ if (enabled) {
+ avdatump->specified |= AVTAB_ENABLED;
+ }
+ else {
+ avdatump->specified &= ~AVTAB_ENABLED;
+ }
+
+ if (specified & AVRULE_ALLOWED) {
+ avtab_allowed(avdatump) |= cur->data;
+ } else if (specified & AVRULE_AUDITALLOW) {
+ avtab_auditallow(avdatump) |= cur->data;
+ } else if (specified & AVRULE_AUDITDENY) {
+ /* Since a '0' in an auditdeny mask represents
+ * a permission we do NOT want to audit
+ * (dontaudit), we use the '&' operand to
+ * ensure that all '0's in the mask are
+ * retained (much unlike the allow and
+ * auditallow cases).
+ */
+ avtab_auditdeny(avdatump) &= cur->data;
+ } else if (specified & AVRULE_DONTAUDIT) {
+ if (avtab_auditdeny(avdatump))
+ avtab_auditdeny(avdatump) &= ~cur->data;
+ else
+ avtab_auditdeny(avdatump) = ~cur->data;
+ } else {
+ assert(0); /* should never occur */
+ }
+
+ cur = cur->next;
+ }
+ return 1;
+}
+
+static int expand_rule_helper(policydb_t *p, uint32_t *typemap,
+ avrule_t *source_rule, avtab_t *dest_avtab,
+ cond_av_list_t **cond, cond_av_list_t **other,
+ int enabled, char **error_msg,
+ ebitmap_t *stypes, ebitmap_t *ttypes)
+{
+ int i, j, retval;
+ for (i = ebitmap_startbit(stypes); i < ebitmap_length(stypes); i++) {
+ if (!ebitmap_get_bit(stypes, i))
+ continue;
+ if (source_rule->flags & RULE_SELF) {
+ if (source_rule->specified & AVRULE_AV) {
+ if ((retval =
+ expand_avrule_helper(source_rule->specified,
+ cond,
+ i, i, source_rule->perms,
+ dest_avtab, enabled)) != 1) {
+ return retval;
+ }
+ } else {
+ if ((retval =
+ expand_terule_helper(p,
+ typemap, source_rule->specified,
+ cond, other,
+ i, i, source_rule->perms,
+ dest_avtab, enabled, error_msg)) != 1) {
+ return retval;
+ }
+ }
+ }
+ for (j = ebitmap_startbit(ttypes); j < ebitmap_length(ttypes); j++) {
+ if (!ebitmap_get_bit(ttypes, j))
+ continue;
+ if (source_rule->specified & AVRULE_AV) {
+ if ((retval =
+ expand_avrule_helper(source_rule->specified,
+ cond,
+ i, j, source_rule->perms,
+ dest_avtab, enabled)) != 1) {
+ return retval;
+ }
+ } else {
+ if ((retval =
+ expand_terule_helper(p,
+ typemap, source_rule->specified,
+ cond, other,
+ i, j, source_rule->perms,
+ dest_avtab, enabled, error_msg)) != 1) {
+ return retval;
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+/* Expand a rule into a given avtab - checking for conflicting type
+ * rules in the destination policy. Return 1 on success, 0 if the
+ * rule conflicts with something (and hence was not added), or -1 on
+ * error. */
+static int convert_and_expand_rule(policydb_t *source_pol, policydb_t *dest_pol,
+ uint32_t *typemap, avrule_t *source_rule, avtab_t *dest_avtab,
+ cond_av_list_t **cond, cond_av_list_t **other,
+ int enabled, char **error_msg) {
+ int retval;
+ ebitmap_t stypes, ttypes;
+
+ if (source_rule->specified & AVRULE_NEVERALLOW)
+ return 1;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (expand_convert_type_set(source_pol, typemap, &source_rule->stypes, &stypes))
+ return -1;
+ if (expand_convert_type_set(source_pol, typemap, &source_rule->ttypes, &ttypes))
+ return -1;
+
+ retval = expand_rule_helper(dest_pol, typemap,
+ source_rule, dest_avtab,
+ cond, other,
+ enabled, error_msg,
+ &stypes, &ttypes);
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return retval;
+}
+
+
+static int cond_avrule_list_copy(policydb_t *source_pol, policydb_t *dest_pol,
+ avrule_t *source_rules, avtab_t *dest_avtab,
+ cond_av_list_t **list, cond_av_list_t **other,
+ uint32_t *typemap, int enabled,
+ expand_state_t *state)
+{
+ char *error_msg;
+ avrule_t *cur;
+
+ cur = source_rules;
+ error_msg = NULL;
+ while (cur) {
+ if (convert_and_expand_rule(source_pol, dest_pol,
+ typemap, cur, dest_avtab,
+ list, other,
+ enabled, &error_msg) != 1) {
+ if (error_msg) {
+ write_error (state, "%s", error_msg);
+ free(error_msg);
+ }
+ return -1;
+ }
+ cur = cur->next;
+ }
+
+ return 0;
+}
+
+/* copy the nodes in *reverse* order -- the result is that the last
+ * given conditional appears first in the policy, so as to match the
+ * behavior of the upstream compiler */
+static int cond_node_copy(cond_node_t *cn, expand_state_t *state)
+{
+ cond_node_t *new_cond;
+
+ if (cn == NULL) {
+ return 0;
+ }
+ if (cond_node_copy(cn->next, state)) {
+ return -1;
+ }
+ if (cond_normalize_expr(state->base, cn)) {
+ write_error (state, "Error while normalizing conditional");
+ return -1;
+ }
+
+ new_cond = cond_node_search(state->out, state->out->cond_list, cn);
+ if (!new_cond) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ if (cond_avrule_list_copy(state->base, state->out,
+ cn->avtrue_list, &state->out->te_cond_avtab,
+ &new_cond->true_list, &new_cond->false_list,
+ state->typemap, new_cond->cur_state, state))
+ return -1;
+ if (cond_avrule_list_copy(state->base, state->out,
+ cn->avfalse_list, &state->out->te_cond_avtab,
+ &new_cond->false_list, &new_cond->true_list,
+ state->typemap, !new_cond->cur_state, state))
+ return -1;
+
+ return 0;
+}
+
+static int context_copy(context_struct_t *dst, context_struct_t *src, expand_state_t *state)
+{
+ dst->user = src->user;
+ dst->role = src->role;
+ dst->type = state->typemap[src->type - 1];
+ return mls_context_cpy(dst, src);
+}
+
+static int ocontext_copy(expand_state_t *state)
+{
+ int i, j;
+ ocontext_t *c, *n, *l;
+
+ for (i = 0; i < OCON_NUM; i++) {
+ l = NULL;
+ for (c = state->base->ocontexts[i]; c; c = c->next) {
+ n = malloc(sizeof(ocontext_t));
+ if (!n) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(n, 0, sizeof(ocontext_t));
+ if (l) {
+ l->next = n;
+ } else {
+ state->out->ocontexts[i] = n;
+ }
+ l = n;
+ if (context_copy(&n->context[0], &c->context[0], state)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ switch (i) {
+ case OCON_ISID:
+ n->sid[0] = c->sid[0];
+ break;
+ case OCON_FS: /* FALLTHROUGH */
+ case OCON_NETIF:
+ n->u.name = strdup(c->u.name);
+ if (!n->u.name) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ if (context_copy(&n->context[1], &c->context[1], state)) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ break;
+ case OCON_PORT:
+ n->u.port.protocol = c->u.port.protocol;
+ n->u.port.low_port = c->u.port.low_port;
+ n->u.port.high_port = c->u.port.high_port;
+ break;
+ case OCON_NODE:
+ n->u.node.addr = c->u.node.addr;
+ n->u.node.mask = c->u.node.mask;
+ break;
+ case OCON_FSUSE:
+ n->v.behavior = c->v.behavior;
+ n->u.name = strdup(c->u.name);
+ if (!n->u.name) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ break;
+ case OCON_NODE6:
+ for (j = 0; j < 4; j++)
+ n->u.node6.addr[j] = c->u.node6.addr[j];
+ for (j = 0; j < 4; j++)
+ n->u.node6.mask[j] = c->u.node6.mask[j];
+ break;
+ default:
+ /* shouldn't get here */
+ assert(0);
+ }
+ }
+ }
+ return 0;
+ }
+
+static int genfs_copy(expand_state_t *state)
+{
+ ocontext_t *c, *newc, *l;
+ genfs_t *genfs, *newgenfs, *end;
+
+ end = NULL;
+ for (genfs = state->base->genfs; genfs; genfs = genfs->next) {
+ newgenfs = malloc(sizeof(genfs_t));
+ if (!newgenfs) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(newgenfs, 0, sizeof(genfs_t));
+ newgenfs->fstype = strdup(genfs->fstype);
+ if (!newgenfs->fstype) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+
+ l = NULL;
+ for (c = genfs->head; c; c = c->next) {
+ newc = malloc(sizeof(ocontext_t));
+ if (!newc) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ memset(newc, 0, sizeof(ocontext_t));
+ newc->u.name = strdup(c->u.name);
+ if (!newc->u.name) {
+ write_error (state, "Out of memory!");
+ return -1;
+ }
+ newc->v.sclass = c->v.sclass;
+ context_copy(&newc->context[0], &c->context[0], state);
+ if (l)
+ l->next = newc;
+ else
+ newgenfs->head = newc;
+ l = newc;
+ }
+ if (!end) {
+ state->out->genfs = newgenfs;
+ } else {
+ end->next = newgenfs;
+ }
+ end = newgenfs;
+ }
+ return 0;
+}
+
+
+static int range_trans_clone(expand_state_t *state)
+{
+ range_trans_t *range = state->base->range_tr, *last_new_range = NULL;
+ state->out->range_tr = NULL;
+
+ if (state->verbose)
+ printf("copying range transitions\n");
+
+ while (range != NULL) {
+ range_trans_t *new_range;
+ if ((new_range = malloc(sizeof(*new_range))) == NULL) {
+ goto out_of_mem;
+ }
+ new_range->dom = range->dom;
+ new_range->type = range->type;
+ if (mls_level_clone(&new_range->range.level[0], &range->range.level[0]) == -1 ||
+ mls_level_clone(&new_range->range.level[1], &range->range.level[1])) {
+ goto out_of_mem;
+ }
+ new_range->next = NULL;
+ if (last_new_range == NULL) {
+ state->out->range_tr = last_new_range = new_range;
+ }
+ else {
+ last_new_range->next = new_range;
+ last_new_range = new_range;
+ }
+ range = range->next;
+ }
+ return 0;
+
+ out_of_mem:
+ write_error(state, "Out of memory!");
+ return -1;
+}
+
+static int type_attr_remove(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *p __attribute__ ((unused)))
+{
+ type_datum_t *typdatum;
+
+ typdatum = (type_datum_t *) datum;
+ if (typdatum->isattr)
+ return 1;
+ return 0;
+}
+
+
+int expand_convert_type_set(policydb_t *p, uint32_t *typemap, type_set_t *set, ebitmap_t *types)
+{
+ int i;
+ ebitmap_t tmp;
+
+ ebitmap_init(types);
+ ebitmap_init(&tmp);
+
+ if (type_set_expand(set, &tmp, p))
+ return -1;
+
+ for (i = ebitmap_startbit(&tmp); i < ebitmap_length(&tmp); i++) {
+ if (!ebitmap_get_bit(&tmp, i))
+ continue;
+ if (ebitmap_set_bit(types, typemap[i] - 1, 1))
+ return -1;
+ }
+
+ ebitmap_destroy(&tmp);
+
+ return 0;
+}
+
+
+
+/* Expand a rule into a given avtab - checking for conflicting type
+ * rules. Return 1 on success, 0 if the rule conflicts with something
+ * (and hence was not added), or -1 on error. */
+int expand_rule(policydb_t *source_pol,
+ avrule_t *source_rule, avtab_t *dest_avtab,
+ cond_av_list_t **cond, cond_av_list_t **other,
+ int enabled, char **error_msg)
+{
+ int retval;
+ ebitmap_t stypes, ttypes;
+
+ if (source_rule->specified & AVRULE_NEVERALLOW)
+ return 1;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (type_set_expand(&source_rule->stypes, &stypes, source_pol))
+ return -1;
+ if (type_set_expand(&source_rule->ttypes, &ttypes, source_pol))
+ return -1;
+ retval = expand_rule_helper(source_pol, NULL,
+ source_rule, dest_avtab,
+ cond, other, enabled, error_msg,
+ &stypes, &ttypes);
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+ return retval;
+}
+
+int role_set_expand(role_set_t *x, ebitmap_t *r, policydb_t *p)
+{
+ int i;
+
+ ebitmap_init(r);
+
+ if (x->flags & ROLE_STAR) {
+ for (i = 0; i < p->p_roles.nprim++; i++)
+ if (ebitmap_set_bit(r, i, 1))
+ return -1;
+ return 0;
+ }
+
+ for (i = ebitmap_startbit(&x->roles); i < ebitmap_length(&x->roles); i++) {
+ if (ebitmap_get_bit(&x->roles, i)) {
+ if(ebitmap_set_bit (r, i, 1))
+ return -1;
+ }
+ }
+
+ /* if role is to be complimented, invert the entire bitmap here */
+ if (x->flags & ROLE_COMP) {
+ for (i = 0; i < ebitmap_length(r); i++) {
+ if (ebitmap_get_bit(r, i)) {
+ if (ebitmap_set_bit(r, i, 0))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(r, i, 1))
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Expand a type set into an ebitmap containing the types. This
+ * handles the negset, attributes, and flags.
+ */
+int type_set_expand(type_set_t *set, ebitmap_t *t, policydb_t *p)
+{
+ int i;
+ ebitmap_t types, neg_types;
+
+ ebitmap_init(&types);
+ ebitmap_init(t);
+
+ /* First go through the types and OR all the attributes to types */
+ for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); i++) {
+ if (ebitmap_get_bit(&set->types, i)) {
+ if (p->type_val_to_struct[i]->isattr) {
+ if (ebitmap_or_eq(&types, &p->type_val_to_struct[i]->types)) {
+ return -1;
+ }
+ } else {
+ if (ebitmap_set_bit(&types, i, 1)) {
+ return -1;
+ }
+ }
+ }
+ }
+
+ /* Now do the same thing for negset */
+ ebitmap_init(&neg_types);
+ for (i = ebitmap_startbit(&set->negset); i < ebitmap_length(&set->negset); i++) {
+ if (ebitmap_get_bit(&set->negset, i)) {
+ if (p->type_val_to_struct[i]->isattr) {
+ if (ebitmap_or_eq(&neg_types, &p->type_val_to_struct[i]->types)) {
+ return -1;
+ }
+ } else {
+ if (ebitmap_set_bit(&neg_types, i, 1)) {
+ return -1;
+ }
+ }
+ }
+ }
+
+ if (set->flags & TYPE_STAR) {
+ /* set all types not in neg_types */
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (ebitmap_get_bit(&neg_types, i))
+ continue;
+ if (p->type_val_to_struct[i]->isattr)
+ continue;
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+ goto out;
+ }
+
+ for (i = 0; i < p->p_types.nprim; i++) {
+ if (ebitmap_get_bit(&types, i) && (!ebitmap_get_bit(&neg_types, i)))
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+
+ if (set->flags & TYPE_COMP) {
+ for(i = 0; i < p->p_types.nprim; i++) {
+ if (p->type_val_to_struct[i]->isattr) {
+ assert(!ebitmap_get_bit(t, i));
+ continue;
+ }
+ if (ebitmap_get_bit(t, i)) {
+ if (ebitmap_set_bit(t, i, 0))
+ return -1;
+ } else {
+ if (ebitmap_set_bit(t, i, 1))
+ return -1;
+ }
+ }
+ }
+
+out:
+
+ ebitmap_destroy(&types);
+ ebitmap_destroy(&neg_types);
+
+ return 0;
+}
+
+static int copy_neverallow (policydb_t *source_pol, policydb_t *dest_pol,
+ uint32_t *typemap, avrule_t *source_rule)
+{
+ ebitmap_t stypes, ttypes;
+ avrule_t *avrule;
+ class_perm_node_t *cur_perm, *new_perm, *tail_perm;
+
+ ebitmap_init(&stypes);
+ ebitmap_init(&ttypes);
+
+ if (expand_convert_type_set(source_pol, typemap, &source_rule->stypes, &stypes))
+ return -1;
+ if (expand_convert_type_set(source_pol, typemap, &source_rule->ttypes, &ttypes))
+ return -1;
+
+ avrule = (avrule_t*)malloc(sizeof(avrule_t));
+ if (!avrule)
+ return -1;
+
+ avrule_init(avrule);
+ avrule->specified = AVRULE_NEVERALLOW;
+ avrule->line = source_rule->line;
+ avrule->flags = source_rule->flags;
+
+ if (ebitmap_cpy(&avrule->stypes.types, &stypes))
+ return -1;
+
+ if (ebitmap_cpy(&avrule->ttypes.types, &ttypes))
+ return -1;
+
+ cur_perm = source_rule->perms;
+ tail_perm = NULL;
+ while (cur_perm) {
+ new_perm = (class_perm_node_t*)malloc(sizeof(class_perm_node_t));
+ if (!new_perm)
+ return -1;
+ class_perm_node_init(new_perm);
+ new_perm->class = cur_perm->class;
+ assert(new_perm->class);
+
+ /* once we have modules with permissions we'll need to map the permissions (and classes) */
+ new_perm->data = cur_perm->data;
+
+ if (!avrule->perms)
+ avrule->perms = new_perm;
+
+ if (tail_perm)
+ tail_perm->next = new_perm;
+ tail_perm = new_perm;
+ cur_perm = cur_perm->next;
+ }
+
+ /* just prepend the avrule, it'll never be written to disk */
+ if (!dest_pol->avrules)
+ dest_pol->avrules = avrule;
+ else {
+ avrule->next = dest_pol->avrules;
+ dest_pol->avrules = avrule;
+ }
+
+ ebitmap_destroy(&stypes);
+ ebitmap_destroy(&ttypes);
+
+ return 0;
+}
+
+
+int expand_module(policydb_t *base, policydb_t *out,
+ int verbose, char *error_buf, size_t error_buf_size)
+{
+ int retval = -1;
+ expand_state_t state;
+ avrule_t *cur;
+ char *error_msg = NULL;
+
+ state.verbose = verbose;
+ state.typemap = NULL;
+ state.base = base;
+ state.out = out;
+ state.error_buf = error_buf;
+ state.error_buf_size = error_buf_size;
+ if (error_buf != NULL && error_buf_size > 0) {
+ *error_buf = '\0';
+ }
+
+ if (policydb_index_classes(state.base)) {
+ write_error (&state, "Error while indexing base classes");
+ goto cleanup;
+ }
+ if (policydb_index_others(state.base, 0)) {
+ write_error (&state, "Error while indexing base symbols");
+ goto cleanup;
+ }
+ if (policydb_init(state.out, POLICY_KERN)) {
+ write_error (&state, "Out of memory!");
+ goto cleanup;
+ }
+
+ if ((state.typemap = (uint32_t*)calloc(state.base->p_types.nprim, sizeof(uint32_t))) == NULL) {
+ write_error (&state, "Out of memory!");
+ goto cleanup;
+ }
+
+ /* order is important - types must be first */
+
+ /* copy types */
+ if (hashtab_map(state.base->p_types.table, type_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy commons */
+ if (hashtab_map(state.base->p_commons.table, common_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ /* copy classes */
+ if (hashtab_map(state.base->p_classes.table, class_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ if (policydb_index_classes(out)) {
+ write_error (&state, "Error while indexing out classes");
+ goto cleanup;
+ }
+ /* copy aliases */
+ if (hashtab_map(state.base->p_types.table, alias_copy_callback, &state))
+ goto cleanup;
+
+ /* copy roles */
+ if (hashtab_map(state.base->p_roles.table, role_copy_callback, &state))
+ goto cleanup;
+
+ /* copy users */
+ if (hashtab_map(state.base->p_users.table, user_copy_callback, &state))
+ goto cleanup;
+
+ /* copy bools */
+ if (hashtab_map(state.base->p_bools.table, bool_copy_callback, &state))
+ goto cleanup;
+
+ /* now copy MLS's sensitivity level and categories */
+ if (hashtab_map(state.base->p_levels.table, sens_copy_callback, &state) ||
+ hashtab_map(state.base->p_cats.table, cats_copy_callback, &state)) {
+ goto cleanup;
+ }
+
+ if (policydb_index_classes(out)) {
+ write_error (&state, "Error while indexing out classes");
+ goto cleanup;
+ }
+ if (policydb_index_others(out, 0)) {
+ write_error (&state, "Error while indexing symbols");
+ goto cleanup;
+ }
+
+ /* role allows */
+ if (copy_role_allows(&state))
+ goto cleanup;
+
+ /* role trans */
+ if (copy_role_trans(&state))
+ goto cleanup;
+
+ /* copy rules */
+ cur = state.base->avrules;
+ while (cur) {
+ if (cur->specified & AVRULE_NEVERALLOW) {
+ /* We'll just copy this over directly so we can check the assertions later */
+ if (copy_neverallow(state.base, out, state.typemap, cur))
+ write_error (&state, "Error while copying neverallows.");
+ } else {
+ if (convert_and_expand_rule(state.base, out,
+ state.typemap, cur, &out->te_avtab,
+ NULL, NULL,
+ 0, &error_msg) != 1) {
+ if (error_msg == NULL) {
+ write_error (&state, "Error while expanding rule.");
+ }
+ else {
+ write_error (&state, "%s", error_msg);
+ free(error_msg);
+ }
+ goto cleanup;
+ }
+ }
+ cur = cur->next;
+ }
+
+ /* copy conditional rules */
+ if (cond_node_copy(state.base->cond_list, &state))
+ goto cleanup;
+
+ cond_optimize_lists(state.out->cond_list);
+ evaluate_conds(state.out);
+
+ /* copy ocontexts */
+ if (ocontext_copy(&state))
+ goto cleanup;
+
+ /* copy genfs */
+ if (genfs_copy(&state))
+ goto cleanup;
+
+ if (range_trans_clone(&state) == -1) {
+ goto cleanup;
+ }
+
+ hashtab_map_remove_on_error(state.out->p_types.table,
+ type_attr_remove, 0, 0);
+
+ retval = 0;
+
+ cleanup:
+
+ free (state.typemap);
+ return retval;
+}
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [Patch 2/3] Loadable policy module infrastructure
2005-05-26 17:27 [Patch 2/3] Loadable policy module infrastructure Joshua Brindle
@ 2005-06-01 12:25 ` Stephen Smalley
2005-06-01 13:02 ` Joshua Brindle
0 siblings, 1 reply; 3+ messages in thread
From: Stephen Smalley @ 2005-06-01 12:25 UTC (permalink / raw)
To: Joshua Brindle; +Cc: selinux, selinux-dev
On Thu, 2005-05-26 at 13:27 -0400, Joshua Brindle wrote:
> diff -burNd a1/libsepol/src/expand.c b/libsepol/src/expand.c
> --- a1/libsepol/src/expand.c 1969-12-31 19:00:00.000000000 -0500
> +++ b/libsepol/src/expand.c 2005-05-25 13:11:19.526055000 -0400
> + new_type->isattr = type->isattr;
> + if (!type->isattr) {
> + new_type->value = ++state->out->p_types.nprim;
> + /* FIX ME: temp fix here */
> + new_type->value = type->order;
> + new_type->primary = 1;
> + }
Is this an attempt to preserve type value ordering to allow easier
comparison of the resulting binary policies before and after the patch?
Shouldn't matter if using sediff, right? I'd advise just dropping it.
--
Stephen Smalley
National Security Agency
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [Patch 2/3] Loadable policy module infrastructure
2005-06-01 12:25 ` Stephen Smalley
@ 2005-06-01 13:02 ` Joshua Brindle
0 siblings, 0 replies; 3+ messages in thread
From: Joshua Brindle @ 2005-06-01 13:02 UTC (permalink / raw)
To: Stephen Smalley; +Cc: selinux, selinux-dev
On Wed, 2005-06-01 at 08:25 -0400, Stephen Smalley wrote:
>
> Is this an attempt to preserve type value ordering to allow easier
> comparison of the resulting binary policies before and after the
> patch?
> Shouldn't matter if using sediff, right? I'd advise just dropping it.
Yes, it was added so that we could ensure the binaries created are the
same. sediff can verify much of the policy is the same but it still
doesn't analyze every piece of policy (eg, constraints, ocontexts, MLS)
so even though sediff showed no difference we wanted to ensure the
policies were indeed identical. I had every intention to drop this after
everyone was satisfied that it was creating policies correctly :)
Joshua
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2005-06-01 13:02 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-05-26 17:27 [Patch 2/3] Loadable policy module infrastructure Joshua Brindle
2005-06-01 12:25 ` Stephen Smalley
2005-06-01 13:02 ` Joshua Brindle
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.