Re: [PATCH 5/6] SELinux: allow userspace to read policy back out of the kernel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Oct 13, 2010 at 5:50 PM, Eric Paris <eparis@xxxxxxxxxx> wrote:
> There is interest in being able to see what the actual policy is that was
> loaded into the kernel.  The patch creates a new selinuxfs file
> /selinux/policy which can be read by userspace.  The actual policy that is
> loaded into the kernel will be written back out to userspace.

To get bit-for-bit copies of the policy back from the kernel you have
to patch userspace so it sends objects in the order the kernel expects
and uses them, thus the kernel can write them back in that same order.
 The two patches I used to make this situation true are attached.

-Eric
diff -Naupr libsepol-2.0.41/include/sepol/policydb/policydb.h libsepol-2.0.41.new/include/sepol/policydb/policydb.h
--- libsepol-2.0.41/include/sepol/policydb/policydb.h	2010-10-12 20:30:14.968548000 -0400
+++ libsepol-2.0.41.new/include/sepol/policydb/policydb.h	2010-10-12 17:38:42.850548078 -0400
@@ -201,8 +201,6 @@ typedef struct range_trans {
 	uint32_t source_type;
 	uint32_t target_type;
 	uint32_t target_class;
-	mls_range_t target_range;
-	struct range_trans *next;
 } range_trans_t;
 
 /* Boolean data type */
