All of lore.kernel.org
 help / color / mirror / Atom feed
* [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

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.