@@ -527,7 +525,7 @@ typedef struct policydb {
 	genfs_t *genfs;
 
 	/* range transitions */
-	range_trans_t *range_tr;
+	hashtab_t range_tr;
 
 	ebitmap_t *type_attr_map;
 
diff -Naupr libsepol-2.0.41/src/expand.c libsepol-2.0.41.new/src/expand.c
--- libsepol-2.0.41/src/expand.c	2010-10-12 20:31:34.220547308 -0400
+++ libsepol-2.0.41.new/src/expand.c	2010-10-12 17:33:49.847548611 -0400
@@ -1350,63 +1350,63 @@ static int exp_rangetr_helper(uint32_t s
 			      mls_semantic_range_t * trange,
 			      expand_state_t * state)
 {
-	range_trans_t *rt, *check_rt = state->out->range_tr;
-	mls_range_t exp_range;
+	range_trans_t *rt = NULL, check_rt;
+	mls_range_t *r = NULL, exp_range;
 	int rc = -1;
 
 	if (mls_semantic_range_expand(trange, &exp_range, state->out,
 				      state->handle))
 		goto out;
 
+	check_rt.source_type = stype;
+	check_rt.target_type = ttype;
+	check_rt.target_class = tclass;
 	/* check for duplicates/conflicts */
-	while (check_rt) {
-		if ((check_rt->source_type == stype) &&
-		    (check_rt->target_type == ttype) &&
-		    (check_rt->target_class == tclass)) {
-			if (mls_range_eq(&check_rt->target_range, &exp_range)) {
-				/* duplicate */
-				break;
-			} else {
-				/* conflict */
-				ERR(state->handle,
-				    "Conflicting range trans rule %s %s : %s",
-				    state->out->p_type_val_to_name[stype - 1],
-				    state->out->p_type_val_to_name[ttype - 1],
-				    state->out->p_class_val_to_name[tclass -
-								    1]);
-				goto out;
-			}
-		}
-		check_rt = check_rt->next;
-	}
-	if (check_rt) {
-		/* this is a dup - skip */
+	r = hashtab_search(state->out->range_tr, (hashtab_key_t)&check_rt);
+	if (r) {
+		/* duplicate */
 		rc = 0;
+		if (mls_range_eq(r, &exp_range))
+			goto out;
+
+		/* conflict */
+		rc = -1;
+		ERR(state->handle, "Conflicting range trans rule %s %s : %s",
+		    state->out->p_type_val_to_name[stype - 1],
+		    state->out->p_type_val_to_name[ttype - 1],
+		    state->out->p_class_val_to_name[tclass - 1]);
 		goto out;
 	}
 
-	rt = (range_trans_t *) calloc(1, sizeof(range_trans_t));
+	rt = calloc(1, sizeof(*rt));
 	if (!rt) {
 		ERR(state->handle, "Out of memory!");
-		goto out;
+		goto out_free;
 	}
 
-	rt->next = state->out->range_tr;
-	state->out->range_tr = rt;
+	r = calloc(1, sizeof(*r));
+	if (!r) {
+		ERR(state->handle, "Out of memory!");
+		goto out_free;
+	}
 
-	rt->source_type = stype;
-	rt->target_type = ttype;
-	rt->target_class = tclass;
-	if (mls_range_cpy(&rt->target_range, &exp_range)) {
+	if (mls_range_cpy(r, &exp_range)) {
 		ERR(state->handle, "Out of memory!");
-		goto out;
+		goto out_free;
 	}
 
-	rc = 0;
+	rt->source_type = stype;
+	rt->target_type = ttype;
+	rt->target_class = tclass;
 
-      out:
+	rc = hashtab_insert(state->out->range_tr, (hashtab_key_t)rt, r);
+out:
 	mls_range_destroy(&exp_range);
 	return rc;
+out_free:
+	free(rt);
+	free(r);
+	goto out;
 }
 
 static int expand_range_trans(expand_state_t * state,
diff -Naupr libsepol-2.0.41/src/mls.c libsepol-2.0.41.new/src/mls.c
--- libsepol-2.0.41/src/mls.c	2009-11-18 17:06:13.000000000 -0500
+++ libsepol-2.0.41.new/src/mls.c	2010-10-12 17:19:22.370548016 -0400
@@ -608,22 +608,22 @@ int mls_compute_sid(policydb_t * policyd
 		    sepol_security_class_t tclass,
 		    uint32_t specified, context_struct_t * newcontext)
 {
-	range_trans_t *rtr;
+	range_trans_t rt;
+	mls_range_t *r;
 	if (!policydb->mls)
 		return 0;
 
 	switch (specified) {
 	case AVTAB_TRANSITION:
+		rt.source_type = scontext->type;
+		rt.target_type = tcontext->type;
+		rt.target_class = tclass;
+
 		/* Look for a range transition rule. */
-		for (rtr = policydb->range_tr; rtr; rtr = rtr->next) {
-			if (rtr->source_type == scontext->type &&
-			    rtr->target_type == tcontext->type &&
-			    rtr->target_class == tclass) {
-				/* Set the range from the rule */
-				return mls_range_set(newcontext,
-						     &rtr->target_range);
-			}
-		}
+		r = hashtab_search(policydb->range_tr, (hashtab_key_t)&rt);
+		/* Set the range from the rule */
+		if (r)
+			return mls_range_set(newcontext, r);
 		/* Fallthrough */
 	case AVTAB_CHANGE:
 		if (tclass == SECCLASS_PROCESS)
diff -Naupr libsepol-2.0.41/src/policydb.c libsepol-2.0.41.new/src/policydb.c
--- libsepol-2.0.41/src/policydb.c	2010-10-12 20:30:14.980548000 -0400
+++ libsepol-2.0.41.new/src/policydb.c	2010-10-12 19:58:47.032548018 -0400
@@ -589,6 +589,33 @@ static int roles_init(policydb_t * p)
 	goto out;
 }
 
+static unsigned int rangetr_hash(hashtab_t h, const hashtab_key_t k)
+{
+	range_trans_t *key = (range_trans_t *)k;
+	return (key->source_type + (key->target_type << 3) +
+		(key->target_class << 5)) & (h->size - 1);
+}
+
+static int rangetr_cmp(hashtab_t h __attribute__ ((unused)),
+		       const hashtab_key_t k1, const hashtab_key_t k2)
+{
+	range_trans_t *key1 = (range_trans_t *)k1;
+	range_trans_t *key2 = (range_trans_t *)k2;
+	int v;
+
+	v = key1->source_type - key2->source_type;
+	if (v)
+		return v;
+
+	v = key1->target_type - key2->target_type;
+	if (v) 
+		return v;
+
+	v = key1->target_class - key2->target_class;
+
+	return v;
+}
+
 /*
  * Initialize a policy database structure.
  */
@@ -632,6 +659,11 @@ int policydb_init(policydb_t * p)
 	rc = cond_policydb_init(p);
 	if (rc)
 		goto out_free_symtab;
+
+	p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
+	if (rc)
+		goto out_free_symtab;
+
       out:
 	return rc;
 
@@ -1149,6 +1181,32 @@ void ocontext_xen_free(ocontext_t **ocon
 	}
 }
 
+static int range_destroy_helper(char *key, void *data,
+				void *ptr __attribute__((unused))) {
+	mls_range_t *r = (mls_range_t *)data;
+
+	free(key);
+
+	ebitmap_destroy(&r->level[0].cat);
+	ebitmap_destroy(&r->level[1].cat);
+	free(data);
+
+	return 0;
+}
+
+static int range_trans_destroy(hashtab_t h)
+{
+	int rc;
+
+	rc = hashtab_map(h, range_destroy_helper, NULL);
+	if (rc)
+		return rc;
+
+	hashtab_destroy(h);
+
+	return 0;
+}
+
 /*
  * Free any memory allocated by a policy database structure.
  */
@@ -1159,7 +1217,6 @@ void policydb_destroy(policydb_t * p)
 	unsigned int i;
 	role_allow_t *ra, *lra = NULL;
 	role_trans_t *tr, *ltr = NULL;
-	range_trans_t *rt, *lrt = NULL;
 	filename_trans_t *ft, *nft;
 
 	if (!p)
@@ -1242,19 +1299,7 @@ void policydb_destroy(policydb_t * p)
 	if (lra)
 		free(lra);
 
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		if (lrt) {
-			ebitmap_destroy(&lrt->target_range.level[0].cat);
-			ebitmap_destroy(&lrt->target_range.level[1].cat);
-			free(lrt);
-		}
-		lrt = rt;
-	}
-	if (lrt) {
-		ebitmap_destroy(&lrt->target_range.level[0].cat);
-		ebitmap_destroy(&lrt->target_range.level[1].cat);
-		free(lrt);
-	}
+	range_trans_destroy(p->range_tr);
 
 	if (p->type_attr_map) {
 		for (i = 0; i < p->p_types.nprim; i++) {
@@ -2873,11 +2918,47 @@ static avrule_t *avrule_read(policydb_t 
 	return NULL;
 }
 
+static int range_convert_to_rule(hashtab_key_t key, hashtab_datum_t data, void *ptr)
+{
+	policydb_t *p = ptr;
+	range_trans_t *rt = (range_trans_t *)key;
+	mls_range_t *r = (mls_range_t *)data;
+	range_trans_rule_t *rtr, *lrtr;
+	
+	rtr = malloc(sizeof(range_trans_rule_t));
+	if (!rtr)
+		return -1;
+	range_trans_rule_init(rtr);
+
+	lrtr = p->global->enabled->range_tr_rules;
+	while (lrtr && lrtr->next)
+		lrtr = lrtr->next;
+
+	if (lrtr)
+		lrtr->next = rtr;
+	else
+		p->global->enabled->range_tr_rules = rtr;
+
+	if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1))
+		return -1;
+
+	if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1))
+		return -1;
+
+	if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1))
+		return -1;
+
+	if (mls_range_to_semantic(r, &rtr->trange))
+		return -1;
+
+	return 0;
+}
+
 static int range_read(policydb_t * p, struct policy_file *fp)
 {
 	uint32_t buf[2], nel;
-	range_trans_t *rt, *lrt;
-	range_trans_rule_t *rtr, *lrtr = NULL;
+	range_trans_t *rt = NULL;
+	mls_range_t *r = NULL;
 	unsigned int i;
 	int new_rangetr = (p->policy_type == POLICY_KERN &&
 			   p->policyvers >= POLICYDB_VERSION_RANGETRANS);
@@ -2887,30 +2968,32 @@ static int range_read(policydb_t * p, st
 	if (rc < 0)
 		return -1;
 	nel = le32_to_cpu(buf[0]);
-	lrt = NULL;
 	for (i = 0; i < nel; i++) {
-		rt = calloc(1, sizeof(range_trans_t));
+		rt = calloc(1, sizeof(*rt));
 		if (!rt)
-			return -1;
-		if (lrt)
-			lrt->next = rt;
-		else
-			p->range_tr = rt;
+			goto err;
+		r = calloc(1, sizeof(*r));
+		if (!r)
+			goto err;
 		rc = next_entry(buf, fp, (sizeof(uint32_t) * 2));
 		if (rc < 0)
-			return -1;
+			goto err;
 		rt->source_type = le32_to_cpu(buf[0]);
 		rt->target_type = le32_to_cpu(buf[1]);
 		if (new_rangetr) {
 			rc = next_entry(buf, fp, (sizeof(uint32_t)));
 			if (rc < 0)
-				return -1;
+				goto err;
 			rt->target_class = le32_to_cpu(buf[0]);
 		} else
 			rt->target_class = SECCLASS_PROCESS;
-		if (mls_read_range_helper(&rt->target_range, fp))
-			return -1;
-		lrt = rt;
+		if (mls_read_range_helper(r, fp)) 
+			goto err;
+
+		rc = hashtab_insert(p->range_tr, (hashtab_key_t)rt,
+				    (hashtab_datum_t)r);
+		if (rc)
+			goto err;
 	}
 
 	/* if this is a kernel policy, we are done - otherwise we need to
@@ -2920,51 +3003,20 @@ static int range_read(policydb_t * p, st
 
 	/* create range_trans_rules_ts that correspond to the range_trans_ts
 	 * that were just read in from an older policy */
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		rtr = malloc(sizeof(range_trans_rule_t));
-		if (!rtr) {
-			return -1;
-		}
-		range_trans_rule_init(rtr);
-
-		if (lrtr)
-			lrtr->next = rtr;
-		else
-			p->global->enabled->range_tr_rules = rtr;
-
-		if (ebitmap_set_bit(&rtr->stypes.types, rt->source_type - 1, 1))
-			return -1;
-
-		if (ebitmap_set_bit(&rtr->ttypes.types, rt->target_type - 1, 1))
-			return -1;
-
-		if (ebitmap_set_bit(&rtr->tclasses, rt->target_class - 1, 1))
-			return -1;
-
-		if (mls_range_to_semantic(&rt->target_range, &rtr->trange))
-			return -1;
-
-		lrtr = rtr;
-	}
+	rc = hashtab_map(p->range_tr, range_convert_to_rule, p);
+	if (rc)
+		return rc;
 
-	/* now destroy the range_trans_ts */
-	lrt = NULL;
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		if (lrt) {
-			ebitmap_destroy(&lrt->target_range.level[0].cat);
-			ebitmap_destroy(&lrt->target_range.level[1].cat);
-			free(lrt);
-		}
-		lrt = rt;
-	}
-	if (lrt) {
-		ebitmap_destroy(&lrt->target_range.level[0].cat);
-		ebitmap_destroy(&lrt->target_range.level[1].cat);
-		free(lrt);
-	}
-	p->range_tr = NULL;
+	rc = range_trans_destroy(p->range_tr);
+	assert(!rc);
+	if (rc)
+		return rc;
 
 	return 0;
+err:
+	free(rt);
+	free(r);
+	return 1;
 }
 
 int avrule_read_list(policydb_t * p, avrule_t ** avrules,
diff -Naupr libsepol-2.0.41/src/write.c libsepol-2.0.41.new/src/write.c
--- libsepol-2.0.41/src/write.c	2010-10-12 20:30:14.983548000 -0400
+++ libsepol-2.0.41.new/src/write.c	2010-10-12 17:51:04.702547425 -0400
@@ -1345,50 +1345,95 @@ static int genfs_write(policydb_t * p, s
 	return POLICYDB_SUCCESS;
 }
 
-static int range_write(policydb_t * p, struct policy_file *fp)
+struct range_write_arg {
+	struct policydb *p;
+	struct policy_file *fp;
+	size_t nel;
+};
+
+static int range_count_helper(hashtab_key_t key,
+			      hashtab_datum_t data __attribute__((unused)),
+			      void *in_arg)
+{
+	range_trans_t *rt = (range_trans_t *)key;
+	struct range_write_arg *arg = in_arg;
+	int new_rangetr = (arg->p->policy_type == POLICY_KERN &&
+			   arg->p->policyvers >= POLICYDB_VERSION_RANGETRANS);
+
+	/* all range_transitions are written for the new format, only
+	   process related range_transitions are written for the old
+	   format, so count accordingly */
+	if (new_rangetr || rt->target_class == SECCLASS_PROCESS)
+		arg->nel++;
+
+	return 0;
+}
+
+static int range_write_helper(hashtab_key_t key, hashtab_datum_t data,
+			      void *in_arg)
 {
-	size_t nel, items;
-	struct range_trans *rt;
+	range_trans_t *rt = (range_trans_t *)key;
+	mls_range_t *r = (mls_range_t *)data;
+	struct range_write_arg *arg = in_arg;
+	struct policy_file *fp = arg->fp;
+	static int warning_issued = 0;
+	int new_rangetr = (arg->p->policy_type == POLICY_KERN &&
+			   arg->p->policyvers >= POLICYDB_VERSION_RANGETRANS);
 	uint32_t buf[2];
-	int new_rangetr = (p->policy_type == POLICY_KERN &&
-			   p->policyvers >= POLICYDB_VERSION_RANGETRANS);
-	int warning_issued = 0;
-
-	nel = 0;
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		/* all range_transitions are written for the new format, only
-		   process related range_transitions are written for the old
-		   format, so count accordingly */
-		if (new_rangetr || rt->target_class == SECCLASS_PROCESS)
-			nel++;
+	size_t items;
+
+	if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) {
+		if (!warning_issued)
+			WARN(fp->handle, "Discarding range_transition "
+			     "rules for security classes other than "
+			     "\"process\"");
+		warning_issued = 1;
+		return 0;
+	}
+
+	buf[0] = cpu_to_le32(rt->source_type);
+	buf[1] = cpu_to_le32(rt->target_type);
+	items = put_entry(buf, sizeof(uint32_t), 2, fp);
+	if (items != 2)
+		return POLICYDB_ERROR;
+
+	if (new_rangetr) {
+		buf[0] = cpu_to_le32(rt->target_class);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
 	}
-	buf[0] = cpu_to_le32(nel);
+
+	if (mls_write_range_helper(r, fp))
+		return POLICYDB_ERROR;
+
+	return 0;
+}
+
+static int range_write(policydb_t * p, struct policy_file *fp)
+{
+	struct range_write_arg arg;
+	size_t items;
+	uint32_t buf[1];
+	int rc;
+
+	arg.p = p;
+	arg.fp = fp;
+	arg.nel = 0;
+
+	rc = hashtab_map(p->range_tr, range_count_helper, &arg);
+	if (rc)
+		return POLICYDB_ERROR;
+
+	buf[0] = cpu_to_le32(arg.nel);
 	items = put_entry(buf, sizeof(uint32_t), 1, fp);
 	if (items != 1)
 		return POLICYDB_ERROR;
-	for (rt = p->range_tr; rt; rt = rt->next) {
-		if (!new_rangetr && rt->target_class != SECCLASS_PROCESS) {
-			if (!warning_issued)
-				WARN(fp->handle, "Discarding range_transition "
-				     "rules for security classes other than "
-				     "\"process\"");
-			warning_issued = 1;
-			continue;
-		}
-		buf[0] = cpu_to_le32(rt->source_type);
-		buf[1] = cpu_to_le32(rt->target_type);
-		items = put_entry(buf, sizeof(uint32_t), 2, fp);
-		if (items != 2)
-			return POLICYDB_ERROR;
-		if (new_rangetr) {
-			buf[0] = cpu_to_le32(rt->target_class);
-			items = put_entry(buf, sizeof(uint32_t), 1, fp);
-			if (items != 1)
-				return POLICYDB_ERROR;
-		}
-		if (mls_write_range_helper(&rt->target_range, fp))
-			return POLICYDB_ERROR;
-	}
+
+	rc = hashtab_map(p->range_tr, range_write_helper, &arg);
+	if (rc)
+		return POLICYDB_ERROR;
+
 	return POLICYDB_SUCCESS;
 }
 

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux