All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC][PATCH] user_transition support for libsepol/checkpolicy
@ 2008-03-24 17:40 Joshua Brindle
  2008-03-24 20:15 ` Stephen Smalley
  2008-03-25 16:42 ` Stephen Smalley
  0 siblings, 2 replies; 27+ messages in thread
From: Joshua Brindle @ 2008-03-24 17:40 UTC (permalink / raw)
  To: SE Linux; +Cc: Stephen Smalley, Caleb Case

This implements user_transition in the toolchain. It should help on
distro's like Ubuntu that can't use run_init due to the user not knowing
the root password. It also seems like a more eloquent way to handle
service restarts than assigning system_r to user accounts and having the
daemons run as someuser:system_r:foo_t.

This has some issues in policy due to users not always being known in
the policy (eg., semanage users). I hope Chris or Dan will be able to
give some suggestions there.

The kernel patch (forthcoming after this is accepted) so far only
implements the transition on process transitions. Later on I plan on
doing a patch to expand role_transition to object classes (this is a
change needed for policy rbac support to work). I suspect I'll do the
same for user at that time. The question here is, do we think its worth
it to do fine grained transitions like we did for range_trans? (I don't).

Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
--- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
+++ libsepol/include/sepol/policydb/policydb.h	(working copy)
@@ -156,6 +156,14 @@
	mls_level_t exp_dfltlevel; /* expanded range used for validation */
} user_datum_t;

+typedef struct user_trans {
+	uint32_t user;		/* current role */
+	uint32_t type;		/* program executable type */
+	uint32_t new_user;	/* new role */
+	struct user_trans *next;
+} user_trans_t;
+
+
/* Sensitivity attributes */
typedef struct level_datum {
	mls_level_t *level;	/* sensitivity and associated categories */
@@ -225,6 +233,13 @@
	struct role_trans_rule *next;
} role_trans_rule_t;

+typedef struct user_trans_rule {
+	ebitmap_t users;	/* current role */
+	type_set_t types;	/* program executable type */
+	uint32_t new_user;	/* new role */
+	struct user_trans_rule *next;
+} user_trans_rule_t;
+
typedef struct role_allow_rule {
	role_set_t roles;	/* current role */
	role_set_t new_roles;	/* new roles */
@@ -348,6 +363,9 @@
	char *module_name;

	struct avrule_decl *next;
+
+	user_trans_rule_t *user_tr_rules;
+	
} avrule_decl_t;

typedef struct avrule_block {
@@ -470,6 +488,8 @@

	ebitmap_t policycaps;

+	user_trans_t *user_tr;
+
	unsigned policyvers;

	unsigned handle_unknown;
@@ -524,6 +544,9 @@
extern void role_trans_rule_init(role_trans_rule_t * x);
extern void role_trans_rule_list_destroy(role_trans_rule_t * x);

+extern void user_trans_rule_init(user_trans_rule_t * x);
+extern void user_trans_rule_list_destroy(user_trans_rule_t * x);
+
extern void role_datum_init(role_datum_t * x);
extern void role_datum_destroy(role_datum_t * x);
extern void role_allow_rule_init(role_allow_rule_t * x);
@@ -588,10 +611,11 @@
#define POLICYDB_VERSION_AVTAB		20
#define POLICYDB_VERSION_RANGETRANS	21
#define POLICYDB_VERSION_POLCAP		22
+#define POLICYDB_VERSION_USERTRANS	23

/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_POLCAP
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_USERTRANS

/* Module versions and specific changes*/
#define MOD_POLICYDB_VERSION_BASE	   4
@@ -600,9 +624,10 @@
#define MOD_POLICYDB_VERSION_RANGETRANS	   6
#define MOD_POLICYDB_VERSION_MLS_USERS	   6
#define MOD_POLICYDB_VERSION_POLCAP	   7
+#define MOD_POLICYDB_VERSION_USERTRANS	   8

#define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_POLCAP
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_USERTRANS

#define POLICYDB_CONFIG_MLS    1

Index: libsepol/src/policydb.c
===================================================================
--- libsepol/src/policydb.c	(revision 2854)
+++ libsepol/src/policydb.c	(working copy)
@@ -105,6 +105,12 @@
	 .ocon_num = OCON_NODE6 + 1,
	 },
	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_USERTRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 },
+	{
	 .type = POLICY_BASE,
	 .version = MOD_POLICYDB_VERSION_BASE,
	 .sym_num = SYM_NUM,
@@ -129,6 +135,12 @@
	 .ocon_num = OCON_NODE6 + 1,
	 },
	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_USERTRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	 },
+	{
	 .type = POLICY_MOD,
	 .version = MOD_POLICYDB_VERSION_BASE,
	 .sym_num = SYM_NUM,
@@ -150,7 +162,14 @@
	 .type = POLICY_MOD,
	 .version = MOD_POLICYDB_VERSION_POLCAP,
	 .sym_num = SYM_NUM,
-	 .ocon_num = 0},
+	 .ocon_num = 0
+	 },
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_USERTRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0
+	 },
};

#if 0
@@ -348,6 +367,30 @@
	}
}

+void user_trans_rule_init(user_trans_rule_t * x)
+{
+	memset(x, 0, sizeof(*x));
+	ebitmap_init(&x->users);
+	type_set_init(&x->types);
+}
+
+void user_trans_rule_destroy(user_trans_rule_t * x)
+{
+	if (x != NULL) {
+		ebitmap_init(&x->users);
+		type_set_destroy(&x->types);
+	}
+}
+
+void user_trans_rule_list_destroy(user_trans_rule_t * x)
+{
+	while (x != NULL) {
+		user_trans_rule_t *next = x->next;
+		user_trans_rule_destroy(x);
+		free(x);
+		x = next;
+	}
+}
void role_allow_rule_init(role_allow_rule_t * x)
{
	memset(x, 0, sizeof(role_allow_rule_t));
@@ -985,6 +1028,7 @@
	unsigned int i;
	role_allow_t *ra, *lra = NULL;
	role_trans_t *tr, *ltr = NULL;
+	user_trans_t *ut, *lut = NULL;
	range_trans_t *rt, *lrt = NULL;

	if (!p)
@@ -1058,6 +1102,14 @@
	if (ltr)
		free(ltr);

+	for (ut = p->user_tr; ut; ut = ut->next) {
+		if (lut)
+			free(lut);
+		lut = ut;
+	}
+	if (lut)
+		free(lut);
+
	for (ra = p->role_allow; ra; ra = ra->next) {
		if (lra)
			free(lra);
@@ -1983,6 +2035,40 @@
	return 0;
}

+int user_trans_read(user_trans_t ** t, struct policy_file *fp)
+{
+        unsigned int i;
+        uint32_t buf[3], nel;
+        user_trans_t *ut, *lut;
+        int rc;
+
+        rc = next_entry(buf, fp, sizeof(uint32_t));
+        if (rc < 0)
+                return -1;
+        nel = le32_to_cpu(buf[0]);
+        lut = NULL;
+        for (i = 0; i < nel; i++) {
+                ut = calloc(1, sizeof(struct user_trans));
+                if (!ut) {
+                        return -1;
+                }
+                if (lut) {
+                        lut->next = ut;
+                } else {
+                        *t = ut;
+                }
+                rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
+                if (rc < 0)
+                        return -1;
+                ut->user = le32_to_cpu(buf[0]);
+                ut->type = le32_to_cpu(buf[1]);
+                ut->new_user = le32_to_cpu(buf[2]);
+                lut = ut;
+        }
+        return 0;
+}
+
+
int role_allow_read(role_allow_t ** r, struct policy_file *fp)
{
	unsigned int i;
@@ -2679,6 +2765,48 @@
	return 0;
}

+static int user_trans_rule_read(user_trans_rule_t ** u, struct 
policy_file *fp)
+{
+        uint32_t buf[1], nel;
+        unsigned int i;
+        user_trans_rule_t *ut, *lut;
+        int rc;
+
+        rc = next_entry(buf, fp, sizeof(uint32_t));
+        if (rc < 0)
+                return -1;
+        nel = le32_to_cpu(buf[0]);
+        lut = NULL;
+        for (i = 0; i < nel; i++) {
+                ut = malloc(sizeof(user_trans_rule_t));
+                if (!ut) {
+                        return -1;
+                }
+                user_trans_rule_init(ut);
+
+                if (lut) {
+                        lut->next = ut;
+                } else {
+                        *u = ut;
+                }
+
+                if (ebitmap_read(&ut->users, fp))
+                        return -1;
+
+                if (type_set_read(&ut->types, fp))
+                        return -1;
+
+                rc = next_entry(buf, fp, sizeof(uint32_t));
+                if (rc < 0)
+                        return -1;
+                ut->new_user = le32_to_cpu(buf[0]);
+                lut = ut;
+        }
+
+        return 0;
+}
+
+
static int role_allow_rule_read(role_allow_rule_t ** r, struct 
policy_file *fp)
{
	unsigned int i;
@@ -2805,9 +2933,14 @@
	if (cond_read_list(p, &decl->cond_list, fp) == -1 ||
	    avrule_read_list(p, &decl->avrules, fp) == -1 ||
	    role_trans_rule_read(&decl->role_tr_rules, fp) == -1 ||
-	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1) {
+	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1)
+	    {
		return -1;
	}
+	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
+		if (user_trans_rule_read(&decl->user_tr_rules, fp))
+			return -1;
+	}
	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
	    range_trans_rule_read(&decl->range_tr_rules, fp) == -1) {
		return -1;
@@ -3179,6 +3312,10 @@
				goto bad;
		if (role_trans_read(&p->role_tr, fp))
			goto bad;
+		if (r_policyvers >= POLICYDB_VERSION_USERTRANS) {
+			if (user_trans_read(&p->user_tr, fp))
+				goto bad;
+		}
		if (role_allow_read(&p->role_allow, fp))
			goto bad;
	} else {
Index: libsepol/src/expand.c
===================================================================
--- libsepol/src/expand.c	(revision 2854)
+++ libsepol/src/expand.c	(working copy)
@@ -1060,6 +1060,80 @@
	return 0;
}

+static int copy_user_trans(expand_state_t * state, user_trans_rule_t * 
rules)
+{
+	unsigned int i, j;
+	user_trans_t *n, *l, *cur_trans;
+	user_trans_rule_t *cur;
+	ebitmap_t types;
+	ebitmap_node_t *rnode, *tnode;
+
+	/* start at the end of the list */
+	for (l = state->out->user_tr; l && l->next; l = l->next) ;
+
+	cur = rules;
+	while (cur) {
+		ebitmap_init(&types);
+
+		if (expand_convert_type_set
+		    (state->out, state->typemap, &cur->types, &types, 1)) {
+			ERR(state->handle, "Out of memory!");
+			return -1;
+		}
+		ebitmap_for_each_bit(&cur->users, rnode, i) {
+			if (!ebitmap_node_get_bit(rnode, i))
+				continue;
+			ebitmap_for_each_bit(&types, tnode, j) {
+				if (!ebitmap_node_get_bit(tnode, j))
+					continue;
+
+				cur_trans = state->out->user_tr;
+				while (cur_trans) {
+					if ((cur_trans->user == i + 1) &&
+					    (cur_trans->type == j + 1)) {
+						if (cur_trans->new_user ==
+						    cur->new_user) {
+							break;
+						} else {
+							ERR(state->handle,
+							    "Conflicting user trans rule %s %s : %s",
+							    state->out->p_user_val_to_name[i],
+							    state->out->p_type_val_to_name[j],
+							    state->out->p_user_val_to_name[cur->new_user - 1]);
+							return -1;
+						}
+					}
+					cur_trans = cur_trans->next;
+				}
+				if (cur_trans)
+					continue;
+
+				n = (user_trans_t *)
+				    malloc(sizeof(user_trans_t));
+				if (!n) {
+					ERR(state->handle, "Out of memory!");
+					return -1;
+				}
+				memset(n, 0, sizeof(user_trans_t));
+				n->user = i + 1;
+				n->type = j + 1;
+				n->new_user = cur->new_user;
+				if (l) {
+					l->next = n;
+				} else {
+					state->out->user_tr = n;
+				}
+				l = n;
+			}
+		}
+
+		ebitmap_destroy(&types);
+
+		cur = cur->next;
+	}
+	return 0;
+}
+
static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t 
tclass,
			      mls_semantic_range_t * trange,
			      expand_state_t * state)
@@ -2163,6 +2237,9 @@
			goto cleanup;
		}

+		if (copy_user_trans(state, decl->user_tr_rules))
+			goto cleanup;
+
		/* expand the range transition rules */
		if (expand_range_trans(state, decl->range_tr_rules))
			goto cleanup;
Index: libsepol/src/write.c
===================================================================
--- libsepol/src/write.c	(revision 2854)
+++ libsepol/src/write.c	(working copy)
@@ -487,6 +487,31 @@
	return POLICYDB_SUCCESS;
}

+static int user_trans_write(user_trans_t * u, struct policy_file *fp)
+{
+	user_trans_t *tr;
+	uint32_t buf[3];
+	size_t nel, items;
+
+	nel = 0;
+	for (tr = u; tr; tr = tr->next)
+		nel++;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (tr = u; tr; tr = tr->next) {
+		buf[0] = cpu_to_le32(tr->user);
+		buf[1] = cpu_to_le32(tr->type);
+		buf[2] = cpu_to_le32(tr->new_user);
+		items = put_entry(buf, sizeof(uint32_t), 3, fp);
+		if (items != 3)
+			return POLICYDB_ERROR;
+	}
+
+	return POLICYDB_SUCCESS;
+}
+
static int role_allow_write(role_allow_t * r, struct policy_file *fp)
{
	role_allow_t *ra;
@@ -1325,6 +1350,32 @@
	return POLICYDB_SUCCESS;
}

+static int user_trans_rule_write(user_trans_rule_t * t, struct 
policy_file *fp)
+{
+	int nel = 0;
+	size_t items;
+	uint32_t buf[1];
+	user_trans_rule_t *tr;
+
+	for (tr = t; tr; tr = tr->next)
+		nel++;
+	buf[0] = cpu_to_le32(nel);
+	items = put_entry(buf, sizeof(uint32_t), 1, fp);
+	if (items != 1)
+		return POLICYDB_ERROR;
+	for (tr = t; tr; tr = tr->next) {
+		if (ebitmap_write(&tr->users, fp))
+			return POLICYDB_ERROR;
+		if (type_set_write(&tr->types, fp))
+			return POLICYDB_ERROR;
+		buf[0] = cpu_to_le32(tr->new_user);
+		items = put_entry(buf, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return POLICYDB_ERROR;
+	}
+	return POLICYDB_SUCCESS;
+}
+
static int role_allow_rule_write(role_allow_rule_t * r, struct 
policy_file *fp)
{
	int nel = 0;
@@ -1414,6 +1465,10 @@
	    role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
		return POLICYDB_ERROR;
	}
+	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
+		if (user_trans_rule_write(decl->user_tr_rules, fp))	
+			return POLICYDB_ERROR;
+	}
	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
	    range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
		return POLICYDB_ERROR;
@@ -1642,6 +1697,10 @@
		}
		if (role_trans_write(p->role_tr, fp))
			return POLICYDB_ERROR;
+		if (p->policyvers >= POLICYDB_VERSION_USERTRANS) {
+			if (user_trans_write(p->user_tr, fp))
+				return POLICYDB_ERROR;
+		}
		if (role_allow_write(p->role_allow, fp))
			return POLICYDB_ERROR;
	} else {
Index: libsepol/src/link.c
===================================================================
--- libsepol/src/link.c	(revision 2854)
+++ libsepol/src/link.c	(working copy)
@@ -848,6 +848,34 @@
	return -1;
}

+static int user_bitmap_or_convert(ebitmap_t * users, ebitmap_t * dst,
+			       policy_module_t * mod, link_state_t * state)
+{
+	unsigned int i;
+	ebitmap_t tmp;
+	ebitmap_node_t *rnode;
+
+	ebitmap_init(&tmp);
+	ebitmap_for_each_bit(users, rnode, i) {
+		if (ebitmap_node_get_bit(rnode, i)) {
+			assert(mod->map[SYM_USERS][i]);
+			if (ebitmap_set_bit
+			    (&tmp, mod->map[SYM_USERS][i] - 1, 1)) {
+				goto cleanup;
+			}
+		}
+	}
+	if (ebitmap_union(dst, &tmp)) {
+		goto cleanup;
+	}
+	ebitmap_destroy(&tmp);
+	return 0;
+      cleanup:
+	ERR(state->handle, "Out of memory!");
+	ebitmap_destroy(&tmp);
+	return -1;
+}
+
static int mls_level_convert(mls_semantic_level_t * src, 
mls_semantic_level_t * dst,
			     policy_module_t * mod, link_state_t * state)
{
@@ -1004,13 +1032,22 @@
	link_state_t *state = (link_state_t *) data;
	policy_module_t *mod = state->cur;
	symtab_t *usertab;
+	scope_datum_t *scope;

	user = (user_datum_t *) datum;

+	scope = hashtab_search(state->cur->policy->p_users_scope.table, key);
+	assert(scope);
+	if (scope->scope == SCOPE_REQ) {
+		//this is required user, no role or mls data
+		return 0;
+	}
+
	if (state->dest_decl == NULL)
		usertab = &state->base->p_users;
-	else
+	else {
		usertab = &state->dest_decl->p_users;
+	}

	new_user = hashtab_search(usertab->table, id);
	assert(new_user != NULL);
@@ -1173,6 +1210,49 @@
	return -1;
}

+static int copy_user_trans_list(user_trans_rule_t * list,
+                                user_trans_rule_t ** dst,
+                                policy_module_t * module, link_state_t 
* state)
+{
+        user_trans_rule_t *cur, *new_rule = NULL, *tail;
+
+        cur = list;
+        tail = *dst;
+        while (tail && tail->next) {
+                tail = tail->next;
+        }
+        while (cur) {
+                if ((new_rule =
+                     (user_trans_rule_t *) 
malloc(sizeof(user_trans_rule_t))) ==
+                    NULL) {
+                        goto cleanup;
+                }
+                user_trans_rule_init(new_rule);
+
+                if (user_bitmap_or_convert(&cur->users, 
&new_rule->users, module, state))
+			goto cleanup;
+		if (type_set_or_convert(&cur->types, &new_rule->types, module, state)) {
+                        goto cleanup;
+                }
+
+                new_rule->new_user = 
module->map[SYM_USERS][cur->new_user - 1];
+
+                if (*dst == NULL) {
+                        *dst = new_rule;
+                } else {
+                        tail->next = new_rule;
+                }
+                tail = new_rule;
+                cur = cur->next;
+        }
+        return 0;
+      cleanup:
+        ERR(state->handle, "Out of memory!");
+        user_trans_rule_list_destroy(new_rule);
+        return -1;
+}
+
+
static int copy_role_allow_list(role_allow_rule_t * list,
				role_allow_rule_t ** dst,
				policy_module_t * module, link_state_t * state)
@@ -1446,6 +1526,10 @@
		return -1;
	}

+	if (copy_user_trans_list(src_decl->user_tr_rules, 
&dest_decl->user_tr_rules,
+				 module, state))
+		return -1;
+
	if (copy_range_trans_list(src_decl->range_tr_rules,
				  &dest_decl->range_tr_rules, module, state))
		return -1;
Index: checkpolicy/test/dismod.c
===================================================================
--- checkpolicy/test/dismod.c	(revision 2854)
+++ checkpolicy/test/dismod.c	(working copy)
@@ -354,6 +354,21 @@
	return 0;
}

+int display_user_set(ebitmap_t *u, policydb_t *p, FILE *fp)
+{
+	ebitmap_node_t *node;
+	int i;
+
+	fprintf(fp, " { ");
+	ebitmap_for_each_bit(u, node, i) {
+		if (ebitmap_node_get_bit(node, i)) {
+			display_id(p, fp, SYM_USERS, i, "");
+		}
+	}
+	fprintf(fp, " } ");
+	return 0;
+}
+
int display_bools(policydb_t * p, FILE * fp)
{
	int i;
@@ -461,7 +476,18 @@
		fprintf(fp, "\n");
	}
}
+void display_user_trans(user_trans_rule_t * tr, policydb_t * p, FILE * fp)

+{
+	for (; tr; tr = tr->next) {
+		fprintf(fp, "user transition ");
+		display_user_set(&tr->users, p, fp);
+		display_type_set(&tr->types, 0, p, fp);
+		display_id(p, fp, SYM_USERS, tr->new_user - 1, " :");
+		fprintf(fp, "\n");
+	}
+}
+
void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp)
{
	for (; ra; ra = ra->next) {
@@ -641,6 +667,10 @@
			}
			break;
		}
+	case 7:{
+			display_user_trans(decl->user_tr_rules, policy, out_fp);
+			break;
+		}
	default:{
			assert(0);
		}
@@ -806,6 +836,7 @@
	printf("c)  Display policy capabilities\n");
	printf("l)  Link in a module\n");
	printf("u)  Display the unknown handling setting\n");
+	printf("U)  Display user transitions\n");
	printf("\n");
	printf("f)  set output file\n");
	printf("m)  display menu\n");
@@ -918,9 +949,11 @@
			display_policycaps(&policydb, out_fp);
			break;
		case 'u':
-		case 'U':
			display_handle_unknown(&policydb, out_fp);
			break;
+		case 'U':
+			display_avblock(7, 0, &policydb, out_fp);
+			break;
		case 'f':
			printf
			    ("\nFilename for output (<CR> for screen output): ");
Index: checkpolicy/test/dispol.c
===================================================================
--- checkpolicy/test/dispol.c	(revision 2854)
+++ checkpolicy/test/dispol.c	(working copy)
@@ -299,6 +299,18 @@
	return 0;
}

+static void display_user_transitions(policydb_t *p, FILE *fp)
+{
+	user_trans_t *cur;
+	for (cur = p->user_tr; cur; cur = cur->next) {
+		fprintf(fp, "user_transition ");
+		fprintf(fp, "%s %s %s;\n",
+			p->p_user_val_to_name[cur->user - 1],
+			p->p_type_val_to_name[cur->type - 1],
+			p->p_user_val_to_name[cur->new_user - 1]);
+	}
+}
+
static void display_policycaps(policydb_t * p, FILE * fp)
{
	ebitmap_node_t *node;
@@ -332,6 +344,7 @@
	printf("\n");
	printf("c)  display policy capabilities\n");
	printf("u)  display unknown handling setting\n");
+	printf("U)  display user transitions\n");
	printf("f)  set output file\n");
	printf("m)  display menu\n");
	printf("q)  quit\n");
@@ -448,9 +461,11 @@
			display_policycaps(&policydb, out_fp);
			break;
		case 'u':
-		case 'U':
			display_handle_unknown(&policydb, out_fp);
			break;
+		case 'U':
+			display_user_transitions(&policydb, out_fp);
+			break;
		case 'f':
			printf
			    ("\nFilename for output (<CR> for screen output): ");
Index: checkpolicy/test/Makefile
===================================================================
--- checkpolicy/test/Makefile	(revision 2854)
+++ checkpolicy/test/Makefile	(working copy)
@@ -6,7 +6,7 @@
LIBDIR=$(PREFIX)/lib
INCLUDEDIR ?= $(PREFIX)/include

-CFLAGS ?= -g -Wall -O2 -pipe
+CFLAGS ?= -g3 -gdwarf-2 -Wall -O0 -pipe
override CFLAGS += -I$(INCLUDEDIR)

LDLIBS=-lfl -lsepol -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR)
Index: checkpolicy/policy_define.c
===================================================================
--- checkpolicy/policy_define.c	(revision 2854)
+++ checkpolicy/policy_define.c	(working copy)
@@ -2020,6 +2020,76 @@
	return -1;
}

+int define_user_trans(void)
+{
+        char *id;
+        user_datum_t *user, *u;
+	ebitmap_t users;
+        type_set_t types;
+        struct user_trans_rule *rule = NULL;
+        int add = 1;
+
+        if (pass == 1) {
+                while ((id = queue_remove(id_queue)))
+                        free(id);
+                while ((id = queue_remove(id_queue)))
+                        free(id);
+                id = queue_remove(id_queue);
+                free(id);
+                return 0;
+        }
+
+        ebitmap_init(&users);
+        type_set_init(&types);
+
+	while ((id = queue_remove(id_queue))) {
+		u = hashtab_search(policydbp->p_users.table, id);
+		if (!u) {
+			yyerror2("unknown user %s", id);
+			free(id);
+			return -1;
+		}
+		if (ebitmap_set_bit(&users, u->s.value - 1, TRUE))
+			return -1;
+	}
+	while ((id = queue_remove(id_queue))) {
+		if (set_types(&types, id, &add, 0))
+			return -1;
+	}
+	id = (char *)queue_remove(id_queue);
+	if (!id) {
+		yyerror("no new user in transition definition?");
+		goto bad;
+	}
+	if (!is_id_in_scope(SYM_USERS, id)) {
+		yyerror2("user %s is not within scope", id);
+		free(id);
+		goto bad;
+	}
+	user = hashtab_search(policydbp->p_users.table, id);
+	if (!user) {
+		yyerror2("unknown user %s used in transition definition", id);
+		goto bad;
+	}
+	rule = malloc(sizeof(struct user_trans_rule));
+	if (!rule) {
+		yyerror("out of memory");
+		return -1;
+	}
+	memset(rule, 0, sizeof(struct user_trans_rule));
+	rule->users = users;
+	rule->types = types;
+	rule->new_user = user->s.value;
+
+	append_user_trans(rule);
+
+	return 0;
+
+      bad:
+	return -1;
+}
+
+
int define_role_allow(void)
{
	char *id;
Index: checkpolicy/policy_scan.l
===================================================================
--- checkpolicy/policy_scan.l	(revision 2854)
+++ checkpolicy/policy_scan.l	(working copy)
@@ -102,6 +102,8 @@
type_change			{ return(TYPE_CHANGE); }
ROLE_TRANSITION |
role_transition			{ return(ROLE_TRANSITION); }
+USER_TRANSITION |
+user_transition			{ return(USER_TRANSITION); }
RANGE_TRANSITION |
range_transition		{ return(RANGE_TRANSITION); }
SENSITIVITY |
Index: checkpolicy/policy_define.h
===================================================================
--- checkpolicy/policy_define.h	(revision 2854)
+++ checkpolicy/policy_define.h	(working copy)
@@ -42,6 +42,7 @@
int define_role_allow(void);
int define_role_trans(void);
int define_role_types(void);
+int define_user_trans(void);
int define_sens(void);
int define_te_avtab(int which);
int define_typealias(void);
Index: checkpolicy/module_compiler.c
===================================================================
--- checkpolicy/module_compiler.c	(revision 2854)
+++ checkpolicy/module_compiler.c	(working copy)
@@ -1214,6 +1214,17 @@
	decl->role_tr_rules = role_tr_rules;
}

+void append_user_trans(user_trans_rule_t * user_tr_rules)
+{
+	avrule_decl_t *decl = stack_top->decl;
+
+	/* role transitions are not allowed within conditionals */
+	assert(stack_top->type == 1);
+
+	user_tr_rules->next = decl->user_tr_rules;
+	decl->user_tr_rules = user_tr_rules;
+}
+
/* this doesn't actually append, but really prepends it */
void append_role_allow(role_allow_rule_t * role_allow_rules)
{
Index: checkpolicy/policy_parse.y
===================================================================
--- checkpolicy/policy_parse.y	(revision 2854)
+++ checkpolicy/policy_parse.y	(working copy)
@@ -103,6 +103,7 @@
%token TYPE_MEMBER
%token TYPE_CHANGE
%token ROLE_TRANSITION
+%token USER_TRANSITION
%token RANGE_TRANSITION
%token SENSITIVITY
%token DOMINANCE
@@ -261,6 +262,7 @@
                         | transition_def
                         | range_trans_def
                         | te_avtab_def
+			| user_trans_def
			;
attribute_def           : ATTRIBUTE identifier ';'
                         { if (define_attrib()) return -1;}
@@ -411,6 +413,9 @@
role_trans_def		: ROLE_TRANSITION names names identifier ';'
			{if (define_role_trans()) return -1; }
			;
+user_trans_def		: USER_TRANSITION names names identifier ';'
+			{ if (define_user_trans()) return -1; }
+			;
role_allow_def		: ALLOW names names ';'
			{if (define_role_allow()) return -1; }
			;
Index: checkpolicy/module_compiler.h
===================================================================
--- checkpolicy/module_compiler.h	(revision 2854)
+++ checkpolicy/module_compiler.h	(working copy)
@@ -80,6 +80,7 @@
void append_role_trans(role_trans_rule_t * role_tr_rules);
void append_role_allow(role_allow_rule_t * role_allow_rules);
void append_range_trans(range_trans_rule_t * range_tr_rules);
+void append_user_trans(user_trans_rule_t * user_tr_rules);

/* Create a new optional block and add it to the global policy.
  * During the second pass resolve the block's requirements.  Return 0




--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 17:40 [RFC][PATCH] user_transition support for libsepol/checkpolicy Joshua Brindle
@ 2008-03-24 20:15 ` Stephen Smalley
  2008-03-24 20:27   ` Joshua Brindle
                     ` (3 more replies)
  2008-03-25 16:42 ` Stephen Smalley
  1 sibling, 4 replies; 27+ messages in thread
From: Stephen Smalley @ 2008-03-24 20:15 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: SE Linux, Caleb Case


On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> This implements user_transition in the toolchain. It should help on
> distro's like Ubuntu that can't use run_init due to the user not knowing
> the root password. It also seems like a more eloquent way to handle
> service restarts than assigning system_r to user accounts and having the
> daemons run as someuser:system_r:foo_t.

Yes, that's something that has been wanted in Fedora for quite some
time.

The real issue with run_init isn't the re-authentication stage, as that
can always be disabled via pam config (and was just a weak form of
confirming user intent, not an authorization mechanism), but rather the
difficulty in transparently interposing it into all situations where
services get started/re-started.  Only Gentoo seemed to have a good
story there.

> This has some issues in policy due to users not always being known in
> the policy (eg., semanage users). I hope Chris or Dan will be able to
> give some suggestions there.

I'm not sure why anyone needs to add users to policy via semanage users
given the base set of generic users and the ability to map Linux users
to them via seusers aka semanage login.

> The kernel patch (forthcoming after this is accepted) so far only
> implements the transition on process transitions. Later on I plan on
> doing a patch to expand role_transition to object classes (this is a
> change needed for policy rbac support to work). I suspect I'll do the
> same for user at that time. The question here is, do we think its worth
> it to do fine grained transitions like we did for range_trans? (I don't).

Offhand, I can't see a use for per-class user transitions, if that is
what you mean.

I don't think per-class role transitions is really the fundamental
obstacle to enabling use of roles on objects - more thought is required
there.  What will be fun there is role/type and user/range validation,
which presently gets to ignore everything that has object_r.

> Index: libsepol/include/sepol/policydb/policydb.h
> ===================================================================
> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
> @@ -156,6 +156,14 @@
> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
> } user_datum_t;
> 
> +typedef struct user_trans {
> +	uint32_t user;		/* current role */
> +	uint32_t type;		/* program executable type */
> +	uint32_t new_user;	/* new role */
> +	struct user_trans *next;
> +} user_trans_t;
> +
> +
> /* Sensitivity attributes */
> typedef struct level_datum {
> 	mls_level_t *level;	/* sensitivity and associated categories */
> @@ -225,6 +233,13 @@
> 	struct role_trans_rule *next;
> } role_trans_rule_t;
> 
> +typedef struct user_trans_rule {
> +	ebitmap_t users;	/* current role */
> +	type_set_t types;	/* program executable type */
> +	uint32_t new_user;	/* new role */
> +	struct user_trans_rule *next;
> +} user_trans_rule_t;
> +
> typedef struct role_allow_rule {
> 	role_set_t roles;	/* current role */
> 	role_set_t new_roles;	/* new roles */
> @@ -348,6 +363,9 @@
> 	char *module_name;
> 
> 	struct avrule_decl *next;
> +
> +	user_trans_rule_t *user_tr_rules;
> +	
> } avrule_decl_t;
> 
> typedef struct avrule_block {
> @@ -470,6 +488,8 @@
> 
> 	ebitmap_t policycaps;
> 
> +	user_trans_t *user_tr;
> +
> 	unsigned policyvers;
> 
> 	unsigned handle_unknown;
> @@ -524,6 +544,9 @@
> extern void role_trans_rule_init(role_trans_rule_t * x);
> extern void role_trans_rule_list_destroy(role_trans_rule_t * x);
> 
> +extern void user_trans_rule_init(user_trans_rule_t * x);
> +extern void user_trans_rule_list_destroy(user_trans_rule_t * x);
> +
> extern void role_datum_init(role_datum_t * x);
> extern void role_datum_destroy(role_datum_t * x);
> extern void role_allow_rule_init(role_allow_rule_t * x);
> @@ -588,10 +611,11 @@
> #define POLICYDB_VERSION_AVTAB		20
> #define POLICYDB_VERSION_RANGETRANS	21
> #define POLICYDB_VERSION_POLCAP		22
> +#define POLICYDB_VERSION_USERTRANS	23
> 
> /* Range of policy versions we understand*/
> #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
> -#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_POLCAP
> +#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_USERTRANS
> 
> /* Module versions and specific changes*/
> #define MOD_POLICYDB_VERSION_BASE	   4
> @@ -600,9 +624,10 @@
> #define MOD_POLICYDB_VERSION_RANGETRANS	   6
> #define MOD_POLICYDB_VERSION_MLS_USERS	   6
> #define MOD_POLICYDB_VERSION_POLCAP	   7
> +#define MOD_POLICYDB_VERSION_USERTRANS	   8
> 
> #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
> -#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_POLCAP
> +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_USERTRANS
> 
> #define POLICYDB_CONFIG_MLS    1
> 
> Index: libsepol/src/policydb.c
> ===================================================================
> --- libsepol/src/policydb.c	(revision 2854)
> +++ libsepol/src/policydb.c	(working copy)
> @@ -105,6 +105,12 @@
> 	 .ocon_num = OCON_NODE6 + 1,
> 	 },
> 	{
> +	 .type = POLICY_KERN,
> +	 .version = POLICYDB_VERSION_USERTRANS,
> +	 .sym_num = SYM_NUM,
> +	 .ocon_num = OCON_NODE6 + 1,
> +	 },
> +	{
> 	 .type = POLICY_BASE,
> 	 .version = MOD_POLICYDB_VERSION_BASE,
> 	 .sym_num = SYM_NUM,
> @@ -129,6 +135,12 @@
> 	 .ocon_num = OCON_NODE6 + 1,
> 	 },
> 	{
> +	 .type = POLICY_BASE,
> +	 .version = MOD_POLICYDB_VERSION_USERTRANS,
> +	 .sym_num = SYM_NUM,
> +	 .ocon_num = OCON_NODE6 + 1,
> +	 },
> +	{
> 	 .type = POLICY_MOD,
> 	 .version = MOD_POLICYDB_VERSION_BASE,
> 	 .sym_num = SYM_NUM,
> @@ -150,7 +162,14 @@
> 	 .type = POLICY_MOD,
> 	 .version = MOD_POLICYDB_VERSION_POLCAP,
> 	 .sym_num = SYM_NUM,
> -	 .ocon_num = 0},
> +	 .ocon_num = 0
> +	 },
> +	{
> +	 .type = POLICY_MOD,
> +	 .version = MOD_POLICYDB_VERSION_USERTRANS,
> +	 .sym_num = SYM_NUM,
> +	 .ocon_num = 0
> +	 },
> };
> 
> #if 0
> @@ -348,6 +367,30 @@
> 	}
> }
> 
> +void user_trans_rule_init(user_trans_rule_t * x)
> +{
> +	memset(x, 0, sizeof(*x));
> +	ebitmap_init(&x->users);
> +	type_set_init(&x->types);
> +}
> +
> +void user_trans_rule_destroy(user_trans_rule_t * x)
> +{
> +	if (x != NULL) {
> +		ebitmap_init(&x->users);
> +		type_set_destroy(&x->types);
> +	}
> +}
> +
> +void user_trans_rule_list_destroy(user_trans_rule_t * x)
> +{
> +	while (x != NULL) {
> +		user_trans_rule_t *next = x->next;
> +		user_trans_rule_destroy(x);
> +		free(x);
> +		x = next;
> +	}
> +}
> void role_allow_rule_init(role_allow_rule_t * x)
> {
> 	memset(x, 0, sizeof(role_allow_rule_t));
> @@ -985,6 +1028,7 @@
> 	unsigned int i;
> 	role_allow_t *ra, *lra = NULL;
> 	role_trans_t *tr, *ltr = NULL;
> +	user_trans_t *ut, *lut = NULL;
> 	range_trans_t *rt, *lrt = NULL;
> 
> 	if (!p)
> @@ -1058,6 +1102,14 @@
> 	if (ltr)
> 		free(ltr);
> 
> +	for (ut = p->user_tr; ut; ut = ut->next) {
> +		if (lut)
> +			free(lut);
> +		lut = ut;
> +	}
> +	if (lut)
> +		free(lut);
> +
> 	for (ra = p->role_allow; ra; ra = ra->next) {
> 		if (lra)
> 			free(lra);
> @@ -1983,6 +2035,40 @@
> 	return 0;
> }
> 
> +int user_trans_read(user_trans_t ** t, struct policy_file *fp)
> +{
> +        unsigned int i;
> +        uint32_t buf[3], nel;
> +        user_trans_t *ut, *lut;
> +        int rc;
> +
> +        rc = next_entry(buf, fp, sizeof(uint32_t));
> +        if (rc < 0)
> +                return -1;
> +        nel = le32_to_cpu(buf[0]);
> +        lut = NULL;
> +        for (i = 0; i < nel; i++) {
> +                ut = calloc(1, sizeof(struct user_trans));
> +                if (!ut) {
> +                        return -1;
> +                }
> +                if (lut) {
> +                        lut->next = ut;
> +                } else {
> +                        *t = ut;
> +                }
> +                rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
> +                if (rc < 0)
> +                        return -1;
> +                ut->user = le32_to_cpu(buf[0]);
> +                ut->type = le32_to_cpu(buf[1]);
> +                ut->new_user = le32_to_cpu(buf[2]);
> +                lut = ut;
> +        }
> +        return 0;
> +}
> +
> +
> int role_allow_read(role_allow_t ** r, struct policy_file *fp)
> {
> 	unsigned int i;
> @@ -2679,6 +2765,48 @@
> 	return 0;
> }
> 
> +static int user_trans_rule_read(user_trans_rule_t ** u, struct 
> policy_file *fp)
> +{
> +        uint32_t buf[1], nel;
> +        unsigned int i;
> +        user_trans_rule_t *ut, *lut;
> +        int rc;
> +
> +        rc = next_entry(buf, fp, sizeof(uint32_t));
> +        if (rc < 0)
> +                return -1;
> +        nel = le32_to_cpu(buf[0]);
> +        lut = NULL;
> +        for (i = 0; i < nel; i++) {
> +                ut = malloc(sizeof(user_trans_rule_t));
> +                if (!ut) {
> +                        return -1;
> +                }
> +                user_trans_rule_init(ut);
> +
> +                if (lut) {
> +                        lut->next = ut;
> +                } else {
> +                        *u = ut;
> +                }
> +
> +                if (ebitmap_read(&ut->users, fp))
> +                        return -1;
> +
> +                if (type_set_read(&ut->types, fp))
> +                        return -1;
> +
> +                rc = next_entry(buf, fp, sizeof(uint32_t));
> +                if (rc < 0)
> +                        return -1;
> +                ut->new_user = le32_to_cpu(buf[0]);
> +                lut = ut;
> +        }
> +
> +        return 0;
> +}
> +
> +
> static int role_allow_rule_read(role_allow_rule_t ** r, struct 
> policy_file *fp)
> {
> 	unsigned int i;
> @@ -2805,9 +2933,14 @@
> 	if (cond_read_list(p, &decl->cond_list, fp) == -1 ||
> 	    avrule_read_list(p, &decl->avrules, fp) == -1 ||
> 	    role_trans_rule_read(&decl->role_tr_rules, fp) == -1 ||
> -	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1) {
> +	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1)
> +	    {
> 		return -1;
> 	}
> +	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
> +		if (user_trans_rule_read(&decl->user_tr_rules, fp))
> +			return -1;
> +	}
> 	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
> 	    range_trans_rule_read(&decl->range_tr_rules, fp) == -1) {
> 		return -1;
> @@ -3179,6 +3312,10 @@
> 				goto bad;
> 		if (role_trans_read(&p->role_tr, fp))
> 			goto bad;
> +		if (r_policyvers >= POLICYDB_VERSION_USERTRANS) {
> +			if (user_trans_read(&p->user_tr, fp))
> +				goto bad;
> +		}
> 		if (role_allow_read(&p->role_allow, fp))
> 			goto bad;
> 	} else {
> Index: libsepol/src/expand.c
> ===================================================================
> --- libsepol/src/expand.c	(revision 2854)
> +++ libsepol/src/expand.c	(working copy)
> @@ -1060,6 +1060,80 @@
> 	return 0;
> }
> 
> +static int copy_user_trans(expand_state_t * state, user_trans_rule_t * 
> rules)
> +{
> +	unsigned int i, j;
> +	user_trans_t *n, *l, *cur_trans;
> +	user_trans_rule_t *cur;
> +	ebitmap_t types;
> +	ebitmap_node_t *rnode, *tnode;
> +
> +	/* start at the end of the list */
> +	for (l = state->out->user_tr; l && l->next; l = l->next) ;
> +
> +	cur = rules;
> +	while (cur) {
> +		ebitmap_init(&types);
> +
> +		if (expand_convert_type_set
> +		    (state->out, state->typemap, &cur->types, &types, 1)) {
> +			ERR(state->handle, "Out of memory!");
> +			return -1;
> +		}
> +		ebitmap_for_each_bit(&cur->users, rnode, i) {
> +			if (!ebitmap_node_get_bit(rnode, i))
> +				continue;
> +			ebitmap_for_each_bit(&types, tnode, j) {
> +				if (!ebitmap_node_get_bit(tnode, j))
> +					continue;
> +
> +				cur_trans = state->out->user_tr;
> +				while (cur_trans) {
> +					if ((cur_trans->user == i + 1) &&
> +					    (cur_trans->type == j + 1)) {
> +						if (cur_trans->new_user ==
> +						    cur->new_user) {
> +							break;
> +						} else {
> +							ERR(state->handle,
> +							    "Conflicting user trans rule %s %s : %s",
> +							    state->out->p_user_val_to_name[i],
> +							    state->out->p_type_val_to_name[j],
> +							    state->out->p_user_val_to_name[cur->new_user - 1]);
> +							return -1;
> +						}
> +					}
> +					cur_trans = cur_trans->next;
> +				}
> +				if (cur_trans)
> +					continue;
> +
> +				n = (user_trans_t *)
> +				    malloc(sizeof(user_trans_t));
> +				if (!n) {
> +					ERR(state->handle, "Out of memory!");
> +					return -1;
> +				}
> +				memset(n, 0, sizeof(user_trans_t));
> +				n->user = i + 1;
> +				n->type = j + 1;
> +				n->new_user = cur->new_user;
> +				if (l) {
> +					l->next = n;
> +				} else {
> +					state->out->user_tr = n;
> +				}
> +				l = n;
> +			}
> +		}
> +
> +		ebitmap_destroy(&types);
> +
> +		cur = cur->next;
> +	}
> +	return 0;
> +}
> +
> static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t 
> tclass,
> 			      mls_semantic_range_t * trange,
> 			      expand_state_t * state)
> @@ -2163,6 +2237,9 @@
> 			goto cleanup;
> 		}
> 
> +		if (copy_user_trans(state, decl->user_tr_rules))
> +			goto cleanup;
> +
> 		/* expand the range transition rules */
> 		if (expand_range_trans(state, decl->range_tr_rules))
> 			goto cleanup;
> Index: libsepol/src/write.c
> ===================================================================
> --- libsepol/src/write.c	(revision 2854)
> +++ libsepol/src/write.c	(working copy)
> @@ -487,6 +487,31 @@
> 	return POLICYDB_SUCCESS;
> }
> 
> +static int user_trans_write(user_trans_t * u, struct policy_file *fp)
> +{
> +	user_trans_t *tr;
> +	uint32_t buf[3];
> +	size_t nel, items;
> +
> +	nel = 0;
> +	for (tr = u; tr; tr = tr->next)
> +		nel++;
> +	buf[0] = cpu_to_le32(nel);
> +	items = put_entry(buf, sizeof(uint32_t), 1, fp);
> +	if (items != 1)
> +		return POLICYDB_ERROR;
> +	for (tr = u; tr; tr = tr->next) {
> +		buf[0] = cpu_to_le32(tr->user);
> +		buf[1] = cpu_to_le32(tr->type);
> +		buf[2] = cpu_to_le32(tr->new_user);
> +		items = put_entry(buf, sizeof(uint32_t), 3, fp);
> +		if (items != 3)
> +			return POLICYDB_ERROR;
> +	}
> +
> +	return POLICYDB_SUCCESS;
> +}
> +
> static int role_allow_write(role_allow_t * r, struct policy_file *fp)
> {
> 	role_allow_t *ra;
> @@ -1325,6 +1350,32 @@
> 	return POLICYDB_SUCCESS;
> }
> 
> +static int user_trans_rule_write(user_trans_rule_t * t, struct 
> policy_file *fp)
> +{
> +	int nel = 0;
> +	size_t items;
> +	uint32_t buf[1];
> +	user_trans_rule_t *tr;
> +
> +	for (tr = t; tr; tr = tr->next)
> +		nel++;
> +	buf[0] = cpu_to_le32(nel);
> +	items = put_entry(buf, sizeof(uint32_t), 1, fp);
> +	if (items != 1)
> +		return POLICYDB_ERROR;
> +	for (tr = t; tr; tr = tr->next) {
> +		if (ebitmap_write(&tr->users, fp))
> +			return POLICYDB_ERROR;
> +		if (type_set_write(&tr->types, fp))
> +			return POLICYDB_ERROR;
> +		buf[0] = cpu_to_le32(tr->new_user);
> +		items = put_entry(buf, sizeof(uint32_t), 1, fp);
> +		if (items != 1)
> +			return POLICYDB_ERROR;
> +	}
> +	return POLICYDB_SUCCESS;
> +}
> +
> static int role_allow_rule_write(role_allow_rule_t * r, struct 
> policy_file *fp)
> {
> 	int nel = 0;
> @@ -1414,6 +1465,10 @@
> 	    role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
> 		return POLICYDB_ERROR;
> 	}
> +	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
> +		if (user_trans_rule_write(decl->user_tr_rules, fp))	
> +			return POLICYDB_ERROR;
> +	}
> 	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
> 	    range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
> 		return POLICYDB_ERROR;
> @@ -1642,6 +1697,10 @@
> 		}
> 		if (role_trans_write(p->role_tr, fp))
> 			return POLICYDB_ERROR;
> +		if (p->policyvers >= POLICYDB_VERSION_USERTRANS) {
> +			if (user_trans_write(p->user_tr, fp))
> +				return POLICYDB_ERROR;
> +		}
> 		if (role_allow_write(p->role_allow, fp))
> 			return POLICYDB_ERROR;
> 	} else {
> Index: libsepol/src/link.c
> ===================================================================
> --- libsepol/src/link.c	(revision 2854)
> +++ libsepol/src/link.c	(working copy)
> @@ -848,6 +848,34 @@
> 	return -1;
> }
> 
> +static int user_bitmap_or_convert(ebitmap_t * users, ebitmap_t * dst,
> +			       policy_module_t * mod, link_state_t * state)
> +{
> +	unsigned int i;
> +	ebitmap_t tmp;
> +	ebitmap_node_t *rnode;
> +
> +	ebitmap_init(&tmp);
> +	ebitmap_for_each_bit(users, rnode, i) {
> +		if (ebitmap_node_get_bit(rnode, i)) {
> +			assert(mod->map[SYM_USERS][i]);
> +			if (ebitmap_set_bit
> +			    (&tmp, mod->map[SYM_USERS][i] - 1, 1)) {
> +				goto cleanup;
> +			}
> +		}
> +	}
> +	if (ebitmap_union(dst, &tmp)) {
> +		goto cleanup;
> +	}
> +	ebitmap_destroy(&tmp);
> +	return 0;
> +      cleanup:
> +	ERR(state->handle, "Out of memory!");
> +	ebitmap_destroy(&tmp);
> +	return -1;
> +}
> +
> static int mls_level_convert(mls_semantic_level_t * src, 
> mls_semantic_level_t * dst,
> 			     policy_module_t * mod, link_state_t * state)
> {
> @@ -1004,13 +1032,22 @@
> 	link_state_t *state = (link_state_t *) data;
> 	policy_module_t *mod = state->cur;
> 	symtab_t *usertab;
> +	scope_datum_t *scope;
> 
> 	user = (user_datum_t *) datum;
> 
> +	scope = hashtab_search(state->cur->policy->p_users_scope.table, key);
> +	assert(scope);
> +	if (scope->scope == SCOPE_REQ) {
> +		//this is required user, no role or mls data
> +		return 0;
> +	}
> +
> 	if (state->dest_decl == NULL)
> 		usertab = &state->base->p_users;
> -	else
> +	else {
> 		usertab = &state->dest_decl->p_users;
> +	}
> 
> 	new_user = hashtab_search(usertab->table, id);
> 	assert(new_user != NULL);
> @@ -1173,6 +1210,49 @@
> 	return -1;
> }
> 
> +static int copy_user_trans_list(user_trans_rule_t * list,
> +                                user_trans_rule_t ** dst,
> +                                policy_module_t * module, link_state_t 
> * state)
> +{
> +        user_trans_rule_t *cur, *new_rule = NULL, *tail;
> +
> +        cur = list;
> +        tail = *dst;
> +        while (tail && tail->next) {
> +                tail = tail->next;
> +        }
> +        while (cur) {
> +                if ((new_rule =
> +                     (user_trans_rule_t *) 
> malloc(sizeof(user_trans_rule_t))) ==
> +                    NULL) {
> +                        goto cleanup;
> +                }
> +                user_trans_rule_init(new_rule);
> +
> +                if (user_bitmap_or_convert(&cur->users, 
> &new_rule->users, module, state))
> +			goto cleanup;
> +		if (type_set_or_convert(&cur->types, &new_rule->types, module, state)) {
> +                        goto cleanup;
> +                }
> +
> +                new_rule->new_user = 
> module->map[SYM_USERS][cur->new_user - 1];
> +
> +                if (*dst == NULL) {
> +                        *dst = new_rule;
> +                } else {
> +                        tail->next = new_rule;
> +                }
> +                tail = new_rule;
> +                cur = cur->next;
> +        }
> +        return 0;
> +      cleanup:
> +        ERR(state->handle, "Out of memory!");
> +        user_trans_rule_list_destroy(new_rule);
> +        return -1;
> +}
> +
> +
> static int copy_role_allow_list(role_allow_rule_t * list,
> 				role_allow_rule_t ** dst,
> 				policy_module_t * module, link_state_t * state)
> @@ -1446,6 +1526,10 @@
> 		return -1;
> 	}
> 
> +	if (copy_user_trans_list(src_decl->user_tr_rules, 
> &dest_decl->user_tr_rules,
> +				 module, state))
> +		return -1;
> +
> 	if (copy_range_trans_list(src_decl->range_tr_rules,
> 				  &dest_decl->range_tr_rules, module, state))
> 		return -1;
> Index: checkpolicy/test/dismod.c
> ===================================================================
> --- checkpolicy/test/dismod.c	(revision 2854)
> +++ checkpolicy/test/dismod.c	(working copy)
> @@ -354,6 +354,21 @@
> 	return 0;
> }
> 
> +int display_user_set(ebitmap_t *u, policydb_t *p, FILE *fp)
> +{
> +	ebitmap_node_t *node;
> +	int i;
> +
> +	fprintf(fp, " { ");
> +	ebitmap_for_each_bit(u, node, i) {
> +		if (ebitmap_node_get_bit(node, i)) {
> +			display_id(p, fp, SYM_USERS, i, "");
> +		}
> +	}
> +	fprintf(fp, " } ");
> +	return 0;
> +}
> +
> int display_bools(policydb_t * p, FILE * fp)
> {
> 	int i;
> @@ -461,7 +476,18 @@
> 		fprintf(fp, "\n");
> 	}
> }
> +void display_user_trans(user_trans_rule_t * tr, policydb_t * p, FILE * fp)
> 
> +{
> +	for (; tr; tr = tr->next) {
> +		fprintf(fp, "user transition ");
> +		display_user_set(&tr->users, p, fp);
> +		display_type_set(&tr->types, 0, p, fp);
> +		display_id(p, fp, SYM_USERS, tr->new_user - 1, " :");
> +		fprintf(fp, "\n");
> +	}
> +}
> +
> void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp)
> {
> 	for (; ra; ra = ra->next) {
> @@ -641,6 +667,10 @@
> 			}
> 			break;
> 		}
> +	case 7:{
> +			display_user_trans(decl->user_tr_rules, policy, out_fp);
> +			break;
> +		}
> 	default:{
> 			assert(0);
> 		}
> @@ -806,6 +836,7 @@
> 	printf("c)  Display policy capabilities\n");
> 	printf("l)  Link in a module\n");
> 	printf("u)  Display the unknown handling setting\n");
> +	printf("U)  Display user transitions\n");
> 	printf("\n");
> 	printf("f)  set output file\n");
> 	printf("m)  display menu\n");
> @@ -918,9 +949,11 @@
> 			display_policycaps(&policydb, out_fp);
> 			break;
> 		case 'u':
> -		case 'U':
> 			display_handle_unknown(&policydb, out_fp);
> 			break;
> +		case 'U':
> +			display_avblock(7, 0, &policydb, out_fp);
> +			break;
> 		case 'f':
> 			printf
> 			    ("\nFilename for output (<CR> for screen output): ");
> Index: checkpolicy/test/dispol.c
> ===================================================================
> --- checkpolicy/test/dispol.c	(revision 2854)
> +++ checkpolicy/test/dispol.c	(working copy)
> @@ -299,6 +299,18 @@
> 	return 0;
> }
> 
> +static void display_user_transitions(policydb_t *p, FILE *fp)
> +{
> +	user_trans_t *cur;
> +	for (cur = p->user_tr; cur; cur = cur->next) {
> +		fprintf(fp, "user_transition ");
> +		fprintf(fp, "%s %s %s;\n",
> +			p->p_user_val_to_name[cur->user - 1],
> +			p->p_type_val_to_name[cur->type - 1],
> +			p->p_user_val_to_name[cur->new_user - 1]);
> +	}
> +}
> +
> static void display_policycaps(policydb_t * p, FILE * fp)
> {
> 	ebitmap_node_t *node;
> @@ -332,6 +344,7 @@
> 	printf("\n");
> 	printf("c)  display policy capabilities\n");
> 	printf("u)  display unknown handling setting\n");
> +	printf("U)  display user transitions\n");
> 	printf("f)  set output file\n");
> 	printf("m)  display menu\n");
> 	printf("q)  quit\n");
> @@ -448,9 +461,11 @@
> 			display_policycaps(&policydb, out_fp);
> 			break;
> 		case 'u':
> -		case 'U':
> 			display_handle_unknown(&policydb, out_fp);
> 			break;
> +		case 'U':
> +			display_user_transitions(&policydb, out_fp);
> +			break;
> 		case 'f':
> 			printf
> 			    ("\nFilename for output (<CR> for screen output): ");
> Index: checkpolicy/test/Makefile
> ===================================================================
> --- checkpolicy/test/Makefile	(revision 2854)
> +++ checkpolicy/test/Makefile	(working copy)
> @@ -6,7 +6,7 @@
> LIBDIR=$(PREFIX)/lib
> INCLUDEDIR ?= $(PREFIX)/include
> 
> -CFLAGS ?= -g -Wall -O2 -pipe
> +CFLAGS ?= -g3 -gdwarf-2 -Wall -O0 -pipe
> override CFLAGS += -I$(INCLUDEDIR)
> 
> LDLIBS=-lfl -lsepol -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR)
> Index: checkpolicy/policy_define.c
> ===================================================================
> --- checkpolicy/policy_define.c	(revision 2854)
> +++ checkpolicy/policy_define.c	(working copy)
> @@ -2020,6 +2020,76 @@
> 	return -1;
> }
> 
> +int define_user_trans(void)
> +{
> +        char *id;
> +        user_datum_t *user, *u;
> +	ebitmap_t users;
> +        type_set_t types;
> +        struct user_trans_rule *rule = NULL;
> +        int add = 1;
> +
> +        if (pass == 1) {
> +                while ((id = queue_remove(id_queue)))
> +                        free(id);
> +                while ((id = queue_remove(id_queue)))
> +                        free(id);
> +                id = queue_remove(id_queue);
> +                free(id);
> +                return 0;
> +        }
> +
> +        ebitmap_init(&users);
> +        type_set_init(&types);
> +
> +	while ((id = queue_remove(id_queue))) {
> +		u = hashtab_search(policydbp->p_users.table, id);
> +		if (!u) {
> +			yyerror2("unknown user %s", id);
> +			free(id);
> +			return -1;
> +		}
> +		if (ebitmap_set_bit(&users, u->s.value - 1, TRUE))
> +			return -1;
> +	}
> +	while ((id = queue_remove(id_queue))) {
> +		if (set_types(&types, id, &add, 0))
> +			return -1;
> +	}
> +	id = (char *)queue_remove(id_queue);
> +	if (!id) {
> +		yyerror("no new user in transition definition?");
> +		goto bad;
> +	}
> +	if (!is_id_in_scope(SYM_USERS, id)) {
> +		yyerror2("user %s is not within scope", id);
> +		free(id);
> +		goto bad;
> +	}
> +	user = hashtab_search(policydbp->p_users.table, id);
> +	if (!user) {
> +		yyerror2("unknown user %s used in transition definition", id);
> +		goto bad;
> +	}
> +	rule = malloc(sizeof(struct user_trans_rule));
> +	if (!rule) {
> +		yyerror("out of memory");
> +		return -1;
> +	}
> +	memset(rule, 0, sizeof(struct user_trans_rule));
> +	rule->users = users;
> +	rule->types = types;
> +	rule->new_user = user->s.value;
> +
> +	append_user_trans(rule);
> +
> +	return 0;
> +
> +      bad:
> +	return -1;
> +}
> +
> +
> int define_role_allow(void)
> {
> 	char *id;
> Index: checkpolicy/policy_scan.l
> ===================================================================
> --- checkpolicy/policy_scan.l	(revision 2854)
> +++ checkpolicy/policy_scan.l	(working copy)
> @@ -102,6 +102,8 @@
> type_change			{ return(TYPE_CHANGE); }
> ROLE_TRANSITION |
> role_transition			{ return(ROLE_TRANSITION); }
> +USER_TRANSITION |
> +user_transition			{ return(USER_TRANSITION); }
> RANGE_TRANSITION |
> range_transition		{ return(RANGE_TRANSITION); }
> SENSITIVITY |
> Index: checkpolicy/policy_define.h
> ===================================================================
> --- checkpolicy/policy_define.h	(revision 2854)
> +++ checkpolicy/policy_define.h	(working copy)
> @@ -42,6 +42,7 @@
> int define_role_allow(void);
> int define_role_trans(void);
> int define_role_types(void);
> +int define_user_trans(void);
> int define_sens(void);
> int define_te_avtab(int which);
> int define_typealias(void);
> Index: checkpolicy/module_compiler.c
> ===================================================================
> --- checkpolicy/module_compiler.c	(revision 2854)
> +++ checkpolicy/module_compiler.c	(working copy)
> @@ -1214,6 +1214,17 @@
> 	decl->role_tr_rules = role_tr_rules;
> }
> 
> +void append_user_trans(user_trans_rule_t * user_tr_rules)
> +{
> +	avrule_decl_t *decl = stack_top->decl;
> +
> +	/* role transitions are not allowed within conditionals */
> +	assert(stack_top->type == 1);
> +
> +	user_tr_rules->next = decl->user_tr_rules;
> +	decl->user_tr_rules = user_tr_rules;
> +}
> +
> /* this doesn't actually append, but really prepends it */
> void append_role_allow(role_allow_rule_t * role_allow_rules)
> {
> Index: checkpolicy/policy_parse.y
> ===================================================================
> --- checkpolicy/policy_parse.y	(revision 2854)
> +++ checkpolicy/policy_parse.y	(working copy)
> @@ -103,6 +103,7 @@
> %token TYPE_MEMBER
> %token TYPE_CHANGE
> %token ROLE_TRANSITION
> +%token USER_TRANSITION
> %token RANGE_TRANSITION
> %token SENSITIVITY
> %token DOMINANCE
> @@ -261,6 +262,7 @@
>                          | transition_def
>                          | range_trans_def
>                          | te_avtab_def
> +			| user_trans_def
> 			;
> attribute_def           : ATTRIBUTE identifier ';'
>                          { if (define_attrib()) return -1;}
> @@ -411,6 +413,9 @@
> role_trans_def		: ROLE_TRANSITION names names identifier ';'
> 			{if (define_role_trans()) return -1; }
> 			;
> +user_trans_def		: USER_TRANSITION names names identifier ';'
> +			{ if (define_user_trans()) return -1; }
> +			;
> role_allow_def		: ALLOW names names ';'
> 			{if (define_role_allow()) return -1; }
> 			;
> Index: checkpolicy/module_compiler.h
> ===================================================================
> --- checkpolicy/module_compiler.h	(revision 2854)
> +++ checkpolicy/module_compiler.h	(working copy)
> @@ -80,6 +80,7 @@
> void append_role_trans(role_trans_rule_t * role_tr_rules);
> void append_role_allow(role_allow_rule_t * role_allow_rules);
> void append_range_trans(range_trans_rule_t * range_tr_rules);
> +void append_user_trans(user_trans_rule_t * user_tr_rules);
> 
> /* Create a new optional block and add it to the global policy.
>   * During the second pass resolve the block's requirements.  Return 0
> 
> 
-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 20:15 ` Stephen Smalley
@ 2008-03-24 20:27   ` Joshua Brindle
  2008-03-24 20:36     ` Stephen Smalley
  2008-03-24 20:30   ` Joshua Brindle
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 27+ messages in thread
From: Joshua Brindle @ 2008-03-24 20:27 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: SE Linux, Caleb Case, jmowery

Stephen Smalley wrote:
> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>   
>> This implements user_transition in the toolchain. It should help on
>> distro's like Ubuntu that can't use run_init due to the user not knowing
>> the root password. It also seems like a more eloquent way to handle
>> service restarts than assigning system_r to user accounts and having the
>> daemons run as someuser:system_r:foo_t.
>>     
>
> Yes, that's something that has been wanted in Fedora for quite some
> time.
>
> The real issue with run_init isn't the re-authentication stage, as that
> can always be disabled via pam config (and was just a weak form of
> confirming user intent, not an authorization mechanism), but rather the
> difficulty in transparently interposing it into all situations where
> services get started/re-started.  Only Gentoo seemed to have a good
> story there.
>
>   
>> This has some issues in policy due to users not always being known in
>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>> give some suggestions there.
>>     
>
> I'm not sure why anyone needs to add users to policy via semanage users
> given the base set of generic users and the ability to map Linux users
> to them via seusers aka semanage login.
>
>   
>> The kernel patch (forthcoming after this is accepted) so far only
>> implements the transition on process transitions. Later on I plan on
>> doing a patch to expand role_transition to object classes (this is a
>> change needed for policy rbac support to work). I suspect I'll do the
>> same for user at that time. The question here is, do we think its worth
>> it to do fine grained transitions like we did for range_trans? (I don't).
>>     
>
> Offhand, I can't see a use for per-class user transitions, if that is
> what you mean.
>
> I don't think per-class role transitions is really the fundamental
> obstacle to enabling use of roles on objects - more thought is required
> there.  What will be fun there is role/type and user/range validation,
> which presently gets to ignore everything that has object_r.
>   

Ah, another thing. While going through the policyrep implementation the 
question of object_r came up. My thought is to start adding object_r 
magic into the toolchain (adding all types, etc) and eventually purge 
object_r from the kernel. at least one magic instance of object_r will 
be removed by object role_transitions, the others are really short 
circuits in the security server that can be removed after sufficient 
support is in the toolchain. What are your thoughts on that (for future 
reference)?


--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 20:15 ` Stephen Smalley
  2008-03-24 20:27   ` Joshua Brindle
@ 2008-03-24 20:30   ` Joshua Brindle
  2008-03-25  4:25   ` Russell Coker
  2008-03-26  8:40   ` Daniel J Walsh
  3 siblings, 0 replies; 27+ messages in thread
From: Joshua Brindle @ 2008-03-24 20:30 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: SE Linux, Caleb Case, Eric Paris

Stephen Smalley wrote:
> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>   
>> This implements user_transition in the toolchain. It should help on
>> distro's like Ubuntu that can't use run_init due to the user not knowing
>> the root password. It also seems like a more eloquent way to handle
>> service restarts than assigning system_r to user accounts and having the
>> daemons run as someuser:system_r:foo_t.
>>     
>
> Yes, that's something that has been wanted in Fedora for quite some
> time.
>
> The real issue with run_init isn't the re-authentication stage, as that
> can always be disabled via pam config (and was just a weak form of
> confirming user intent, not an authorization mechanism), but rather the
> difficulty in transparently interposing it into all situations where
> services get started/re-started.  Only Gentoo seemed to have a good
> story there.
>
>   

Do you have any comments on the patch? (Other than it needing to be 
rebased against permissive types?)

Also, if permissive types haven't hit akpm yet maybe we can merge the 
policy changes for both of these into 23?

I'm currently putting the user_transitions directly below the 
role_transitions in the on-disk format. I can change that if its easier 
but I doubt it matters, anything that reads policy will bail as soon as 
it doesn't understand that version.

>> This has some issues in policy due to users not always being known in
>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>> give some suggestions there.
>>     
>
> I'm not sure why anyone needs to add users to policy via semanage users
> given the base set of generic users and the ability to map Linux users
> to them via seusers aka semanage login.
>
>   
>> The kernel patch (forthcoming after this is accepted) so far only
>> implements the transition on process transitions. Later on I plan on
>> doing a patch to expand role_transition to object classes (this is a
>> change needed for policy rbac support to work). I suspect I'll do the
>> same for user at that time. The question here is, do we think its worth
>> it to do fine grained transitions like we did for range_trans? (I don't).
>>     
>
> Offhand, I can't see a use for per-class user transitions, if that is
> what you mean.
>
> I don't think per-class role transitions is really the fundamental
> obstacle to enabling use of roles on objects - more thought is required
> there.  What will be fun there is role/type and user/range validation,
> which presently gets to ignore everything that has object_r.
>
>   
>> Index: libsepol/include/sepol/policydb/policydb.h
>> ===================================================================
>> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
>> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
>> @@ -156,6 +156,14 @@
>> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
>> } user_datum_t;
>>
>> +typedef struct user_trans {
>> +	uint32_t user;		/* current role */
>> +	uint32_t type;		/* program executable type */
>> +	uint32_t new_user;	/* new role */
>> +	struct user_trans *next;
>> +} user_trans_t;
>> +
>> +
>> /* Sensitivity attributes */
>> typedef struct level_datum {
>> 	mls_level_t *level;	/* sensitivity and associated categories */
>> @@ -225,6 +233,13 @@
>> 	struct role_trans_rule *next;
>> } role_trans_rule_t;
>>
>> +typedef struct user_trans_rule {
>> +	ebitmap_t users;	/* current role */
>> +	type_set_t types;	/* program executable type */
>> +	uint32_t new_user;	/* new role */
>> +	struct user_trans_rule *next;
>> +} user_trans_rule_t;
>> +
>> typedef struct role_allow_rule {
>> 	role_set_t roles;	/* current role */
>> 	role_set_t new_roles;	/* new roles */
>> @@ -348,6 +363,9 @@
>> 	char *module_name;
>>
>> 	struct avrule_decl *next;
>> +
>> +	user_trans_rule_t *user_tr_rules;
>> +	
>> } avrule_decl_t;
>>
>> typedef struct avrule_block {
>> @@ -470,6 +488,8 @@
>>
>> 	ebitmap_t policycaps;
>>
>> +	user_trans_t *user_tr;
>> +
>> 	unsigned policyvers;
>>
>> 	unsigned handle_unknown;
>> @@ -524,6 +544,9 @@
>> extern void role_trans_rule_init(role_trans_rule_t * x);
>> extern void role_trans_rule_list_destroy(role_trans_rule_t * x);
>>
>> +extern void user_trans_rule_init(user_trans_rule_t * x);
>> +extern void user_trans_rule_list_destroy(user_trans_rule_t * x);
>> +
>> extern void role_datum_init(role_datum_t * x);
>> extern void role_datum_destroy(role_datum_t * x);
>> extern void role_allow_rule_init(role_allow_rule_t * x);
>> @@ -588,10 +611,11 @@
>> #define POLICYDB_VERSION_AVTAB		20
>> #define POLICYDB_VERSION_RANGETRANS	21
>> #define POLICYDB_VERSION_POLCAP		22
>> +#define POLICYDB_VERSION_USERTRANS	23
>>
>> /* Range of policy versions we understand*/
>> #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
>> -#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_POLCAP
>> +#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_USERTRANS
>>
>> /* Module versions and specific changes*/
>> #define MOD_POLICYDB_VERSION_BASE	   4
>> @@ -600,9 +624,10 @@
>> #define MOD_POLICYDB_VERSION_RANGETRANS	   6
>> #define MOD_POLICYDB_VERSION_MLS_USERS	   6
>> #define MOD_POLICYDB_VERSION_POLCAP	   7
>> +#define MOD_POLICYDB_VERSION_USERTRANS	   8
>>
>> #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
>> -#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_POLCAP
>> +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_USERTRANS
>>
>> #define POLICYDB_CONFIG_MLS    1
>>
>> Index: libsepol/src/policydb.c
>> ===================================================================
>> --- libsepol/src/policydb.c	(revision 2854)
>> +++ libsepol/src/policydb.c	(working copy)
>> @@ -105,6 +105,12 @@
>> 	 .ocon_num = OCON_NODE6 + 1,
>> 	 },
>> 	{
>> +	 .type = POLICY_KERN,
>> +	 .version = POLICYDB_VERSION_USERTRANS,
>> +	 .sym_num = SYM_NUM,
>> +	 .ocon_num = OCON_NODE6 + 1,
>> +	 },
>> +	{
>> 	 .type = POLICY_BASE,
>> 	 .version = MOD_POLICYDB_VERSION_BASE,
>> 	 .sym_num = SYM_NUM,
>> @@ -129,6 +135,12 @@
>> 	 .ocon_num = OCON_NODE6 + 1,
>> 	 },
>> 	{
>> +	 .type = POLICY_BASE,
>> +	 .version = MOD_POLICYDB_VERSION_USERTRANS,
>> +	 .sym_num = SYM_NUM,
>> +	 .ocon_num = OCON_NODE6 + 1,
>> +	 },
>> +	{
>> 	 .type = POLICY_MOD,
>> 	 .version = MOD_POLICYDB_VERSION_BASE,
>> 	 .sym_num = SYM_NUM,
>> @@ -150,7 +162,14 @@
>> 	 .type = POLICY_MOD,
>> 	 .version = MOD_POLICYDB_VERSION_POLCAP,
>> 	 .sym_num = SYM_NUM,
>> -	 .ocon_num = 0},
>> +	 .ocon_num = 0
>> +	 },
>> +	{
>> +	 .type = POLICY_MOD,
>> +	 .version = MOD_POLICYDB_VERSION_USERTRANS,
>> +	 .sym_num = SYM_NUM,
>> +	 .ocon_num = 0
>> +	 },
>> };
>>
>> #if 0
>> @@ -348,6 +367,30 @@
>> 	}
>> }
>>
>> +void user_trans_rule_init(user_trans_rule_t * x)
>> +{
>> +	memset(x, 0, sizeof(*x));
>> +	ebitmap_init(&x->users);
>> +	type_set_init(&x->types);
>> +}
>> +
>> +void user_trans_rule_destroy(user_trans_rule_t * x)
>> +{
>> +	if (x != NULL) {
>> +		ebitmap_init(&x->users);
>> +		type_set_destroy(&x->types);
>> +	}
>> +}
>> +
>> +void user_trans_rule_list_destroy(user_trans_rule_t * x)
>> +{
>> +	while (x != NULL) {
>> +		user_trans_rule_t *next = x->next;
>> +		user_trans_rule_destroy(x);
>> +		free(x);
>> +		x = next;
>> +	}
>> +}
>> void role_allow_rule_init(role_allow_rule_t * x)
>> {
>> 	memset(x, 0, sizeof(role_allow_rule_t));
>> @@ -985,6 +1028,7 @@
>> 	unsigned int i;
>> 	role_allow_t *ra, *lra = NULL;
>> 	role_trans_t *tr, *ltr = NULL;
>> +	user_trans_t *ut, *lut = NULL;
>> 	range_trans_t *rt, *lrt = NULL;
>>
>> 	if (!p)
>> @@ -1058,6 +1102,14 @@
>> 	if (ltr)
>> 		free(ltr);
>>
>> +	for (ut = p->user_tr; ut; ut = ut->next) {
>> +		if (lut)
>> +			free(lut);
>> +		lut = ut;
>> +	}
>> +	if (lut)
>> +		free(lut);
>> +
>> 	for (ra = p->role_allow; ra; ra = ra->next) {
>> 		if (lra)
>> 			free(lra);
>> @@ -1983,6 +2035,40 @@
>> 	return 0;
>> }
>>
>> +int user_trans_read(user_trans_t ** t, struct policy_file *fp)
>> +{
>> +        unsigned int i;
>> +        uint32_t buf[3], nel;
>> +        user_trans_t *ut, *lut;
>> +        int rc;
>> +
>> +        rc = next_entry(buf, fp, sizeof(uint32_t));
>> +        if (rc < 0)
>> +                return -1;
>> +        nel = le32_to_cpu(buf[0]);
>> +        lut = NULL;
>> +        for (i = 0; i < nel; i++) {
>> +                ut = calloc(1, sizeof(struct user_trans));
>> +                if (!ut) {
>> +                        return -1;
>> +                }
>> +                if (lut) {
>> +                        lut->next = ut;
>> +                } else {
>> +                        *t = ut;
>> +                }
>> +                rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
>> +                if (rc < 0)
>> +                        return -1;
>> +                ut->user = le32_to_cpu(buf[0]);
>> +                ut->type = le32_to_cpu(buf[1]);
>> +                ut->new_user = le32_to_cpu(buf[2]);
>> +                lut = ut;
>> +        }
>> +        return 0;
>> +}
>> +
>> +
>> int role_allow_read(role_allow_t ** r, struct policy_file *fp)
>> {
>> 	unsigned int i;
>> @@ -2679,6 +2765,48 @@
>> 	return 0;
>> }
>>
>> +static int user_trans_rule_read(user_trans_rule_t ** u, struct 
>> policy_file *fp)
>> +{
>> +        uint32_t buf[1], nel;
>> +        unsigned int i;
>> +        user_trans_rule_t *ut, *lut;
>> +        int rc;
>> +
>> +        rc = next_entry(buf, fp, sizeof(uint32_t));
>> +        if (rc < 0)
>> +                return -1;
>> +        nel = le32_to_cpu(buf[0]);
>> +        lut = NULL;
>> +        for (i = 0; i < nel; i++) {
>> +                ut = malloc(sizeof(user_trans_rule_t));
>> +                if (!ut) {
>> +                        return -1;
>> +                }
>> +                user_trans_rule_init(ut);
>> +
>> +                if (lut) {
>> +                        lut->next = ut;
>> +                } else {
>> +                        *u = ut;
>> +                }
>> +
>> +                if (ebitmap_read(&ut->users, fp))
>> +                        return -1;
>> +
>> +                if (type_set_read(&ut->types, fp))
>> +                        return -1;
>> +
>> +                rc = next_entry(buf, fp, sizeof(uint32_t));
>> +                if (rc < 0)
>> +                        return -1;
>> +                ut->new_user = le32_to_cpu(buf[0]);
>> +                lut = ut;
>> +        }
>> +
>> +        return 0;
>> +}
>> +
>> +
>> static int role_allow_rule_read(role_allow_rule_t ** r, struct 
>> policy_file *fp)
>> {
>> 	unsigned int i;
>> @@ -2805,9 +2933,14 @@
>> 	if (cond_read_list(p, &decl->cond_list, fp) == -1 ||
>> 	    avrule_read_list(p, &decl->avrules, fp) == -1 ||
>> 	    role_trans_rule_read(&decl->role_tr_rules, fp) == -1 ||
>> -	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1) {
>> +	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1)
>> +	    {
>> 		return -1;
>> 	}
>> +	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
>> +		if (user_trans_rule_read(&decl->user_tr_rules, fp))
>> +			return -1;
>> +	}
>> 	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
>> 	    range_trans_rule_read(&decl->range_tr_rules, fp) == -1) {
>> 		return -1;
>> @@ -3179,6 +3312,10 @@
>> 				goto bad;
>> 		if (role_trans_read(&p->role_tr, fp))
>> 			goto bad;
>> +		if (r_policyvers >= POLICYDB_VERSION_USERTRANS) {
>> +			if (user_trans_read(&p->user_tr, fp))
>> +				goto bad;
>> +		}
>> 		if (role_allow_read(&p->role_allow, fp))
>> 			goto bad;
>> 	} else {
>> Index: libsepol/src/expand.c
>> ===================================================================
>> --- libsepol/src/expand.c	(revision 2854)
>> +++ libsepol/src/expand.c	(working copy)
>> @@ -1060,6 +1060,80 @@
>> 	return 0;
>> }
>>
>> +static int copy_user_trans(expand_state_t * state, user_trans_rule_t * 
>> rules)
>> +{
>> +	unsigned int i, j;
>> +	user_trans_t *n, *l, *cur_trans;
>> +	user_trans_rule_t *cur;
>> +	ebitmap_t types;
>> +	ebitmap_node_t *rnode, *tnode;
>> +
>> +	/* start at the end of the list */
>> +	for (l = state->out->user_tr; l && l->next; l = l->next) ;
>> +
>> +	cur = rules;
>> +	while (cur) {
>> +		ebitmap_init(&types);
>> +
>> +		if (expand_convert_type_set
>> +		    (state->out, state->typemap, &cur->types, &types, 1)) {
>> +			ERR(state->handle, "Out of memory!");
>> +			return -1;
>> +		}
>> +		ebitmap_for_each_bit(&cur->users, rnode, i) {
>> +			if (!ebitmap_node_get_bit(rnode, i))
>> +				continue;
>> +			ebitmap_for_each_bit(&types, tnode, j) {
>> +				if (!ebitmap_node_get_bit(tnode, j))
>> +					continue;
>> +
>> +				cur_trans = state->out->user_tr;
>> +				while (cur_trans) {
>> +					if ((cur_trans->user == i + 1) &&
>> +					    (cur_trans->type == j + 1)) {
>> +						if (cur_trans->new_user ==
>> +						    cur->new_user) {
>> +							break;
>> +						} else {
>> +							ERR(state->handle,
>> +							    "Conflicting user trans rule %s %s : %s",
>> +							    state->out->p_user_val_to_name[i],
>> +							    state->out->p_type_val_to_name[j],
>> +							    state->out->p_user_val_to_name[cur->new_user - 1]);
>> +							return -1;
>> +						}
>> +					}
>> +					cur_trans = cur_trans->next;
>> +				}
>> +				if (cur_trans)
>> +					continue;
>> +
>> +				n = (user_trans_t *)
>> +				    malloc(sizeof(user_trans_t));
>> +				if (!n) {
>> +					ERR(state->handle, "Out of memory!");
>> +					return -1;
>> +				}
>> +				memset(n, 0, sizeof(user_trans_t));
>> +				n->user = i + 1;
>> +				n->type = j + 1;
>> +				n->new_user = cur->new_user;
>> +				if (l) {
>> +					l->next = n;
>> +				} else {
>> +					state->out->user_tr = n;
>> +				}
>> +				l = n;
>> +			}
>> +		}
>> +
>> +		ebitmap_destroy(&types);
>> +
>> +		cur = cur->next;
>> +	}
>> +	return 0;
>> +}
>> +
>> static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t 
>> tclass,
>> 			      mls_semantic_range_t * trange,
>> 			      expand_state_t * state)
>> @@ -2163,6 +2237,9 @@
>> 			goto cleanup;
>> 		}
>>
>> +		if (copy_user_trans(state, decl->user_tr_rules))
>> +			goto cleanup;
>> +
>> 		/* expand the range transition rules */
>> 		if (expand_range_trans(state, decl->range_tr_rules))
>> 			goto cleanup;
>> Index: libsepol/src/write.c
>> ===================================================================
>> --- libsepol/src/write.c	(revision 2854)
>> +++ libsepol/src/write.c	(working copy)
>> @@ -487,6 +487,31 @@
>> 	return POLICYDB_SUCCESS;
>> }
>>
>> +static int user_trans_write(user_trans_t * u, struct policy_file *fp)
>> +{
>> +	user_trans_t *tr;
>> +	uint32_t buf[3];
>> +	size_t nel, items;
>> +
>> +	nel = 0;
>> +	for (tr = u; tr; tr = tr->next)
>> +		nel++;
>> +	buf[0] = cpu_to_le32(nel);
>> +	items = put_entry(buf, sizeof(uint32_t), 1, fp);
>> +	if (items != 1)
>> +		return POLICYDB_ERROR;
>> +	for (tr = u; tr; tr = tr->next) {
>> +		buf[0] = cpu_to_le32(tr->user);
>> +		buf[1] = cpu_to_le32(tr->type);
>> +		buf[2] = cpu_to_le32(tr->new_user);
>> +		items = put_entry(buf, sizeof(uint32_t), 3, fp);
>> +		if (items != 3)
>> +			return POLICYDB_ERROR;
>> +	}
>> +
>> +	return POLICYDB_SUCCESS;
>> +}
>> +
>> static int role_allow_write(role_allow_t * r, struct policy_file *fp)
>> {
>> 	role_allow_t *ra;
>> @@ -1325,6 +1350,32 @@
>> 	return POLICYDB_SUCCESS;
>> }
>>
>> +static int user_trans_rule_write(user_trans_rule_t * t, struct 
>> policy_file *fp)
>> +{
>> +	int nel = 0;
>> +	size_t items;
>> +	uint32_t buf[1];
>> +	user_trans_rule_t *tr;
>> +
>> +	for (tr = t; tr; tr = tr->next)
>> +		nel++;
>> +	buf[0] = cpu_to_le32(nel);
>> +	items = put_entry(buf, sizeof(uint32_t), 1, fp);
>> +	if (items != 1)
>> +		return POLICYDB_ERROR;
>> +	for (tr = t; tr; tr = tr->next) {
>> +		if (ebitmap_write(&tr->users, fp))
>> +			return POLICYDB_ERROR;
>> +		if (type_set_write(&tr->types, fp))
>> +			return POLICYDB_ERROR;
>> +		buf[0] = cpu_to_le32(tr->new_user);
>> +		items = put_entry(buf, sizeof(uint32_t), 1, fp);
>> +		if (items != 1)
>> +			return POLICYDB_ERROR;
>> +	}
>> +	return POLICYDB_SUCCESS;
>> +}
>> +
>> static int role_allow_rule_write(role_allow_rule_t * r, struct 
>> policy_file *fp)
>> {
>> 	int nel = 0;
>> @@ -1414,6 +1465,10 @@
>> 	    role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
>> 		return POLICYDB_ERROR;
>> 	}
>> +	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
>> +		if (user_trans_rule_write(decl->user_tr_rules, fp))	
>> +			return POLICYDB_ERROR;
>> +	}
>> 	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
>> 	    range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
>> 		return POLICYDB_ERROR;
>> @@ -1642,6 +1697,10 @@
>> 		}
>> 		if (role_trans_write(p->role_tr, fp))
>> 			return POLICYDB_ERROR;
>> +		if (p->policyvers >= POLICYDB_VERSION_USERTRANS) {
>> +			if (user_trans_write(p->user_tr, fp))
>> +				return POLICYDB_ERROR;
>> +		}
>> 		if (role_allow_write(p->role_allow, fp))
>> 			return POLICYDB_ERROR;
>> 	} else {
>> Index: libsepol/src/link.c
>> ===================================================================
>> --- libsepol/src/link.c	(revision 2854)
>> +++ libsepol/src/link.c	(working copy)
>> @@ -848,6 +848,34 @@
>> 	return -1;
>> }
>>
>> +static int user_bitmap_or_convert(ebitmap_t * users, ebitmap_t * dst,
>> +			       policy_module_t * mod, link_state_t * state)
>> +{
>> +	unsigned int i;
>> +	ebitmap_t tmp;
>> +	ebitmap_node_t *rnode;
>> +
>> +	ebitmap_init(&tmp);
>> +	ebitmap_for_each_bit(users, rnode, i) {
>> +		if (ebitmap_node_get_bit(rnode, i)) {
>> +			assert(mod->map[SYM_USERS][i]);
>> +			if (ebitmap_set_bit
>> +			    (&tmp, mod->map[SYM_USERS][i] - 1, 1)) {
>> +				goto cleanup;
>> +			}
>> +		}
>> +	}
>> +	if (ebitmap_union(dst, &tmp)) {
>> +		goto cleanup;
>> +	}
>> +	ebitmap_destroy(&tmp);
>> +	return 0;
>> +      cleanup:
>> +	ERR(state->handle, "Out of memory!");
>> +	ebitmap_destroy(&tmp);
>> +	return -1;
>> +}
>> +
>> static int mls_level_convert(mls_semantic_level_t * src, 
>> mls_semantic_level_t * dst,
>> 			     policy_module_t * mod, link_state_t * state)
>> {
>> @@ -1004,13 +1032,22 @@
>> 	link_state_t *state = (link_state_t *) data;
>> 	policy_module_t *mod = state->cur;
>> 	symtab_t *usertab;
>> +	scope_datum_t *scope;
>>
>> 	user = (user_datum_t *) datum;
>>
>> +	scope = hashtab_search(state->cur->policy->p_users_scope.table, key);
>> +	assert(scope);
>> +	if (scope->scope == SCOPE_REQ) {
>> +		//this is required user, no role or mls data
>> +		return 0;
>> +	}
>> +
>> 	if (state->dest_decl == NULL)
>> 		usertab = &state->base->p_users;
>> -	else
>> +	else {
>> 		usertab = &state->dest_decl->p_users;
>> +	}
>>
>> 	new_user = hashtab_search(usertab->table, id);
>> 	assert(new_user != NULL);
>> @@ -1173,6 +1210,49 @@
>> 	return -1;
>> }
>>
>> +static int copy_user_trans_list(user_trans_rule_t * list,
>> +                                user_trans_rule_t ** dst,
>> +                                policy_module_t * module, link_state_t 
>> * state)
>> +{
>> +        user_trans_rule_t *cur, *new_rule = NULL, *tail;
>> +
>> +        cur = list;
>> +        tail = *dst;
>> +        while (tail && tail->next) {
>> +                tail = tail->next;
>> +        }
>> +        while (cur) {
>> +                if ((new_rule =
>> +                     (user_trans_rule_t *) 
>> malloc(sizeof(user_trans_rule_t))) ==
>> +                    NULL) {
>> +                        goto cleanup;
>> +                }
>> +                user_trans_rule_init(new_rule);
>> +
>> +                if (user_bitmap_or_convert(&cur->users, 
>> &new_rule->users, module, state))
>> +			goto cleanup;
>> +		if (type_set_or_convert(&cur->types, &new_rule->types, module, state)) {
>> +                        goto cleanup;
>> +                }
>> +
>> +                new_rule->new_user = 
>> module->map[SYM_USERS][cur->new_user - 1];
>> +
>> +                if (*dst == NULL) {
>> +                        *dst = new_rule;
>> +                } else {
>> +                        tail->next = new_rule;
>> +                }
>> +                tail = new_rule;
>> +                cur = cur->next;
>> +        }
>> +        return 0;
>> +      cleanup:
>> +        ERR(state->handle, "Out of memory!");
>> +        user_trans_rule_list_destroy(new_rule);
>> +        return -1;
>> +}
>> +
>> +
>> static int copy_role_allow_list(role_allow_rule_t * list,
>> 				role_allow_rule_t ** dst,
>> 				policy_module_t * module, link_state_t * state)
>> @@ -1446,6 +1526,10 @@
>> 		return -1;
>> 	}
>>
>> +	if (copy_user_trans_list(src_decl->user_tr_rules, 
>> &dest_decl->user_tr_rules,
>> +				 module, state))
>> +		return -1;
>> +
>> 	if (copy_range_trans_list(src_decl->range_tr_rules,
>> 				  &dest_decl->range_tr_rules, module, state))
>> 		return -1;
>> Index: checkpolicy/test/dismod.c
>> ===================================================================
>> --- checkpolicy/test/dismod.c	(revision 2854)
>> +++ checkpolicy/test/dismod.c	(working copy)
>> @@ -354,6 +354,21 @@
>> 	return 0;
>> }
>>
>> +int display_user_set(ebitmap_t *u, policydb_t *p, FILE *fp)
>> +{
>> +	ebitmap_node_t *node;
>> +	int i;
>> +
>> +	fprintf(fp, " { ");
>> +	ebitmap_for_each_bit(u, node, i) {
>> +		if (ebitmap_node_get_bit(node, i)) {
>> +			display_id(p, fp, SYM_USERS, i, "");
>> +		}
>> +	}
>> +	fprintf(fp, " } ");
>> +	return 0;
>> +}
>> +
>> int display_bools(policydb_t * p, FILE * fp)
>> {
>> 	int i;
>> @@ -461,7 +476,18 @@
>> 		fprintf(fp, "\n");
>> 	}
>> }
>> +void display_user_trans(user_trans_rule_t * tr, policydb_t * p, FILE * fp)
>>
>> +{
>> +	for (; tr; tr = tr->next) {
>> +		fprintf(fp, "user transition ");
>> +		display_user_set(&tr->users, p, fp);
>> +		display_type_set(&tr->types, 0, p, fp);
>> +		display_id(p, fp, SYM_USERS, tr->new_user - 1, " :");
>> +		fprintf(fp, "\n");
>> +	}
>> +}
>> +
>> void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp)
>> {
>> 	for (; ra; ra = ra->next) {
>> @@ -641,6 +667,10 @@
>> 			}
>> 			break;
>> 		}
>> +	case 7:{
>> +			display_user_trans(decl->user_tr_rules, policy, out_fp);
>> +			break;
>> +		}
>> 	default:{
>> 			assert(0);
>> 		}
>> @@ -806,6 +836,7 @@
>> 	printf("c)  Display policy capabilities\n");
>> 	printf("l)  Link in a module\n");
>> 	printf("u)  Display the unknown handling setting\n");
>> +	printf("U)  Display user transitions\n");
>> 	printf("\n");
>> 	printf("f)  set output file\n");
>> 	printf("m)  display menu\n");
>> @@ -918,9 +949,11 @@
>> 			display_policycaps(&policydb, out_fp);
>> 			break;
>> 		case 'u':
>> -		case 'U':
>> 			display_handle_unknown(&policydb, out_fp);
>> 			break;
>> +		case 'U':
>> +			display_avblock(7, 0, &policydb, out_fp);
>> +			break;
>> 		case 'f':
>> 			printf
>> 			    ("\nFilename for output (<CR> for screen output): ");
>> Index: checkpolicy/test/dispol.c
>> ===================================================================
>> --- checkpolicy/test/dispol.c	(revision 2854)
>> +++ checkpolicy/test/dispol.c	(working copy)
>> @@ -299,6 +299,18 @@
>> 	return 0;
>> }
>>
>> +static void display_user_transitions(policydb_t *p, FILE *fp)
>> +{
>> +	user_trans_t *cur;
>> +	for (cur = p->user_tr; cur; cur = cur->next) {
>> +		fprintf(fp, "user_transition ");
>> +		fprintf(fp, "%s %s %s;\n",
>> +			p->p_user_val_to_name[cur->user - 1],
>> +			p->p_type_val_to_name[cur->type - 1],
>> +			p->p_user_val_to_name[cur->new_user - 1]);
>> +	}
>> +}
>> +
>> static void display_policycaps(policydb_t * p, FILE * fp)
>> {
>> 	ebitmap_node_t *node;
>> @@ -332,6 +344,7 @@
>> 	printf("\n");
>> 	printf("c)  display policy capabilities\n");
>> 	printf("u)  display unknown handling setting\n");
>> +	printf("U)  display user transitions\n");
>> 	printf("f)  set output file\n");
>> 	printf("m)  display menu\n");
>> 	printf("q)  quit\n");
>> @@ -448,9 +461,11 @@
>> 			display_policycaps(&policydb, out_fp);
>> 			break;
>> 		case 'u':
>> -		case 'U':
>> 			display_handle_unknown(&policydb, out_fp);
>> 			break;
>> +		case 'U':
>> +			display_user_transitions(&policydb, out_fp);
>> +			break;
>> 		case 'f':
>> 			printf
>> 			    ("\nFilename for output (<CR> for screen output): ");
>> Index: checkpolicy/test/Makefile
>> ===================================================================
>> --- checkpolicy/test/Makefile	(revision 2854)
>> +++ checkpolicy/test/Makefile	(working copy)
>> @@ -6,7 +6,7 @@
>> LIBDIR=$(PREFIX)/lib
>> INCLUDEDIR ?= $(PREFIX)/include
>>
>> -CFLAGS ?= -g -Wall -O2 -pipe
>> +CFLAGS ?= -g3 -gdwarf-2 -Wall -O0 -pipe
>> override CFLAGS += -I$(INCLUDEDIR)
>>
>> LDLIBS=-lfl -lsepol -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR)
>> Index: checkpolicy/policy_define.c
>> ===================================================================
>> --- checkpolicy/policy_define.c	(revision 2854)
>> +++ checkpolicy/policy_define.c	(working copy)
>> @@ -2020,6 +2020,76 @@
>> 	return -1;
>> }
>>
>> +int define_user_trans(void)
>> +{
>> +        char *id;
>> +        user_datum_t *user, *u;
>> +	ebitmap_t users;
>> +        type_set_t types;
>> +        struct user_trans_rule *rule = NULL;
>> +        int add = 1;
>> +
>> +        if (pass == 1) {
>> +                while ((id = queue_remove(id_queue)))
>> +                        free(id);
>> +                while ((id = queue_remove(id_queue)))
>> +                        free(id);
>> +                id = queue_remove(id_queue);
>> +                free(id);
>> +                return 0;
>> +        }
>> +
>> +        ebitmap_init(&users);
>> +        type_set_init(&types);
>> +
>> +	while ((id = queue_remove(id_queue))) {
>> +		u = hashtab_search(policydbp->p_users.table, id);
>> +		if (!u) {
>> +			yyerror2("unknown user %s", id);
>> +			free(id);
>> +			return -1;
>> +		}
>> +		if (ebitmap_set_bit(&users, u->s.value - 1, TRUE))
>> +			return -1;
>> +	}
>> +	while ((id = queue_remove(id_queue))) {
>> +		if (set_types(&types, id, &add, 0))
>> +			return -1;
>> +	}
>> +	id = (char *)queue_remove(id_queue);
>> +	if (!id) {
>> +		yyerror("no new user in transition definition?");
>> +		goto bad;
>> +	}
>> +	if (!is_id_in_scope(SYM_USERS, id)) {
>> +		yyerror2("user %s is not within scope", id);
>> +		free(id);
>> +		goto bad;
>> +	}
>> +	user = hashtab_search(policydbp->p_users.table, id);
>> +	if (!user) {
>> +		yyerror2("unknown user %s used in transition definition", id);
>> +		goto bad;
>> +	}
>> +	rule = malloc(sizeof(struct user_trans_rule));
>> +	if (!rule) {
>> +		yyerror("out of memory");
>> +		return -1;
>> +	}
>> +	memset(rule, 0, sizeof(struct user_trans_rule));
>> +	rule->users = users;
>> +	rule->types = types;
>> +	rule->new_user = user->s.value;
>> +
>> +	append_user_trans(rule);
>> +
>> +	return 0;
>> +
>> +      bad:
>> +	return -1;
>> +}
>> +
>> +
>> int define_role_allow(void)
>> {
>> 	char *id;
>> Index: checkpolicy/policy_scan.l
>> ===================================================================
>> --- checkpolicy/policy_scan.l	(revision 2854)
>> +++ checkpolicy/policy_scan.l	(working copy)
>> @@ -102,6 +102,8 @@
>> type_change			{ return(TYPE_CHANGE); }
>> ROLE_TRANSITION |
>> role_transition			{ return(ROLE_TRANSITION); }
>> +USER_TRANSITION |
>> +user_transition			{ return(USER_TRANSITION); }
>> RANGE_TRANSITION |
>> range_transition		{ return(RANGE_TRANSITION); }
>> SENSITIVITY |
>> Index: checkpolicy/policy_define.h
>> ===================================================================
>> --- checkpolicy/policy_define.h	(revision 2854)
>> +++ checkpolicy/policy_define.h	(working copy)
>> @@ -42,6 +42,7 @@
>> int define_role_allow(void);
>> int define_role_trans(void);
>> int define_role_types(void);
>> +int define_user_trans(void);
>> int define_sens(void);
>> int define_te_avtab(int which);
>> int define_typealias(void);
>> Index: checkpolicy/module_compiler.c
>> ===================================================================
>> --- checkpolicy/module_compiler.c	(revision 2854)
>> +++ checkpolicy/module_compiler.c	(working copy)
>> @@ -1214,6 +1214,17 @@
>> 	decl->role_tr_rules = role_tr_rules;
>> }
>>
>> +void append_user_trans(user_trans_rule_t * user_tr_rules)
>> +{
>> +	avrule_decl_t *decl = stack_top->decl;
>> +
>> +	/* role transitions are not allowed within conditionals */
>> +	assert(stack_top->type == 1);
>> +
>> +	user_tr_rules->next = decl->user_tr_rules;
>> +	decl->user_tr_rules = user_tr_rules;
>> +}
>> +
>> /* this doesn't actually append, but really prepends it */
>> void append_role_allow(role_allow_rule_t * role_allow_rules)
>> {
>> Index: checkpolicy/policy_parse.y
>> ===================================================================
>> --- checkpolicy/policy_parse.y	(revision 2854)
>> +++ checkpolicy/policy_parse.y	(working copy)
>> @@ -103,6 +103,7 @@
>> %token TYPE_MEMBER
>> %token TYPE_CHANGE
>> %token ROLE_TRANSITION
>> +%token USER_TRANSITION
>> %token RANGE_TRANSITION
>> %token SENSITIVITY
>> %token DOMINANCE
>> @@ -261,6 +262,7 @@
>>                          | transition_def
>>                          | range_trans_def
>>                          | te_avtab_def
>> +			| user_trans_def
>> 			;
>> attribute_def           : ATTRIBUTE identifier ';'
>>                          { if (define_attrib()) return -1;}
>> @@ -411,6 +413,9 @@
>> role_trans_def		: ROLE_TRANSITION names names identifier ';'
>> 			{if (define_role_trans()) return -1; }
>> 			;
>> +user_trans_def		: USER_TRANSITION names names identifier ';'
>> +			{ if (define_user_trans()) return -1; }
>> +			;
>> role_allow_def		: ALLOW names names ';'
>> 			{if (define_role_allow()) return -1; }
>> 			;
>> Index: checkpolicy/module_compiler.h
>> ===================================================================
>> --- checkpolicy/module_compiler.h	(revision 2854)
>> +++ checkpolicy/module_compiler.h	(working copy)
>> @@ -80,6 +80,7 @@
>> void append_role_trans(role_trans_rule_t * role_tr_rules);
>> void append_role_allow(role_allow_rule_t * role_allow_rules);
>> void append_range_trans(range_trans_rule_t * range_tr_rules);
>> +void append_user_trans(user_trans_rule_t * user_tr_rules);
>>
>> /* Create a new optional block and add it to the global policy.
>>   * During the second pass resolve the block's requirements.  Return 0
>>
>>
>>     



--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 20:27   ` Joshua Brindle
@ 2008-03-24 20:36     ` Stephen Smalley
  2008-03-25 11:04       ` Joshua Brindle
  0 siblings, 1 reply; 27+ messages in thread
From: Stephen Smalley @ 2008-03-24 20:36 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: SE Linux, Caleb Case, jmowery


On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
> Stephen Smalley wrote:
> > On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> >   
> >> This implements user_transition in the toolchain. It should help on
> >> distro's like Ubuntu that can't use run_init due to the user not knowing
> >> the root password. It also seems like a more eloquent way to handle
> >> service restarts than assigning system_r to user accounts and having the
> >> daemons run as someuser:system_r:foo_t.
> >>     
> >
> > Yes, that's something that has been wanted in Fedora for quite some
> > time.
> >
> > The real issue with run_init isn't the re-authentication stage, as that
> > can always be disabled via pam config (and was just a weak form of
> > confirming user intent, not an authorization mechanism), but rather the
> > difficulty in transparently interposing it into all situations where
> > services get started/re-started.  Only Gentoo seemed to have a good
> > story there.
> >
> >   
> >> This has some issues in policy due to users not always being known in
> >> the policy (eg., semanage users). I hope Chris or Dan will be able to
> >> give some suggestions there.
> >>     
> >
> > I'm not sure why anyone needs to add users to policy via semanage users
> > given the base set of generic users and the ability to map Linux users
> > to them via seusers aka semanage login.
> >
> >   
> >> The kernel patch (forthcoming after this is accepted) so far only
> >> implements the transition on process transitions. Later on I plan on
> >> doing a patch to expand role_transition to object classes (this is a
> >> change needed for policy rbac support to work). I suspect I'll do the
> >> same for user at that time. The question here is, do we think its worth
> >> it to do fine grained transitions like we did for range_trans? (I don't).
> >>     
> >
> > Offhand, I can't see a use for per-class user transitions, if that is
> > what you mean.
> >
> > I don't think per-class role transitions is really the fundamental
> > obstacle to enabling use of roles on objects - more thought is required
> > there.  What will be fun there is role/type and user/range validation,
> > which presently gets to ignore everything that has object_r.
> >   
> 
> Ah, another thing. While going through the policyrep implementation the 
> question of object_r came up. My thought is to start adding object_r 
> magic into the toolchain (adding all types, etc) and eventually purge 
> object_r from the kernel. at least one magic instance of object_r will 
> be removed by object role_transitions, the others are really short 
> circuits in the security server that can be removed after sufficient 
> support is in the toolchain. What are your thoughts on that (for future 
> reference)?

Well, the interesting question is what should the default role be in the
new context in security_compute_sid, if not object_r.  Even aside from
the support for per-class role transitions.  User defaults to the source
context, type defaults to the related object context, and MLS range
defaults to the low level of the source context.  Role could be the
subject's role or the related object's role.

-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 20:15 ` Stephen Smalley
  2008-03-24 20:27   ` Joshua Brindle
  2008-03-24 20:30   ` Joshua Brindle
@ 2008-03-25  4:25   ` Russell Coker
  2008-03-25 10:37     ` Joshua Brindle
  2008-03-25 11:42     ` Stephen Smalley
  2008-03-26  8:40   ` Daniel J Walsh
  3 siblings, 2 replies; 27+ messages in thread
From: Russell Coker @ 2008-03-25  4:25 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: Joshua Brindle, SE Linux, Caleb Case

On Tuesday 25 March 2008 07:15, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> The real issue with run_init isn't the re-authentication stage, as that
> can always be disabled via pam config (and was just a weak form of
> confirming user intent, not an authorization mechanism), but rather the
> difficulty in transparently interposing it into all situations where
> services get started/re-started.  Only Gentoo seemed to have a good
> story there.

In Red Hat distributions the command "service" is well documented, and last 
time I checked it was the only documented way of restarting daemons.

If the "service" command was modified to call run_init then a large part of 
that problem would be solved.  It would not be unreasonable to demand that 
people who use the strict or mls policy also exclusively use "service" 
instead of running the script directly.

> I'm not sure why anyone needs to add users to policy via semanage users
> given the base set of generic users and the ability to map Linux users
> to them via seusers aka semanage login.

Roles?

Also I like to be able to run "ls -Z" to see the SE Linux identity of the 
person who created the file.

-- 
russell@coker.com.au
http://etbe.coker.com.au/          My Blog

http://www.coker.com.au/sponsorship.html Sponsoring Free Software development

--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25  4:25   ` Russell Coker
@ 2008-03-25 10:37     ` Joshua Brindle
  2008-03-25 11:42     ` Stephen Smalley
  1 sibling, 0 replies; 27+ messages in thread
From: Joshua Brindle @ 2008-03-25 10:37 UTC (permalink / raw)
  To: russell; +Cc: Stephen Smalley, SE Linux, Caleb Case

Russell Coker wrote:
> On Tuesday 25 March 2008 07:15, Stephen Smalley <sds@tycho.nsa.gov> wrote:
>   
>> I'm not sure why anyone needs to add users to policy via semanage users
>> given the base set of generic users and the ability to map Linux users
>> to them via seusers aka semanage login.
>>     
>
> Roles?
>
> Also I like to be able to run "ls -Z" to see the SE Linux identity of the 
> person who created the file.
>   

Roles on objects will be my next patch after this one goes through. It 
will be necessary to implement the rbac separation in the policy that 
we've been talking about.



--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 20:36     ` Stephen Smalley
@ 2008-03-25 11:04       ` Joshua Brindle
  2008-03-25 12:08         ` Stephen Smalley
  0 siblings, 1 reply; 27+ messages in thread
From: Joshua Brindle @ 2008-03-25 11:04 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: SE Linux, Caleb Case, Christopher J. PeBenito

Stephen Smalley wrote:
> On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
>   
>> Stephen Smalley wrote:
>>     
>>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>>>   
>>>       
>>>> This implements user_transition in the toolchain. It should help on
>>>> distro's like Ubuntu that can't use run_init due to the user not knowing
>>>> the root password. It also seems like a more eloquent way to handle
>>>> service restarts than assigning system_r to user accounts and having the
>>>> daemons run as someuser:system_r:foo_t.
>>>>     
>>>>         
>>> Yes, that's something that has been wanted in Fedora for quite some
>>> time.
>>>
>>> The real issue with run_init isn't the re-authentication stage, as that
>>> can always be disabled via pam config (and was just a weak form of
>>> confirming user intent, not an authorization mechanism), but rather the
>>> difficulty in transparently interposing it into all situations where
>>> services get started/re-started.  Only Gentoo seemed to have a good
>>> story there.
>>>
>>>   
>>>       
>>>> This has some issues in policy due to users not always being known in
>>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>>>> give some suggestions there.
>>>>     
>>>>         
>>> I'm not sure why anyone needs to add users to policy via semanage users
>>> given the base set of generic users and the ability to map Linux users
>>> to them via seusers aka semanage login.
>>>
>>>   
>>>       
>>>> The kernel patch (forthcoming after this is accepted) so far only
>>>> implements the transition on process transitions. Later on I plan on
>>>> doing a patch to expand role_transition to object classes (this is a
>>>> change needed for policy rbac support to work). I suspect I'll do the
>>>> same for user at that time. The question here is, do we think its worth
>>>> it to do fine grained transitions like we did for range_trans? (I don't).
>>>>     
>>>>         
>>> Offhand, I can't see a use for per-class user transitions, if that is
>>> what you mean.
>>>
>>> I don't think per-class role transitions is really the fundamental
>>> obstacle to enabling use of roles on objects - more thought is required
>>> there.  What will be fun there is role/type and user/range validation,
>>> which presently gets to ignore everything that has object_r.
>>>   
>>>       
>> Ah, another thing. While going through the policyrep implementation the 
>> question of object_r came up. My thought is to start adding object_r 
>> magic into the toolchain (adding all types, etc) and eventually purge 
>> object_r from the kernel. at least one magic instance of object_r will 
>> be removed by object role_transitions, the others are really short 
>> circuits in the security server that can be removed after sufficient 
>> support is in the toolchain. What are your thoughts on that (for future 
>> reference)?
>>     
>
> Well, the interesting question is what should the default role be in the
> new context in security_compute_sid, if not object_r.  Even aside from
> the support for per-class role transitions.  User defaults to the source
> context, type defaults to the related object context, and MLS range
> defaults to the low level of the source context.  Role could be the
> subject's role or the related object's role.
>
>   

Good question. My original assumption was that we'd use the related 
object role. That would require that home directories be correctly 
labeled with the role of the user. If we start using the source role 
then things will quickly change from object_r to system_r, so maybe the 
policy should do that anyway. Chris, any opinions on this?



--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25  4:25   ` Russell Coker
  2008-03-25 10:37     ` Joshua Brindle
@ 2008-03-25 11:42     ` Stephen Smalley
  1 sibling, 0 replies; 27+ messages in thread
From: Stephen Smalley @ 2008-03-25 11:42 UTC (permalink / raw)
  To: russell; +Cc: Joshua Brindle, SE Linux, Caleb Case


On Tue, 2008-03-25 at 15:25 +1100, Russell Coker wrote:
> On Tuesday 25 March 2008 07:15, Stephen Smalley <sds@tycho.nsa.gov> wrote:
> > The real issue with run_init isn't the re-authentication stage, as that
> > can always be disabled via pam config (and was just a weak form of
> > confirming user intent, not an authorization mechanism), but rather the
> > difficulty in transparently interposing it into all situations where
> > services get started/re-started.  Only Gentoo seemed to have a good
> > story there.
> 
> In Red Hat distributions the command "service" is well documented, and last 
> time I checked it was the only documented way of restarting daemons.
> 
> If the "service" command was modified to call run_init then a large part of 
> that problem would be solved.  It would not be unreasonable to demand that 
> people who use the strict or mls policy also exclusively use "service" 
> instead of running the script directly.

That was what we thought originally, and IIRC, Dan originally modified
service to invoke run_init during early Fedora SELinux integration.
Only to find out just how many things bypass it, like rpm %post
scriptlets and admins from the shell ;)

> 
> > I'm not sure why anyone needs to add users to policy via semanage users
> > given the base set of generic users and the ability to map Linux users
> > to them via seusers aka semanage login.
> 
> Roles?
> 
> Also I like to be able to run "ls -Z" to see the SE Linux identity of the 
> person who created the file.
> 
-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25 11:04       ` Joshua Brindle
@ 2008-03-25 12:08         ` Stephen Smalley
  2008-03-25 13:01           ` Christopher J. PeBenito
  2008-03-26  8:46           ` Daniel J Walsh
  0 siblings, 2 replies; 27+ messages in thread
From: Stephen Smalley @ 2008-03-25 12:08 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: SE Linux, Caleb Case, Christopher J. PeBenito


On Tue, 2008-03-25 at 07:04 -0400, Joshua Brindle wrote:
> Stephen Smalley wrote:
> > On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
> >   
> >> Stephen Smalley wrote:
> >>     
> >>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> >>>   
> >>>       
> >>>> This implements user_transition in the toolchain. It should help on
> >>>> distro's like Ubuntu that can't use run_init due to the user not knowing
> >>>> the root password. It also seems like a more eloquent way to handle
> >>>> service restarts than assigning system_r to user accounts and having the
> >>>> daemons run as someuser:system_r:foo_t.
> >>>>     
> >>>>         
> >>> Yes, that's something that has been wanted in Fedora for quite some
> >>> time.
> >>>
> >>> The real issue with run_init isn't the re-authentication stage, as that
> >>> can always be disabled via pam config (and was just a weak form of
> >>> confirming user intent, not an authorization mechanism), but rather the
> >>> difficulty in transparently interposing it into all situations where
> >>> services get started/re-started.  Only Gentoo seemed to have a good
> >>> story there.
> >>>
> >>>   
> >>>       
> >>>> This has some issues in policy due to users not always being known in
> >>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
> >>>> give some suggestions there.
> >>>>     
> >>>>         
> >>> I'm not sure why anyone needs to add users to policy via semanage users
> >>> given the base set of generic users and the ability to map Linux users
> >>> to them via seusers aka semanage login.
> >>>
> >>>   
> >>>       
> >>>> The kernel patch (forthcoming after this is accepted) so far only
> >>>> implements the transition on process transitions. Later on I plan on
> >>>> doing a patch to expand role_transition to object classes (this is a
> >>>> change needed for policy rbac support to work). I suspect I'll do the
> >>>> same for user at that time. The question here is, do we think its worth
> >>>> it to do fine grained transitions like we did for range_trans? (I don't).
> >>>>     
> >>>>         
> >>> Offhand, I can't see a use for per-class user transitions, if that is
> >>> what you mean.
> >>>
> >>> I don't think per-class role transitions is really the fundamental
> >>> obstacle to enabling use of roles on objects - more thought is required
> >>> there.  What will be fun there is role/type and user/range validation,
> >>> which presently gets to ignore everything that has object_r.
> >>>   
> >>>       
> >> Ah, another thing. While going through the policyrep implementation the 
> >> question of object_r came up. My thought is to start adding object_r 
> >> magic into the toolchain (adding all types, etc) and eventually purge 
> >> object_r from the kernel. at least one magic instance of object_r will 
> >> be removed by object role_transitions, the others are really short 
> >> circuits in the security server that can be removed after sufficient 
> >> support is in the toolchain. What are your thoughts on that (for future 
> >> reference)?
> >>     
> >
> > Well, the interesting question is what should the default role be in the
> > new context in security_compute_sid, if not object_r.  Even aside from
> > the support for per-class role transitions.  User defaults to the source
> > context, type defaults to the related object context, and MLS range
> > defaults to the low level of the source context.  Role could be the
> > subject's role or the related object's role.
> >
> >   
> 
> Good question. My original assumption was that we'd use the related 
> object role. That would require that home directories be correctly 
> labeled with the role of the user. If we start using the source role 
> then things will quickly change from object_r to system_r, so maybe the 
> policy should do that anyway. Chris, any opinions on this?

Yes, related object role would likely cause the least breakage.  It
would preserve the existing default for existing filesystems (as they
already have object_r in the directory contexts), while allowing us to
switch over to the user's role for home directories upon a relabel or
new filesystem.  Source role might create more conflicts, as we enforce
the role/type relationship for contexts and there might be a mismatch
between the creating process role and the parent directory type.

-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25 12:08         ` Stephen Smalley
@ 2008-03-25 13:01           ` Christopher J. PeBenito
  2008-03-25 13:52             ` Joshua Brindle
  2008-03-26  8:46           ` Daniel J Walsh
  1 sibling, 1 reply; 27+ messages in thread
From: Christopher J. PeBenito @ 2008-03-25 13:01 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: Joshua Brindle, SE Linux, Caleb Case

On Tue, 2008-03-25 at 08:08 -0400, Stephen Smalley wrote:
> On Tue, 2008-03-25 at 07:04 -0400, Joshua Brindle wrote:
> > Stephen Smalley wrote:
> > > On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:

> > >> Ah, another thing. While going through the policyrep implementation the 
> > >> question of object_r came up. My thought is to start adding object_r 
> > >> magic into the toolchain (adding all types, etc) and eventually purge 
> > >> object_r from the kernel. at least one magic instance of object_r will 
> > >> be removed by object role_transitions, the others are really short 
> > >> circuits in the security server that can be removed after sufficient 
> > >> support is in the toolchain. What are your thoughts on that (for future 
> > >> reference)?
> > >>     
> > >
> > > Well, the interesting question is what should the default role be in the
> > > new context in security_compute_sid, if not object_r.  Even aside from
> > > the support for per-class role transitions.  User defaults to the source
> > > context, type defaults to the related object context, and MLS range
> > > defaults to the low level of the source context.  Role could be the
> > > subject's role or the related object's role.
> > >
> > >   
> > 
> > Good question. My original assumption was that we'd use the related 
> > object role. That would require that home directories be correctly 
> > labeled with the role of the user. If we start using the source role 
> > then things will quickly change from object_r to system_r, so maybe the 
> > policy should do that anyway. Chris, any opinions on this?
> 
> Yes, related object role would likely cause the least breakage.  It
> would preserve the existing default for existing filesystems (as they
> already have object_r in the directory contexts), while allowing us to
> switch over to the user's role for home directories upon a relabel or
> new filesystem.  Source role might create more conflicts, as we enforce
> the role/type relationship for contexts and there might be a mismatch
> between the creating process role and the parent directory type.

Using the related object role seems right to me too.

-- 
Chris PeBenito
Tresys Technology, LLC
(410) 290-1411 x150



--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25 13:01           ` Christopher J. PeBenito
@ 2008-03-25 13:52             ` Joshua Brindle
  2008-03-25 16:27               ` Stephen Smalley
  0 siblings, 1 reply; 27+ messages in thread
From: Joshua Brindle @ 2008-03-25 13:52 UTC (permalink / raw)
  To: Christopher J. PeBenito; +Cc: Stephen Smalley, SE Linux, Caleb Case

Christopher J. PeBenito wrote:
> On Tue, 2008-03-25 at 08:08 -0400, Stephen Smalley wrote:
>   
>> On Tue, 2008-03-25 at 07:04 -0400, Joshua Brindle wrote:
>>     
>>> Stephen Smalley wrote:
>>>       
>>>> On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
>>>>         
>
>   
>>>>> Ah, another thing. While going through the policyrep implementation the 
>>>>> question of object_r came up. My thought is to start adding object_r 
>>>>> magic into the toolchain (adding all types, etc) and eventually purge 
>>>>> object_r from the kernel. at least one magic instance of object_r will 
>>>>> be removed by object role_transitions, the others are really short 
>>>>> circuits in the security server that can be removed after sufficient 
>>>>> support is in the toolchain. What are your thoughts on that (for future 
>>>>> reference)?
>>>>>     
>>>>>           
>>>> Well, the interesting question is what should the default role be in the
>>>> new context in security_compute_sid, if not object_r.  Even aside from
>>>> the support for per-class role transitions.  User defaults to the source
>>>> context, type defaults to the related object context, and MLS range
>>>> defaults to the low level of the source context.  Role could be the
>>>> subject's role or the related object's role.
>>>>
>>>>   
>>>>         
>>> Good question. My original assumption was that we'd use the related 
>>> object role. That would require that home directories be correctly 
>>> labeled with the role of the user. If we start using the source role 
>>> then things will quickly change from object_r to system_r, so maybe the 
>>> policy should do that anyway. Chris, any opinions on this?
>>>       
>> Yes, related object role would likely cause the least breakage.  It
>> would preserve the existing default for existing filesystems (as they
>> already have object_r in the directory contexts), while allowing us to
>> switch over to the user's role for home directories upon a relabel or
>> new filesystem.  Source role might create more conflicts, as we enforce
>> the role/type relationship for contexts and there might be a mismatch
>> between the creating process role and the parent directory type.
>>     
>
> Using the related object role seems right to me too.
>   

The inconsistency of handling parts of the context is a little troubling 
to me, half the context will be coming from the source and half from the 
object container. If this doesn't bother anyone else I suppose I'll try 
to ignore that OCD'ism of mine but I love it when the models we support 
work pretty seamlessly together and this seems like artifacts of them 
not doing that.



--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25 13:52             ` Joshua Brindle
@ 2008-03-25 16:27               ` Stephen Smalley
  0 siblings, 0 replies; 27+ messages in thread
From: Stephen Smalley @ 2008-03-25 16:27 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: Christopher J. PeBenito, SE Linux, Caleb Case


On Tue, 2008-03-25 at 09:52 -0400, Joshua Brindle wrote:
> Christopher J. PeBenito wrote:
> > On Tue, 2008-03-25 at 08:08 -0400, Stephen Smalley wrote:
> >   
> >> On Tue, 2008-03-25 at 07:04 -0400, Joshua Brindle wrote:
> >>     
> >>> Stephen Smalley wrote:
> >>>       
> >>>> On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
> >>>>         
> >
> >   
> >>>>> Ah, another thing. While going through the policyrep implementation the 
> >>>>> question of object_r came up. My thought is to start adding object_r 
> >>>>> magic into the toolchain (adding all types, etc) and eventually purge 
> >>>>> object_r from the kernel. at least one magic instance of object_r will 
> >>>>> be removed by object role_transitions, the others are really short 
> >>>>> circuits in the security server that can be removed after sufficient 
> >>>>> support is in the toolchain. What are your thoughts on that (for future 
> >>>>> reference)?
> >>>>>     
> >>>>>           
> >>>> Well, the interesting question is what should the default role be in the
> >>>> new context in security_compute_sid, if not object_r.  Even aside from
> >>>> the support for per-class role transitions.  User defaults to the source
> >>>> context, type defaults to the related object context, and MLS range
> >>>> defaults to the low level of the source context.  Role could be the
> >>>> subject's role or the related object's role.
> >>>>
> >>>>   
> >>>>         
> >>> Good question. My original assumption was that we'd use the related 
> >>> object role. That would require that home directories be correctly 
> >>> labeled with the role of the user. If we start using the source role 
> >>> then things will quickly change from object_r to system_r, so maybe the 
> >>> policy should do that anyway. Chris, any opinions on this?
> >>>       
> >> Yes, related object role would likely cause the least breakage.  It
> >> would preserve the existing default for existing filesystems (as they
> >> already have object_r in the directory contexts), while allowing us to
> >> switch over to the user's role for home directories upon a relabel or
> >> new filesystem.  Source role might create more conflicts, as we enforce
> >> the role/type relationship for contexts and there might be a mismatch
> >> between the creating process role and the parent directory type.
> >>     
> >
> > Using the related object role seems right to me too.
> >   
> 
> The inconsistency of handling parts of the context is a little troubling 
> to me, half the context will be coming from the source and half from the 
> object container. If this doesn't bother anyone else I suppose I'll try 
> to ignore that OCD'ism of mine but I love it when the models we support 
> work pretty seamlessly together and this seems like artifacts of them 
> not doing that.

It's a logical consequence of the individual models, which are indeed
different.  I don't believe we can or want to make them all the same.

One thing that has come up previously though is that it would be
convenient if we could specify the default inheritance behaviors in the
policy configuration itself.

-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 17:40 [RFC][PATCH] user_transition support for libsepol/checkpolicy Joshua Brindle
  2008-03-24 20:15 ` Stephen Smalley
@ 2008-03-25 16:42 ` Stephen Smalley
  2008-03-25 20:50   ` Joshua Brindle
  1 sibling, 1 reply; 27+ messages in thread
From: Stephen Smalley @ 2008-03-25 16:42 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: SE Linux, Caleb Case


On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> This implements user_transition in the toolchain. It should help on
> distro's like Ubuntu that can't use run_init due to the user not knowing
> the root password. It also seems like a more eloquent way to handle
> service restarts than assigning system_r to user accounts and having the
> daemons run as someuser:system_r:foo_t.
> 
> This has some issues in policy due to users not always being known in
> the policy (eg., semanage users). I hope Chris or Dan will be able to
> give some suggestions there.
> 
> The kernel patch (forthcoming after this is accepted) so far only
> implements the transition on process transitions. Later on I plan on
> doing a patch to expand role_transition to object classes (this is a
> change needed for policy rbac support to work). I suspect I'll do the
> same for user at that time. The question here is, do we think its worth
> it to do fine grained transitions like we did for range_trans? (I don't).
> 
> Index: libsepol/include/sepol/policydb/policydb.h
> ===================================================================
> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
> @@ -156,6 +156,14 @@
> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
> } user_datum_t;
> 
> +typedef struct user_trans {
> +	uint32_t user;		/* current role */
> +	uint32_t type;		/* program executable type */
> +	uint32_t new_user;	/* new role */
> +	struct user_trans *next;
> +} user_trans_t;
> +
> +
> /* Sensitivity attributes */
> typedef struct level_datum {
> 	mls_level_t *level;	/* sensitivity and associated categories */
> @@ -225,6 +233,13 @@
> 	struct role_trans_rule *next;
> } role_trans_rule_t;
> 
> +typedef struct user_trans_rule {
> +	ebitmap_t users;	/* current role */
> +	type_set_t types;	/* program executable type */
> +	uint32_t new_user;	/* new role */
> +	struct user_trans_rule *next;
> +} user_trans_rule_t;

Possibly crazy idea - given the current trend, would it be better to
just save the user transition rules in symbolic form in the module
format.  Would that simplify the link/expand code?

> Index: libsepol/src/policydb.c
> ===================================================================
> --- libsepol/src/policydb.c	(revision 2854)
> +++ libsepol/src/policydb.c	(working copy)
> @@ -348,6 +367,30 @@
> 	}
> }
> 
> +void user_trans_rule_init(user_trans_rule_t * x)
> +{
> +	memset(x, 0, sizeof(*x));

Not unique to this patch, but it seems funny that we use memset followed
by explicit initializers for fields that have them.  And that as a
result of the memset here, we don't calloc when allocate the structs.

> +	ebitmap_init(&x->users);
> +	type_set_init(&x->types);
> +}
> +
> +void user_trans_rule_destroy(user_trans_rule_t * x)
> +{
> +	if (x != NULL) {
> +		ebitmap_init(&x->users);

Should be ebitmap_destroy, right?

> +		type_set_destroy(&x->types);
> +	}
> +}
> +

Usual boilerplate - make sure it runs under valgrind cleanly and doesn't
introduce any (new) leaks on monolithic and modular build+link.

-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25 16:42 ` Stephen Smalley
@ 2008-03-25 20:50   ` Joshua Brindle
  2008-03-26 12:48     ` Stephen Smalley
  0 siblings, 1 reply; 27+ messages in thread
From: Joshua Brindle @ 2008-03-25 20:50 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: SE Linux, Caleb Case

Stephen Smalley wrote:
> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>   
>> This implements user_transition in the toolchain. It should help on
>> distro's like Ubuntu that can't use run_init due to the user not knowing
>> the root password. It also seems like a more eloquent way to handle
>> service restarts than assigning system_r to user accounts and having the
>> daemons run as someuser:system_r:foo_t.
>>
>> This has some issues in policy due to users not always being known in
>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>> give some suggestions there.
>>
>> The kernel patch (forthcoming after this is accepted) so far only
>> implements the transition on process transitions. Later on I plan on
>> doing a patch to expand role_transition to object classes (this is a
>> change needed for policy rbac support to work). I suspect I'll do the
>> same for user at that time. The question here is, do we think its worth
>> it to do fine grained transitions like we did for range_trans? (I don't).
>>
>> Index: libsepol/include/sepol/policydb/policydb.h
>> ===================================================================
>> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
>> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
>> @@ -156,6 +156,14 @@
>> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
>> } user_datum_t;
>>
>> +typedef struct user_trans {
>> +	uint32_t user;		/* current role */
>> +	uint32_t type;		/* program executable type */
>> +	uint32_t new_user;	/* new role */
>> +	struct user_trans *next;
>> +} user_trans_t;
>> +
>> +
>> /* Sensitivity attributes */
>> typedef struct level_datum {
>> 	mls_level_t *level;	/* sensitivity and associated categories */
>> @@ -225,6 +233,13 @@
>> 	struct role_trans_rule *next;
>> } role_trans_rule_t;
>>
>> +typedef struct user_trans_rule {
>> +	ebitmap_t users;	/* current role */
>> +	type_set_t types;	/* program executable type */
>> +	uint32_t new_user;	/* new role */
>> +	struct user_trans_rule *next;
>> +} user_trans_rule_t;
>>     
>
> Possibly crazy idea - given the current trend, would it be better to
> just save the user transition rules in symbolic form in the module
> format.  Would that simplify the link/expand code?
>
>   

Possibly, I am hoping policyrep will supplant this code in the near 
future so I didn't think about it much. This is consistent with how we 
store other modular things.

>> Index: libsepol/src/policydb.c
>> ===================================================================
>> --- libsepol/src/policydb.c	(revision 2854)
>> +++ libsepol/src/policydb.c	(working copy)
>> @@ -348,6 +367,30 @@
>> 	}
>> }
>>
>> +void user_trans_rule_init(user_trans_rule_t * x)
>> +{
>> +	memset(x, 0, sizeof(*x));
>>     
>
> Not unique to this patch, but it seems funny that we use memset followed
> by explicit initializers for fields that have them.  And that as a
> result of the memset here, we don't calloc when allocate the structs.
>
>   

I would normally never memset a struct, rather than use an initializer 
but I was going for minimal changes here, I don't plan on this code 
being around for long.

>> +	ebitmap_init(&x->users);
>> +	type_set_init(&x->types);
>> +}
>> +
>> +void user_trans_rule_destroy(user_trans_rule_t * x)
>> +{
>> +	if (x != NULL) {
>> +		ebitmap_init(&x->users);
>>     
>
> Should be ebitmap_destroy, right?
>
>   
Oops, yes

>> +		type_set_destroy(&x->types);
>> +	}
>> +}
>> +
>>     
>
> Usual boilerplate - make sure it runs under valgrind cleanly and doesn't
> introduce any (new) leaks on monolithic and modular build+link

This was an RFC patch and didn't go through any rigorous testing or 
valgrind (though I did ask for comments..) I recently found a bug in it 
so there will be another patch soon. Thanks for the comments.


--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-24 20:15 ` Stephen Smalley
                     ` (2 preceding siblings ...)
  2008-03-25  4:25   ` Russell Coker
@ 2008-03-26  8:40   ` Daniel J Walsh
  2008-03-26 13:33     ` Stephen Smalley
  3 siblings, 1 reply; 27+ messages in thread
From: Daniel J Walsh @ 2008-03-26  8:40 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: Joshua Brindle, SE Linux, Caleb Case

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Stephen Smalley wrote:
> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>> This implements user_transition in the toolchain. It should help on
>> distro's like Ubuntu that can't use run_init due to the user not knowing
>> the root password. It also seems like a more eloquent way to handle
>> service restarts than assigning system_r to user accounts and having the
>> daemons run as someuser:system_r:foo_t.
> 
> Yes, that's something that has been wanted in Fedora for quite some
> time.
> 
> The real issue with run_init isn't the re-authentication stage, as that
> can always be disabled via pam config (and was just a weak form of
> confirming user intent, not an authorization mechanism), but rather the
> difficulty in transparently interposing it into all situations where
> services get started/re-started.  Only Gentoo seemed to have a good
> story there.
> 
>> This has some issues in policy due to users not always being known in
>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>> give some suggestions there.
> 
> I'm not sure why anyone needs to add users to policy via semanage users
> given the base set of generic users and the ability to map Linux users
> to them via seusers aka semanage login.
> 
Can we define users in modules?  I envision and have provided
modifications to do system-config-selinux for someone to take a guest_t
and create a new role/type guest_plussendmail_t for a limited privileged
login account that can connect to the sendmail port.

So once I have created this new User Type,  I need a way to define the
user.  In Fedora right now, we define the xguest and guest accounts in
the postinstall using semanage.

>> The kernel patch (forthcoming after this is accepted) so far only
>> implements the transition on process transitions. Later on I plan on
>> doing a patch to expand role_transition to object classes (this is a
>> change needed for policy rbac support to work). I suspect I'll do the
>> same for user at that time. The question here is, do we think its worth
>> it to do fine grained transitions like we did for range_trans? (I don't).
> 
> Offhand, I can't see a use for per-class user transitions, if that is
> what you mean.
> 
> I don't think per-class role transitions is really the fundamental
> obstacle to enabling use of roles on objects - more thought is required
> there.  What will be fun there is role/type and user/range validation,
> which presently gets to ignore everything that has object_r.
> 
>> Index: libsepol/include/sepol/policydb/policydb.h
>> ===================================================================
>> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
>> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
>> @@ -156,6 +156,14 @@
>> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
>> } user_datum_t;
>>
>> +typedef struct user_trans {
>> +	uint32_t user;		/* current role */
>> +	uint32_t type;		/* program executable type */
>> +	uint32_t new_user;	/* new role */
>> +	struct user_trans *next;
>> +} user_trans_t;
>> +
>> +
>> /* Sensitivity attributes */
>> typedef struct level_datum {
>> 	mls_level_t *level;	/* sensitivity and associated categories */
>> @@ -225,6 +233,13 @@
>> 	struct role_trans_rule *next;
>> } role_trans_rule_t;
>>
>> +typedef struct user_trans_rule {
>> +	ebitmap_t users;	/* current role */
>> +	type_set_t types;	/* program executable type */
>> +	uint32_t new_user;	/* new role */
>> +	struct user_trans_rule *next;
>> +} user_trans_rule_t;
>> +
>> typedef struct role_allow_rule {
>> 	role_set_t roles;	/* current role */
>> 	role_set_t new_roles;	/* new roles */
>> @@ -348,6 +363,9 @@
>> 	char *module_name;
>>
>> 	struct avrule_decl *next;
>> +
>> +	user_trans_rule_t *user_tr_rules;
>> +	
>> } avrule_decl_t;
>>
>> typedef struct avrule_block {
>> @@ -470,6 +488,8 @@
>>
>> 	ebitmap_t policycaps;
>>
>> +	user_trans_t *user_tr;
>> +
>> 	unsigned policyvers;
>>
>> 	unsigned handle_unknown;
>> @@ -524,6 +544,9 @@
>> extern void role_trans_rule_init(role_trans_rule_t * x);
>> extern void role_trans_rule_list_destroy(role_trans_rule_t * x);
>>
>> +extern void user_trans_rule_init(user_trans_rule_t * x);
>> +extern void user_trans_rule_list_destroy(user_trans_rule_t * x);
>> +
>> extern void role_datum_init(role_datum_t * x);
>> extern void role_datum_destroy(role_datum_t * x);
>> extern void role_allow_rule_init(role_allow_rule_t * x);
>> @@ -588,10 +611,11 @@
>> #define POLICYDB_VERSION_AVTAB		20
>> #define POLICYDB_VERSION_RANGETRANS	21
>> #define POLICYDB_VERSION_POLCAP		22
>> +#define POLICYDB_VERSION_USERTRANS	23
>>
>> /* Range of policy versions we understand*/
>> #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
>> -#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_POLCAP
>> +#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_USERTRANS
>>
>> /* Module versions and specific changes*/
>> #define MOD_POLICYDB_VERSION_BASE	   4
>> @@ -600,9 +624,10 @@
>> #define MOD_POLICYDB_VERSION_RANGETRANS	   6
>> #define MOD_POLICYDB_VERSION_MLS_USERS	   6
>> #define MOD_POLICYDB_VERSION_POLCAP	   7
>> +#define MOD_POLICYDB_VERSION_USERTRANS	   8
>>
>> #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
>> -#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_POLCAP
>> +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_USERTRANS
>>
>> #define POLICYDB_CONFIG_MLS    1
>>
>> Index: libsepol/src/policydb.c
>> ===================================================================
>> --- libsepol/src/policydb.c	(revision 2854)
>> +++ libsepol/src/policydb.c	(working copy)
>> @@ -105,6 +105,12 @@
>> 	 .ocon_num = OCON_NODE6 + 1,
>> 	 },
>> 	{
>> +	 .type = POLICY_KERN,
>> +	 .version = POLICYDB_VERSION_USERTRANS,
>> +	 .sym_num = SYM_NUM,
>> +	 .ocon_num = OCON_NODE6 + 1,
>> +	 },
>> +	{
>> 	 .type = POLICY_BASE,
>> 	 .version = MOD_POLICYDB_VERSION_BASE,
>> 	 .sym_num = SYM_NUM,
>> @@ -129,6 +135,12 @@
>> 	 .ocon_num = OCON_NODE6 + 1,
>> 	 },
>> 	{
>> +	 .type = POLICY_BASE,
>> +	 .version = MOD_POLICYDB_VERSION_USERTRANS,
>> +	 .sym_num = SYM_NUM,
>> +	 .ocon_num = OCON_NODE6 + 1,
>> +	 },
>> +	{
>> 	 .type = POLICY_MOD,
>> 	 .version = MOD_POLICYDB_VERSION_BASE,
>> 	 .sym_num = SYM_NUM,
>> @@ -150,7 +162,14 @@
>> 	 .type = POLICY_MOD,
>> 	 .version = MOD_POLICYDB_VERSION_POLCAP,
>> 	 .sym_num = SYM_NUM,
>> -	 .ocon_num = 0},
>> +	 .ocon_num = 0
>> +	 },
>> +	{
>> +	 .type = POLICY_MOD,
>> +	 .version = MOD_POLICYDB_VERSION_USERTRANS,
>> +	 .sym_num = SYM_NUM,
>> +	 .ocon_num = 0
>> +	 },
>> };
>>
>> #if 0
>> @@ -348,6 +367,30 @@
>> 	}
>> }
>>
>> +void user_trans_rule_init(user_trans_rule_t * x)
>> +{
>> +	memset(x, 0, sizeof(*x));
>> +	ebitmap_init(&x->users);
>> +	type_set_init(&x->types);
>> +}
>> +
>> +void user_trans_rule_destroy(user_trans_rule_t * x)
>> +{
>> +	if (x != NULL) {
>> +		ebitmap_init(&x->users);
>> +		type_set_destroy(&x->types);
>> +	}
>> +}
>> +
>> +void user_trans_rule_list_destroy(user_trans_rule_t * x)
>> +{
>> +	while (x != NULL) {
>> +		user_trans_rule_t *next = x->next;
>> +		user_trans_rule_destroy(x);
>> +		free(x);
>> +		x = next;
>> +	}
>> +}
>> void role_allow_rule_init(role_allow_rule_t * x)
>> {
>> 	memset(x, 0, sizeof(role_allow_rule_t));
>> @@ -985,6 +1028,7 @@
>> 	unsigned int i;
>> 	role_allow_t *ra, *lra = NULL;
>> 	role_trans_t *tr, *ltr = NULL;
>> +	user_trans_t *ut, *lut = NULL;
>> 	range_trans_t *rt, *lrt = NULL;
>>
>> 	if (!p)
>> @@ -1058,6 +1102,14 @@
>> 	if (ltr)
>> 		free(ltr);
>>
>> +	for (ut = p->user_tr; ut; ut = ut->next) {
>> +		if (lut)
>> +			free(lut);
>> +		lut = ut;
>> +	}
>> +	if (lut)
>> +		free(lut);
>> +
>> 	for (ra = p->role_allow; ra; ra = ra->next) {
>> 		if (lra)
>> 			free(lra);
>> @@ -1983,6 +2035,40 @@
>> 	return 0;
>> }
>>
>> +int user_trans_read(user_trans_t ** t, struct policy_file *fp)
>> +{
>> +        unsigned int i;
>> +        uint32_t buf[3], nel;
>> +        user_trans_t *ut, *lut;
>> +        int rc;
>> +
>> +        rc = next_entry(buf, fp, sizeof(uint32_t));
>> +        if (rc < 0)
>> +                return -1;
>> +        nel = le32_to_cpu(buf[0]);
>> +        lut = NULL;
>> +        for (i = 0; i < nel; i++) {
>> +                ut = calloc(1, sizeof(struct user_trans));
>> +                if (!ut) {
>> +                        return -1;
>> +                }
>> +                if (lut) {
>> +                        lut->next = ut;
>> +                } else {
>> +                        *t = ut;
>> +                }
>> +                rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
>> +                if (rc < 0)
>> +                        return -1;
>> +                ut->user = le32_to_cpu(buf[0]);
>> +                ut->type = le32_to_cpu(buf[1]);
>> +                ut->new_user = le32_to_cpu(buf[2]);
>> +                lut = ut;
>> +        }
>> +        return 0;
>> +}
>> +
>> +
>> int role_allow_read(role_allow_t ** r, struct policy_file *fp)
>> {
>> 	unsigned int i;
>> @@ -2679,6 +2765,48 @@
>> 	return 0;
>> }
>>
>> +static int user_trans_rule_read(user_trans_rule_t ** u, struct 
>> policy_file *fp)
>> +{
>> +        uint32_t buf[1], nel;
>> +        unsigned int i;
>> +        user_trans_rule_t *ut, *lut;
>> +        int rc;
>> +
>> +        rc = next_entry(buf, fp, sizeof(uint32_t));
>> +        if (rc < 0)
>> +                return -1;
>> +        nel = le32_to_cpu(buf[0]);
>> +        lut = NULL;
>> +        for (i = 0; i < nel; i++) {
>> +                ut = malloc(sizeof(user_trans_rule_t));
>> +                if (!ut) {
>> +                        return -1;
>> +                }
>> +                user_trans_rule_init(ut);
>> +
>> +                if (lut) {
>> +                        lut->next = ut;
>> +                } else {
>> +                        *u = ut;
>> +                }
>> +
>> +                if (ebitmap_read(&ut->users, fp))
>> +                        return -1;
>> +
>> +                if (type_set_read(&ut->types, fp))
>> +                        return -1;
>> +
>> +                rc = next_entry(buf, fp, sizeof(uint32_t));
>> +                if (rc < 0)
>> +                        return -1;
>> +                ut->new_user = le32_to_cpu(buf[0]);
>> +                lut = ut;
>> +        }
>> +
>> +        return 0;
>> +}
>> +
>> +
>> static int role_allow_rule_read(role_allow_rule_t ** r, struct 
>> policy_file *fp)
>> {
>> 	unsigned int i;
>> @@ -2805,9 +2933,14 @@
>> 	if (cond_read_list(p, &decl->cond_list, fp) == -1 ||
>> 	    avrule_read_list(p, &decl->avrules, fp) == -1 ||
>> 	    role_trans_rule_read(&decl->role_tr_rules, fp) == -1 ||
>> -	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1) {
>> +	    role_allow_rule_read(&decl->role_allow_rules, fp) == -1)
>> +	    {
>> 		return -1;
>> 	}
>> +	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
>> +		if (user_trans_rule_read(&decl->user_tr_rules, fp))
>> +			return -1;
>> +	}
>> 	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
>> 	    range_trans_rule_read(&decl->range_tr_rules, fp) == -1) {
>> 		return -1;
>> @@ -3179,6 +3312,10 @@
>> 				goto bad;
>> 		if (role_trans_read(&p->role_tr, fp))
>> 			goto bad;
>> +		if (r_policyvers >= POLICYDB_VERSION_USERTRANS) {
>> +			if (user_trans_read(&p->user_tr, fp))
>> +				goto bad;
>> +		}
>> 		if (role_allow_read(&p->role_allow, fp))
>> 			goto bad;
>> 	} else {
>> Index: libsepol/src/expand.c
>> ===================================================================
>> --- libsepol/src/expand.c	(revision 2854)
>> +++ libsepol/src/expand.c	(working copy)
>> @@ -1060,6 +1060,80 @@
>> 	return 0;
>> }
>>
>> +static int copy_user_trans(expand_state_t * state, user_trans_rule_t * 
>> rules)
>> +{
>> +	unsigned int i, j;
>> +	user_trans_t *n, *l, *cur_trans;
>> +	user_trans_rule_t *cur;
>> +	ebitmap_t types;
>> +	ebitmap_node_t *rnode, *tnode;
>> +
>> +	/* start at the end of the list */
>> +	for (l = state->out->user_tr; l && l->next; l = l->next) ;
>> +
>> +	cur = rules;
>> +	while (cur) {
>> +		ebitmap_init(&types);
>> +
>> +		if (expand_convert_type_set
>> +		    (state->out, state->typemap, &cur->types, &types, 1)) {
>> +			ERR(state->handle, "Out of memory!");
>> +			return -1;
>> +		}
>> +		ebitmap_for_each_bit(&cur->users, rnode, i) {
>> +			if (!ebitmap_node_get_bit(rnode, i))
>> +				continue;
>> +			ebitmap_for_each_bit(&types, tnode, j) {
>> +				if (!ebitmap_node_get_bit(tnode, j))
>> +					continue;
>> +
>> +				cur_trans = state->out->user_tr;
>> +				while (cur_trans) {
>> +					if ((cur_trans->user == i + 1) &&
>> +					    (cur_trans->type == j + 1)) {
>> +						if (cur_trans->new_user ==
>> +						    cur->new_user) {
>> +							break;
>> +						} else {
>> +							ERR(state->handle,
>> +							    "Conflicting user trans rule %s %s : %s",
>> +							    state->out->p_user_val_to_name[i],
>> +							    state->out->p_type_val_to_name[j],
>> +							    state->out->p_user_val_to_name[cur->new_user - 1]);
>> +							return -1;
>> +						}
>> +					}
>> +					cur_trans = cur_trans->next;
>> +				}
>> +				if (cur_trans)
>> +					continue;
>> +
>> +				n = (user_trans_t *)
>> +				    malloc(sizeof(user_trans_t));
>> +				if (!n) {
>> +					ERR(state->handle, "Out of memory!");
>> +					return -1;
>> +				}
>> +				memset(n, 0, sizeof(user_trans_t));
>> +				n->user = i + 1;
>> +				n->type = j + 1;
>> +				n->new_user = cur->new_user;
>> +				if (l) {
>> +					l->next = n;
>> +				} else {
>> +					state->out->user_tr = n;
>> +				}
>> +				l = n;
>> +			}
>> +		}
>> +
>> +		ebitmap_destroy(&types);
>> +
>> +		cur = cur->next;
>> +	}
>> +	return 0;
>> +}
>> +
>> static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t 
>> tclass,
>> 			      mls_semantic_range_t * trange,
>> 			      expand_state_t * state)
>> @@ -2163,6 +2237,9 @@
>> 			goto cleanup;
>> 		}
>>
>> +		if (copy_user_trans(state, decl->user_tr_rules))
>> +			goto cleanup;
>> +
>> 		/* expand the range transition rules */
>> 		if (expand_range_trans(state, decl->range_tr_rules))
>> 			goto cleanup;
>> Index: libsepol/src/write.c
>> ===================================================================
>> --- libsepol/src/write.c	(revision 2854)
>> +++ libsepol/src/write.c	(working copy)
>> @@ -487,6 +487,31 @@
>> 	return POLICYDB_SUCCESS;
>> }
>>
>> +static int user_trans_write(user_trans_t * u, struct policy_file *fp)
>> +{
>> +	user_trans_t *tr;
>> +	uint32_t buf[3];
>> +	size_t nel, items;
>> +
>> +	nel = 0;
>> +	for (tr = u; tr; tr = tr->next)
>> +		nel++;
>> +	buf[0] = cpu_to_le32(nel);
>> +	items = put_entry(buf, sizeof(uint32_t), 1, fp);
>> +	if (items != 1)
>> +		return POLICYDB_ERROR;
>> +	for (tr = u; tr; tr = tr->next) {
>> +		buf[0] = cpu_to_le32(tr->user);
>> +		buf[1] = cpu_to_le32(tr->type);
>> +		buf[2] = cpu_to_le32(tr->new_user);
>> +		items = put_entry(buf, sizeof(uint32_t), 3, fp);
>> +		if (items != 3)
>> +			return POLICYDB_ERROR;
>> +	}
>> +
>> +	return POLICYDB_SUCCESS;
>> +}
>> +
>> static int role_allow_write(role_allow_t * r, struct policy_file *fp)
>> {
>> 	role_allow_t *ra;
>> @@ -1325,6 +1350,32 @@
>> 	return POLICYDB_SUCCESS;
>> }
>>
>> +static int user_trans_rule_write(user_trans_rule_t * t, struct 
>> policy_file *fp)
>> +{
>> +	int nel = 0;
>> +	size_t items;
>> +	uint32_t buf[1];
>> +	user_trans_rule_t *tr;
>> +
>> +	for (tr = t; tr; tr = tr->next)
>> +		nel++;
>> +	buf[0] = cpu_to_le32(nel);
>> +	items = put_entry(buf, sizeof(uint32_t), 1, fp);
>> +	if (items != 1)
>> +		return POLICYDB_ERROR;
>> +	for (tr = t; tr; tr = tr->next) {
>> +		if (ebitmap_write(&tr->users, fp))
>> +			return POLICYDB_ERROR;
>> +		if (type_set_write(&tr->types, fp))
>> +			return POLICYDB_ERROR;
>> +		buf[0] = cpu_to_le32(tr->new_user);
>> +		items = put_entry(buf, sizeof(uint32_t), 1, fp);
>> +		if (items != 1)
>> +			return POLICYDB_ERROR;
>> +	}
>> +	return POLICYDB_SUCCESS;
>> +}
>> +
>> static int role_allow_rule_write(role_allow_rule_t * r, struct 
>> policy_file *fp)
>> {
>> 	int nel = 0;
>> @@ -1414,6 +1465,10 @@
>> 	    role_allow_rule_write(decl->role_allow_rules, fp) == -1) {
>> 		return POLICYDB_ERROR;
>> 	}
>> +	if (p->policyvers >= MOD_POLICYDB_VERSION_USERTRANS) {
>> +		if (user_trans_rule_write(decl->user_tr_rules, fp))	
>> +			return POLICYDB_ERROR;
>> +	}
>> 	if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS &&
>> 	    range_trans_rule_write(decl->range_tr_rules, fp) == -1) {
>> 		return POLICYDB_ERROR;
>> @@ -1642,6 +1697,10 @@
>> 		}
>> 		if (role_trans_write(p->role_tr, fp))
>> 			return POLICYDB_ERROR;
>> +		if (p->policyvers >= POLICYDB_VERSION_USERTRANS) {
>> +			if (user_trans_write(p->user_tr, fp))
>> +				return POLICYDB_ERROR;
>> +		}
>> 		if (role_allow_write(p->role_allow, fp))
>> 			return POLICYDB_ERROR;
>> 	} else {
>> Index: libsepol/src/link.c
>> ===================================================================
>> --- libsepol/src/link.c	(revision 2854)
>> +++ libsepol/src/link.c	(working copy)
>> @@ -848,6 +848,34 @@
>> 	return -1;
>> }
>>
>> +static int user_bitmap_or_convert(ebitmap_t * users, ebitmap_t * dst,
>> +			       policy_module_t * mod, link_state_t * state)
>> +{
>> +	unsigned int i;
>> +	ebitmap_t tmp;
>> +	ebitmap_node_t *rnode;
>> +
>> +	ebitmap_init(&tmp);
>> +	ebitmap_for_each_bit(users, rnode, i) {
>> +		if (ebitmap_node_get_bit(rnode, i)) {
>> +			assert(mod->map[SYM_USERS][i]);
>> +			if (ebitmap_set_bit
>> +			    (&tmp, mod->map[SYM_USERS][i] - 1, 1)) {
>> +				goto cleanup;
>> +			}
>> +		}
>> +	}
>> +	if (ebitmap_union(dst, &tmp)) {
>> +		goto cleanup;
>> +	}
>> +	ebitmap_destroy(&tmp);
>> +	return 0;
>> +      cleanup:
>> +	ERR(state->handle, "Out of memory!");
>> +	ebitmap_destroy(&tmp);
>> +	return -1;
>> +}
>> +
>> static int mls_level_convert(mls_semantic_level_t * src, 
>> mls_semantic_level_t * dst,
>> 			     policy_module_t * mod, link_state_t * state)
>> {
>> @@ -1004,13 +1032,22 @@
>> 	link_state_t *state = (link_state_t *) data;
>> 	policy_module_t *mod = state->cur;
>> 	symtab_t *usertab;
>> +	scope_datum_t *scope;
>>
>> 	user = (user_datum_t *) datum;
>>
>> +	scope = hashtab_search(state->cur->policy->p_users_scope.table, key);
>> +	assert(scope);
>> +	if (scope->scope == SCOPE_REQ) {
>> +		//this is required user, no role or mls data
>> +		return 0;
>> +	}
>> +
>> 	if (state->dest_decl == NULL)
>> 		usertab = &state->base->p_users;
>> -	else
>> +	else {
>> 		usertab = &state->dest_decl->p_users;
>> +	}
>>
>> 	new_user = hashtab_search(usertab->table, id);
>> 	assert(new_user != NULL);
>> @@ -1173,6 +1210,49 @@
>> 	return -1;
>> }
>>
>> +static int copy_user_trans_list(user_trans_rule_t * list,
>> +                                user_trans_rule_t ** dst,
>> +                                policy_module_t * module, link_state_t 
>> * state)
>> +{
>> +        user_trans_rule_t *cur, *new_rule = NULL, *tail;
>> +
>> +        cur = list;
>> +        tail = *dst;
>> +        while (tail && tail->next) {
>> +                tail = tail->next;
>> +        }
>> +        while (cur) {
>> +                if ((new_rule =
>> +                     (user_trans_rule_t *) 
>> malloc(sizeof(user_trans_rule_t))) ==
>> +                    NULL) {
>> +                        goto cleanup;
>> +                }
>> +                user_trans_rule_init(new_rule);
>> +
>> +                if (user_bitmap_or_convert(&cur->users, 
>> &new_rule->users, module, state))
>> +			goto cleanup;
>> +		if (type_set_or_convert(&cur->types, &new_rule->types, module, state)) {
>> +                        goto cleanup;
>> +                }
>> +
>> +                new_rule->new_user = 
>> module->map[SYM_USERS][cur->new_user - 1];
>> +
>> +                if (*dst == NULL) {
>> +                        *dst = new_rule;
>> +                } else {
>> +                        tail->next = new_rule;
>> +                }
>> +                tail = new_rule;
>> +                cur = cur->next;
>> +        }
>> +        return 0;
>> +      cleanup:
>> +        ERR(state->handle, "Out of memory!");
>> +        user_trans_rule_list_destroy(new_rule);
>> +        return -1;
>> +}
>> +
>> +
>> static int copy_role_allow_list(role_allow_rule_t * list,
>> 				role_allow_rule_t ** dst,
>> 				policy_module_t * module, link_state_t * state)
>> @@ -1446,6 +1526,10 @@
>> 		return -1;
>> 	}
>>
>> +	if (copy_user_trans_list(src_decl->user_tr_rules, 
>> &dest_decl->user_tr_rules,
>> +				 module, state))
>> +		return -1;
>> +
>> 	if (copy_range_trans_list(src_decl->range_tr_rules,
>> 				  &dest_decl->range_tr_rules, module, state))
>> 		return -1;
>> Index: checkpolicy/test/dismod.c
>> ===================================================================
>> --- checkpolicy/test/dismod.c	(revision 2854)
>> +++ checkpolicy/test/dismod.c	(working copy)
>> @@ -354,6 +354,21 @@
>> 	return 0;
>> }
>>
>> +int display_user_set(ebitmap_t *u, policydb_t *p, FILE *fp)
>> +{
>> +	ebitmap_node_t *node;
>> +	int i;
>> +
>> +	fprintf(fp, " { ");
>> +	ebitmap_for_each_bit(u, node, i) {
>> +		if (ebitmap_node_get_bit(node, i)) {
>> +			display_id(p, fp, SYM_USERS, i, "");
>> +		}
>> +	}
>> +	fprintf(fp, " } ");
>> +	return 0;
>> +}
>> +
>> int display_bools(policydb_t * p, FILE * fp)
>> {
>> 	int i;
>> @@ -461,7 +476,18 @@
>> 		fprintf(fp, "\n");
>> 	}
>> }
>> +void display_user_trans(user_trans_rule_t * tr, policydb_t * p, FILE * fp)
>>
>> +{
>> +	for (; tr; tr = tr->next) {
>> +		fprintf(fp, "user transition ");
>> +		display_user_set(&tr->users, p, fp);
>> +		display_type_set(&tr->types, 0, p, fp);
>> +		display_id(p, fp, SYM_USERS, tr->new_user - 1, " :");
>> +		fprintf(fp, "\n");
>> +	}
>> +}
>> +
>> void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp)
>> {
>> 	for (; ra; ra = ra->next) {
>> @@ -641,6 +667,10 @@
>> 			}
>> 			break;
>> 		}
>> +	case 7:{
>> +			display_user_trans(decl->user_tr_rules, policy, out_fp);
>> +			break;
>> +		}
>> 	default:{
>> 			assert(0);
>> 		}
>> @@ -806,6 +836,7 @@
>> 	printf("c)  Display policy capabilities\n");
>> 	printf("l)  Link in a module\n");
>> 	printf("u)  Display the unknown handling setting\n");
>> +	printf("U)  Display user transitions\n");
>> 	printf("\n");
>> 	printf("f)  set output file\n");
>> 	printf("m)  display menu\n");
>> @@ -918,9 +949,11 @@
>> 			display_policycaps(&policydb, out_fp);
>> 			break;
>> 		case 'u':
>> -		case 'U':
>> 			display_handle_unknown(&policydb, out_fp);
>> 			break;
>> +		case 'U':
>> +			display_avblock(7, 0, &policydb, out_fp);
>> +			break;
>> 		case 'f':
>> 			printf
>> 			    ("\nFilename for output (<CR> for screen output): ");
>> Index: checkpolicy/test/dispol.c
>> ===================================================================
>> --- checkpolicy/test/dispol.c	(revision 2854)
>> +++ checkpolicy/test/dispol.c	(working copy)
>> @@ -299,6 +299,18 @@
>> 	return 0;
>> }
>>
>> +static void display_user_transitions(policydb_t *p, FILE *fp)
>> +{
>> +	user_trans_t *cur;
>> +	for (cur = p->user_tr; cur; cur = cur->next) {
>> +		fprintf(fp, "user_transition ");
>> +		fprintf(fp, "%s %s %s;\n",
>> +			p->p_user_val_to_name[cur->user - 1],
>> +			p->p_type_val_to_name[cur->type - 1],
>> +			p->p_user_val_to_name[cur->new_user - 1]);
>> +	}
>> +}
>> +
>> static void display_policycaps(policydb_t * p, FILE * fp)
>> {
>> 	ebitmap_node_t *node;
>> @@ -332,6 +344,7 @@
>> 	printf("\n");
>> 	printf("c)  display policy capabilities\n");
>> 	printf("u)  display unknown handling setting\n");
>> +	printf("U)  display user transitions\n");
>> 	printf("f)  set output file\n");
>> 	printf("m)  display menu\n");
>> 	printf("q)  quit\n");
>> @@ -448,9 +461,11 @@
>> 			display_policycaps(&policydb, out_fp);
>> 			break;
>> 		case 'u':
>> -		case 'U':
>> 			display_handle_unknown(&policydb, out_fp);
>> 			break;
>> +		case 'U':
>> +			display_user_transitions(&policydb, out_fp);
>> +			break;
>> 		case 'f':
>> 			printf
>> 			    ("\nFilename for output (<CR> for screen output): ");
>> Index: checkpolicy/test/Makefile
>> ===================================================================
>> --- checkpolicy/test/Makefile	(revision 2854)
>> +++ checkpolicy/test/Makefile	(working copy)
>> @@ -6,7 +6,7 @@
>> LIBDIR=$(PREFIX)/lib
>> INCLUDEDIR ?= $(PREFIX)/include
>>
>> -CFLAGS ?= -g -Wall -O2 -pipe
>> +CFLAGS ?= -g3 -gdwarf-2 -Wall -O0 -pipe
>> override CFLAGS += -I$(INCLUDEDIR)
>>
>> LDLIBS=-lfl -lsepol -lselinux $(LIBDIR)/libsepol.a -L$(LIBDIR)
>> Index: checkpolicy/policy_define.c
>> ===================================================================
>> --- checkpolicy/policy_define.c	(revision 2854)
>> +++ checkpolicy/policy_define.c	(working copy)
>> @@ -2020,6 +2020,76 @@
>> 	return -1;
>> }
>>
>> +int define_user_trans(void)
>> +{
>> +        char *id;
>> +        user_datum_t *user, *u;
>> +	ebitmap_t users;
>> +        type_set_t types;
>> +        struct user_trans_rule *rule = NULL;
>> +        int add = 1;
>> +
>> +        if (pass == 1) {
>> +                while ((id = queue_remove(id_queue)))
>> +                        free(id);
>> +                while ((id = queue_remove(id_queue)))
>> +                        free(id);
>> +                id = queue_remove(id_queue);
>> +                free(id);
>> +                return 0;
>> +        }
>> +
>> +        ebitmap_init(&users);
>> +        type_set_init(&types);
>> +
>> +	while ((id = queue_remove(id_queue))) {
>> +		u = hashtab_search(policydbp->p_users.table, id);
>> +		if (!u) {
>> +			yyerror2("unknown user %s", id);
>> +			free(id);
>> +			return -1;
>> +		}
>> +		if (ebitmap_set_bit(&users, u->s.value - 1, TRUE))
>> +			return -1;
>> +	}
>> +	while ((id = queue_remove(id_queue))) {
>> +		if (set_types(&types, id, &add, 0))
>> +			return -1;
>> +	}
>> +	id = (char *)queue_remove(id_queue);
>> +	if (!id) {
>> +		yyerror("no new user in transition definition?");
>> +		goto bad;
>> +	}
>> +	if (!is_id_in_scope(SYM_USERS, id)) {
>> +		yyerror2("user %s is not within scope", id);
>> +		free(id);
>> +		goto bad;
>> +	}
>> +	user = hashtab_search(policydbp->p_users.table, id);
>> +	if (!user) {
>> +		yyerror2("unknown user %s used in transition definition", id);
>> +		goto bad;
>> +	}
>> +	rule = malloc(sizeof(struct user_trans_rule));
>> +	if (!rule) {
>> +		yyerror("out of memory");
>> +		return -1;
>> +	}
>> +	memset(rule, 0, sizeof(struct user_trans_rule));
>> +	rule->users = users;
>> +	rule->types = types;
>> +	rule->new_user = user->s.value;
>> +
>> +	append_user_trans(rule);
>> +
>> +	return 0;
>> +
>> +      bad:
>> +	return -1;
>> +}
>> +
>> +
>> int define_role_allow(void)
>> {
>> 	char *id;
>> Index: checkpolicy/policy_scan.l
>> ===================================================================
>> --- checkpolicy/policy_scan.l	(revision 2854)
>> +++ checkpolicy/policy_scan.l	(working copy)
>> @@ -102,6 +102,8 @@
>> type_change			{ return(TYPE_CHANGE); }
>> ROLE_TRANSITION |
>> role_transition			{ return(ROLE_TRANSITION); }
>> +USER_TRANSITION |
>> +user_transition			{ return(USER_TRANSITION); }
>> RANGE_TRANSITION |
>> range_transition		{ return(RANGE_TRANSITION); }
>> SENSITIVITY |
>> Index: checkpolicy/policy_define.h
>> ===================================================================
>> --- checkpolicy/policy_define.h	(revision 2854)
>> +++ checkpolicy/policy_define.h	(working copy)
>> @@ -42,6 +42,7 @@
>> int define_role_allow(void);
>> int define_role_trans(void);
>> int define_role_types(void);
>> +int define_user_trans(void);
>> int define_sens(void);
>> int define_te_avtab(int which);
>> int define_typealias(void);
>> Index: checkpolicy/module_compiler.c
>> ===================================================================
>> --- checkpolicy/module_compiler.c	(revision 2854)
>> +++ checkpolicy/module_compiler.c	(working copy)
>> @@ -1214,6 +1214,17 @@
>> 	decl->role_tr_rules = role_tr_rules;
>> }
>>
>> +void append_user_trans(user_trans_rule_t * user_tr_rules)
>> +{
>> +	avrule_decl_t *decl = stack_top->decl;
>> +
>> +	/* role transitions are not allowed within conditionals */
>> +	assert(stack_top->type == 1);
>> +
>> +	user_tr_rules->next = decl->user_tr_rules;
>> +	decl->user_tr_rules = user_tr_rules;
>> +}
>> +
>> /* this doesn't actually append, but really prepends it */
>> void append_role_allow(role_allow_rule_t * role_allow_rules)
>> {
>> Index: checkpolicy/policy_parse.y
>> ===================================================================
>> --- checkpolicy/policy_parse.y	(revision 2854)
>> +++ checkpolicy/policy_parse.y	(working copy)
>> @@ -103,6 +103,7 @@
>> %token TYPE_MEMBER
>> %token TYPE_CHANGE
>> %token ROLE_TRANSITION
>> +%token USER_TRANSITION
>> %token RANGE_TRANSITION
>> %token SENSITIVITY
>> %token DOMINANCE
>> @@ -261,6 +262,7 @@
>>                          | transition_def
>>                          | range_trans_def
>>                          | te_avtab_def
>> +			| user_trans_def
>> 			;
>> attribute_def           : ATTRIBUTE identifier ';'
>>                          { if (define_attrib()) return -1;}
>> @@ -411,6 +413,9 @@
>> role_trans_def		: ROLE_TRANSITION names names identifier ';'
>> 			{if (define_role_trans()) return -1; }
>> 			;
>> +user_trans_def		: USER_TRANSITION names names identifier ';'
>> +			{ if (define_user_trans()) return -1; }
>> +			;
>> role_allow_def		: ALLOW names names ';'
>> 			{if (define_role_allow()) return -1; }
>> 			;
>> Index: checkpolicy/module_compiler.h
>> ===================================================================
>> --- checkpolicy/module_compiler.h	(revision 2854)
>> +++ checkpolicy/module_compiler.h	(working copy)
>> @@ -80,6 +80,7 @@
>> void append_role_trans(role_trans_rule_t * role_tr_rules);
>> void append_role_allow(role_allow_rule_t * role_allow_rules);
>> void append_range_trans(range_trans_rule_t * range_tr_rules);
>> +void append_user_trans(user_trans_rule_t * user_tr_rules);
>>
>> /* Create a new optional block and add it to the global policy.
>>   * During the second pass resolve the block's requirements.  Return 0
>>
>>

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iEYEARECAAYFAkfqDBQACgkQrlYvE4MpobNITACfVxCGgzhZqkqNE4YfgIa1Gt/T
z1kAn2Y7kxJFDnimNarKxbZyafpZzlJR
=xZWX
-----END PGP SIGNATURE-----

--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25 12:08         ` Stephen Smalley
  2008-03-25 13:01           ` Christopher J. PeBenito
@ 2008-03-26  8:46           ` Daniel J Walsh
  2008-03-26 13:36             ` Stephen Smalley
  2008-03-27  4:43             ` Russell Coker
  1 sibling, 2 replies; 27+ messages in thread
From: Daniel J Walsh @ 2008-03-26  8:46 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: Joshua Brindle, SE Linux, Caleb Case, Christopher J. PeBenito

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Stephen Smalley wrote:
> On Tue, 2008-03-25 at 07:04 -0400, Joshua Brindle wrote:
>> Stephen Smalley wrote:
>>> On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
>>>   
>>>> Stephen Smalley wrote:
>>>>     
>>>>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>>>>>   
>>>>>       
>>>>>> This implements user_transition in the toolchain. It should help on
>>>>>> distro's like Ubuntu that can't use run_init due to the user not knowing
>>>>>> the root password. It also seems like a more eloquent way to handle
>>>>>> service restarts than assigning system_r to user accounts and having the
>>>>>> daemons run as someuser:system_r:foo_t.
>>>>>>     
>>>>>>         
>>>>> Yes, that's something that has been wanted in Fedora for quite some
>>>>> time.
>>>>>
>>>>> The real issue with run_init isn't the re-authentication stage, as that
>>>>> can always be disabled via pam config (and was just a weak form of
>>>>> confirming user intent, not an authorization mechanism), but rather the
>>>>> difficulty in transparently interposing it into all situations where
>>>>> services get started/re-started.  Only Gentoo seemed to have a good
>>>>> story there.
>>>>>
>>>>>   
>>>>>       
>>>>>> This has some issues in policy due to users not always being known in
>>>>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>>>>>> give some suggestions there.
>>>>>>     
>>>>>>         
>>>>> I'm not sure why anyone needs to add users to policy via semanage users
>>>>> given the base set of generic users and the ability to map Linux users
>>>>> to them via seusers aka semanage login.
>>>>>
>>>>>   
>>>>>       
>>>>>> The kernel patch (forthcoming after this is accepted) so far only
>>>>>> implements the transition on process transitions. Later on I plan on
>>>>>> doing a patch to expand role_transition to object classes (this is a
>>>>>> change needed for policy rbac support to work). I suspect I'll do the
>>>>>> same for user at that time. The question here is, do we think its worth
>>>>>> it to do fine grained transitions like we did for range_trans? (I don't).
>>>>>>     
>>>>>>         
>>>>> Offhand, I can't see a use for per-class user transitions, if that is
>>>>> what you mean.
>>>>>
>>>>> I don't think per-class role transitions is really the fundamental
>>>>> obstacle to enabling use of roles on objects - more thought is required
>>>>> there.  What will be fun there is role/type and user/range validation,
>>>>> which presently gets to ignore everything that has object_r.
>>>>>   
>>>>>       
>>>> Ah, another thing. While going through the policyrep implementation the 
>>>> question of object_r came up. My thought is to start adding object_r 
>>>> magic into the toolchain (adding all types, etc) and eventually purge 
>>>> object_r from the kernel. at least one magic instance of object_r will 
>>>> be removed by object role_transitions, the others are really short 
>>>> circuits in the security server that can be removed after sufficient 
>>>> support is in the toolchain. What are your thoughts on that (for future 
>>>> reference)?
>>>>     
>>> Well, the interesting question is what should the default role be in the
>>> new context in security_compute_sid, if not object_r.  Even aside from
>>> the support for per-class role transitions.  User defaults to the source
>>> context, type defaults to the related object context, and MLS range
>>> defaults to the low level of the source context.  Role could be the
>>> subject's role or the related object's role.
>>>
>>>   
>> Good question. My original assumption was that we'd use the related 
>> object role. That would require that home directories be correctly 
>> labeled with the role of the user. If we start using the source role 
>> then things will quickly change from object_r to system_r, so maybe the 
>> policy should do that anyway. Chris, any opinions on this?
> 
> Yes, related object role would likely cause the least breakage.  It
> would preserve the existing default for existing filesystems (as they
> already have object_r in the directory contexts), while allowing us to
> switch over to the user's role for home directories upon a relabel or
> new filesystem.  Source role might create more conflicts, as we enforce
> the role/type relationship for contexts and there might be a mismatch
> between the creating process role and the parent directory type.
> 
I am not sure where this is going, but I believe that separation based
on role in the home directory is a mistake.  It assumes that the home
directory will always be used by the same user with the same role.   And
will not work when you have a network file system that supports labels.

In Red Hat I can login to people.redhat.com people.fedoraproject.com
which I should use the guest_r.  While logging into my laptop I would be
unconfined_t and on test machines I might get staff_r or user_r.  All of
them would use the same homedirectory.  So how would this work in this
environment?

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iEYEARECAAYFAkfqDU8ACgkQrlYvE4MpobPK2QCZARp10Z4BcqTHKGywNPo49F06
uJoAoLMYX3lHtyZkzDpS+BquTBFT4uoZ
=/URn
-----END PGP SIGNATURE-----

--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-25 20:50   ` Joshua Brindle
@ 2008-03-26 12:48     ` Stephen Smalley
  2008-03-26 13:29       ` Joshua Brindle
  0 siblings, 1 reply; 27+ messages in thread
From: Stephen Smalley @ 2008-03-26 12:48 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: SE Linux, Caleb Case


On Tue, 2008-03-25 at 16:50 -0400, Joshua Brindle wrote:
> Stephen Smalley wrote:
> > On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> >   
> >> This implements user_transition in the toolchain. It should help on
> >> distro's like Ubuntu that can't use run_init due to the user not knowing
> >> the root password. It also seems like a more eloquent way to handle
> >> service restarts than assigning system_r to user accounts and having the
> >> daemons run as someuser:system_r:foo_t.
> >>
> >> This has some issues in policy due to users not always being known in
> >> the policy (eg., semanage users). I hope Chris or Dan will be able to
> >> give some suggestions there.
> >>
> >> The kernel patch (forthcoming after this is accepted) so far only
> >> implements the transition on process transitions. Later on I plan on
> >> doing a patch to expand role_transition to object classes (this is a
> >> change needed for policy rbac support to work). I suspect I'll do the
> >> same for user at that time. The question here is, do we think its worth
> >> it to do fine grained transitions like we did for range_trans? (I don't).
> >>
> >> Index: libsepol/include/sepol/policydb/policydb.h
> >> ===================================================================
> >> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
> >> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
> >> @@ -156,6 +156,14 @@
> >> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
> >> } user_datum_t;
> >>
> >> +typedef struct user_trans {
> >> +	uint32_t user;		/* current role */
> >> +	uint32_t type;		/* program executable type */
> >> +	uint32_t new_user;	/* new role */
> >> +	struct user_trans *next;
> >> +} user_trans_t;
> >> +
> >> +
> >> /* Sensitivity attributes */
> >> typedef struct level_datum {
> >> 	mls_level_t *level;	/* sensitivity and associated categories */
> >> @@ -225,6 +233,13 @@
> >> 	struct role_trans_rule *next;
> >> } role_trans_rule_t;
> >>
> >> +typedef struct user_trans_rule {
> >> +	ebitmap_t users;	/* current role */
> >> +	type_set_t types;	/* program executable type */
> >> +	uint32_t new_user;	/* new role */
> >> +	struct user_trans_rule *next;
> >> +} user_trans_rule_t;
> >>     
> >
> > Possibly crazy idea - given the current trend, would it be better to
> > just save the user transition rules in symbolic form in the module
> > format.  Would that simplify the link/expand code?
> >
> >   
> 
> Possibly, I am hoping policyrep will supplant this code in the near 
> future so I didn't think about it much. This is consistent with how we 
> store other modular things.
> 
> >> Index: libsepol/src/policydb.c
> >> ===================================================================
> >> --- libsepol/src/policydb.c	(revision 2854)
> >> +++ libsepol/src/policydb.c	(working copy)
> >> @@ -348,6 +367,30 @@
> >> 	}
> >> }
> >>
> >> +void user_trans_rule_init(user_trans_rule_t * x)
> >> +{
> >> +	memset(x, 0, sizeof(*x));
> >>     
> >
> > Not unique to this patch, but it seems funny that we use memset followed
> > by explicit initializers for fields that have them.  And that as a
> > result of the memset here, we don't calloc when allocate the structs.
> >
> >   
> 
> I would normally never memset a struct, rather than use an initializer 
> but I was going for minimal changes here, I don't plan on this code 
> being around for long.

Famous last words.  Don't ever make that assumption ;)
Especially given life cycles of distributions that might incorporate
said code.

I know that this is consistent with how we store other modular things
and that policyrep will "make all things better".  But I'm wondering
whether you could have greatly simplified even this "transient"
implementation of user transition support by keeping it in symbolic
form, even within a "binary" module format, to simplify linking and
reduce likelihood of mapping errors.

> >> +	ebitmap_init(&x->users);
> >> +	type_set_init(&x->types);
> >> +}
> >> +
> >> +void user_trans_rule_destroy(user_trans_rule_t * x)
> >> +{
> >> +	if (x != NULL) {
> >> +		ebitmap_init(&x->users);
> >>     
> >
> > Should be ebitmap_destroy, right?
> >
> >   
> Oops, yes
> 
> >> +		type_set_destroy(&x->types);
> >> +	}
> >> +}
> >> +
> >>     
> >
> > Usual boilerplate - make sure it runs under valgrind cleanly and doesn't
> > introduce any (new) leaks on monolithic and modular build+link
> 
> This was an RFC patch and didn't go through any rigorous testing or 
> valgrind (though I did ask for comments..) I recently found a bug in it 
> so there will be another patch soon. Thanks for the comments.
> 
> 
> --
> 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.
-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26 12:48     ` Stephen Smalley
@ 2008-03-26 13:29       ` Joshua Brindle
  2008-03-26 13:41         ` Stephen Smalley
  0 siblings, 1 reply; 27+ messages in thread
From: Joshua Brindle @ 2008-03-26 13:29 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: SE Linux, Caleb Case

Stephen Smalley wrote:
> On Tue, 2008-03-25 at 16:50 -0400, Joshua Brindle wrote:
>   
>> Stephen Smalley wrote:
>>     
>>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>>>   
>>>       
>>>> This implements user_transition in the toolchain. It should help on
>>>> distro's like Ubuntu that can't use run_init due to the user not knowing
>>>> the root password. It also seems like a more eloquent way to handle
>>>> service restarts than assigning system_r to user accounts and having the
>>>> daemons run as someuser:system_r:foo_t.
>>>>
>>>> This has some issues in policy due to users not always being known in
>>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>>>> give some suggestions there.
>>>>
>>>> The kernel patch (forthcoming after this is accepted) so far only
>>>> implements the transition on process transitions. Later on I plan on
>>>> doing a patch to expand role_transition to object classes (this is a
>>>> change needed for policy rbac support to work). I suspect I'll do the
>>>> same for user at that time. The question here is, do we think its worth
>>>> it to do fine grained transitions like we did for range_trans? (I don't).
>>>>
>>>> Index: libsepol/include/sepol/policydb/policydb.h
>>>> ===================================================================
>>>> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
>>>> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
>>>> @@ -156,6 +156,14 @@
>>>> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
>>>> } user_datum_t;
>>>>
>>>> +typedef struct user_trans {
>>>> +	uint32_t user;		/* current role */
>>>> +	uint32_t type;		/* program executable type */
>>>> +	uint32_t new_user;	/* new role */
>>>> +	struct user_trans *next;
>>>> +} user_trans_t;
>>>> +
>>>> +
>>>> /* Sensitivity attributes */
>>>> typedef struct level_datum {
>>>> 	mls_level_t *level;	/* sensitivity and associated categories */
>>>> @@ -225,6 +233,13 @@
>>>> 	struct role_trans_rule *next;
>>>> } role_trans_rule_t;
>>>>
>>>> +typedef struct user_trans_rule {
>>>> +	ebitmap_t users;	/* current role */
>>>> +	type_set_t types;	/* program executable type */
>>>> +	uint32_t new_user;	/* new role */
>>>> +	struct user_trans_rule *next;
>>>> +} user_trans_rule_t;
>>>>     
>>>>         
>>> Possibly crazy idea - given the current trend, would it be better to
>>> just save the user transition rules in symbolic form in the module
>>> format.  Would that simplify the link/expand code?
>>>
>>>   
>>>       
>> Possibly, I am hoping policyrep will supplant this code in the near 
>> future so I didn't think about it much. This is consistent with how we 
>> store other modular things.
>>
>>     
>>>> Index: libsepol/src/policydb.c
>>>> ===================================================================
>>>> --- libsepol/src/policydb.c	(revision 2854)
>>>> +++ libsepol/src/policydb.c	(working copy)
>>>> @@ -348,6 +367,30 @@
>>>> 	}
>>>> }
>>>>
>>>> +void user_trans_rule_init(user_trans_rule_t * x)
>>>> +{
>>>> +	memset(x, 0, sizeof(*x));
>>>>     
>>>>         
>>> Not unique to this patch, but it seems funny that we use memset followed
>>> by explicit initializers for fields that have them.  And that as a
>>> result of the memset here, we don't calloc when allocate the structs.
>>>
>>>   
>>>       
>> I would normally never memset a struct, rather than use an initializer 
>> but I was going for minimal changes here, I don't plan on this code 
>> being around for long.
>>     
>
> Famous last words.  Don't ever make that assumption ;)
> Especially given life cycles of distributions that might incorporate
> said code.
>   

I know, I typed it tongue-in-cheek.

> I know that this is consistent with how we store other modular things
> and that policyrep will "make all things better".  But I'm wondering
> whether you could have greatly simplified even this "transient"
> implementation of user transition support by keeping it in symbolic
> form, even within a "binary" module format, to simplify linking and
> reduce likelihood of mapping errors.
>
>   

I understand and if there were more time I wouldn't mind doing it. Right 
now I wanted to push these through as fast as possible so that we could 
maybe get them in to Hardy, which as of right now has no solution to 
restart services other than rebooting.

This method is well understood in this codebase and chances are in 
mapping is broken one place its broken in five so I'm not entirely sure 
what it would gain us now.

On the note of getting this out quickly I'm hitting this strange kernel 
but where class_read says a common is unknown when I try to load a 23 
policy, I'm currently working through that but building ubuntu kernels 
takes hours :X

>>>> +	ebitmap_init(&x->users);
>>>> +	type_set_init(&x->types);
>>>> +}
>>>> +
>>>> +void user_trans_rule_destroy(user_trans_rule_t * x)
>>>> +{
>>>> +	if (x != NULL) {
>>>> +		ebitmap_init(&x->users);
>>>>     
>>>>         
>>> Should be ebitmap_destroy, right?
>>>
>>>   
>>>       
>> Oops, yes
>>
>>     
>>>> +		type_set_destroy(&x->types);
>>>> +	}
>>>> +}
>>>> +
>>>>     
>>>>         
>>> Usual boilerplate - make sure it runs under valgrind cleanly and doesn't
>>> introduce any (new) leaks on monolithic and modular build+link
>>>       
>> This was an RFC patch and didn't go through any rigorous testing or 
>> valgrind (though I did ask for comments..) I recently found a bug in it 
>> so there will be another patch soon. Thanks for the comments.
>>
>>
>> --
>> 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.
>>     



--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26  8:40   ` Daniel J Walsh
@ 2008-03-26 13:33     ` Stephen Smalley
  0 siblings, 0 replies; 27+ messages in thread
From: Stephen Smalley @ 2008-03-26 13:33 UTC (permalink / raw)
  To: Daniel J Walsh; +Cc: Joshua Brindle, SE Linux, Caleb Case


On Wed, 2008-03-26 at 09:40 +0100, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Stephen Smalley wrote:
> > On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> >> This implements user_transition in the toolchain. It should help on
> >> distro's like Ubuntu that can't use run_init due to the user not knowing
> >> the root password. It also seems like a more eloquent way to handle
> >> service restarts than assigning system_r to user accounts and having the
> >> daemons run as someuser:system_r:foo_t.
> > 
> > Yes, that's something that has been wanted in Fedora for quite some
> > time.
> > 
> > The real issue with run_init isn't the re-authentication stage, as that
> > can always be disabled via pam config (and was just a weak form of
> > confirming user intent, not an authorization mechanism), but rather the
> > difficulty in transparently interposing it into all situations where
> > services get started/re-started.  Only Gentoo seemed to have a good
> > story there.
> > 
> >> This has some issues in policy due to users not always being known in
> >> the policy (eg., semanage users). I hope Chris or Dan will be able to
> >> give some suggestions there.
> > 
> > I'm not sure why anyone needs to add users to policy via semanage users
> > given the base set of generic users and the ability to map Linux users
> > to them via seusers aka semanage login.
> > 
> Can we define users in modules?  I envision and have provided
> modifications to do system-config-selinux for someone to take a guest_t
> and create a new role/type guest_plussendmail_t for a limited privileged
> login account that can connect to the sendmail port.
> 
> So once I have created this new User Type,  I need a way to define the
> user.  In Fedora right now, we define the xguest and guest accounts in
> the postinstall using semanage.

You can already define SELinux users in modules (after any TE/RBAC
rules).

-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26  8:46           ` Daniel J Walsh
@ 2008-03-26 13:36             ` Stephen Smalley
  2008-03-27 19:42               ` Daniel J Walsh
  2008-03-27  4:43             ` Russell Coker
  1 sibling, 1 reply; 27+ messages in thread
From: Stephen Smalley @ 2008-03-26 13:36 UTC (permalink / raw)
  To: Daniel J Walsh
  Cc: Joshua Brindle, SE Linux, Caleb Case, Christopher J. PeBenito


On Wed, 2008-03-26 at 09:46 +0100, Daniel J Walsh wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Stephen Smalley wrote:
> > On Tue, 2008-03-25 at 07:04 -0400, Joshua Brindle wrote:
> >> Stephen Smalley wrote:
> >>> On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
> >>>   
> >>>> Stephen Smalley wrote:
> >>>>     
> >>>>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> >>>>>   
> >>>>>       
> >>>>>> This implements user_transition in the toolchain. It should help on
> >>>>>> distro's like Ubuntu that can't use run_init due to the user not knowing
> >>>>>> the root password. It also seems like a more eloquent way to handle
> >>>>>> service restarts than assigning system_r to user accounts and having the
> >>>>>> daemons run as someuser:system_r:foo_t.
> >>>>>>     
> >>>>>>         
> >>>>> Yes, that's something that has been wanted in Fedora for quite some
> >>>>> time.
> >>>>>
> >>>>> The real issue with run_init isn't the re-authentication stage, as that
> >>>>> can always be disabled via pam config (and was just a weak form of
> >>>>> confirming user intent, not an authorization mechanism), but rather the
> >>>>> difficulty in transparently interposing it into all situations where
> >>>>> services get started/re-started.  Only Gentoo seemed to have a good
> >>>>> story there.
> >>>>>
> >>>>>   
> >>>>>       
> >>>>>> This has some issues in policy due to users not always being known in
> >>>>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
> >>>>>> give some suggestions there.
> >>>>>>     
> >>>>>>         
> >>>>> I'm not sure why anyone needs to add users to policy via semanage users
> >>>>> given the base set of generic users and the ability to map Linux users
> >>>>> to them via seusers aka semanage login.
> >>>>>
> >>>>>   
> >>>>>       
> >>>>>> The kernel patch (forthcoming after this is accepted) so far only
> >>>>>> implements the transition on process transitions. Later on I plan on
> >>>>>> doing a patch to expand role_transition to object classes (this is a
> >>>>>> change needed for policy rbac support to work). I suspect I'll do the
> >>>>>> same for user at that time. The question here is, do we think its worth
> >>>>>> it to do fine grained transitions like we did for range_trans? (I don't).
> >>>>>>     
> >>>>>>         
> >>>>> Offhand, I can't see a use for per-class user transitions, if that is
> >>>>> what you mean.
> >>>>>
> >>>>> I don't think per-class role transitions is really the fundamental
> >>>>> obstacle to enabling use of roles on objects - more thought is required
> >>>>> there.  What will be fun there is role/type and user/range validation,
> >>>>> which presently gets to ignore everything that has object_r.
> >>>>>   
> >>>>>       
> >>>> Ah, another thing. While going through the policyrep implementation the 
> >>>> question of object_r came up. My thought is to start adding object_r 
> >>>> magic into the toolchain (adding all types, etc) and eventually purge 
> >>>> object_r from the kernel. at least one magic instance of object_r will 
> >>>> be removed by object role_transitions, the others are really short 
> >>>> circuits in the security server that can be removed after sufficient 
> >>>> support is in the toolchain. What are your thoughts on that (for future 
> >>>> reference)?
> >>>>     
> >>> Well, the interesting question is what should the default role be in the
> >>> new context in security_compute_sid, if not object_r.  Even aside from
> >>> the support for per-class role transitions.  User defaults to the source
> >>> context, type defaults to the related object context, and MLS range
> >>> defaults to the low level of the source context.  Role could be the
> >>> subject's role or the related object's role.
> >>>
> >>>   
> >> Good question. My original assumption was that we'd use the related 
> >> object role. That would require that home directories be correctly 
> >> labeled with the role of the user. If we start using the source role 
> >> then things will quickly change from object_r to system_r, so maybe the 
> >> policy should do that anyway. Chris, any opinions on this?
> > 
> > Yes, related object role would likely cause the least breakage.  It
> > would preserve the existing default for existing filesystems (as they
> > already have object_r in the directory contexts), while allowing us to
> > switch over to the user's role for home directories upon a relabel or
> > new filesystem.  Source role might create more conflicts, as we enforce
> > the role/type relationship for contexts and there might be a mismatch
> > between the creating process role and the parent directory type.
> > 
> I am not sure where this is going, but I believe that separation based
> on role in the home directory is a mistake.  It assumes that the home
> directory will always be used by the same user with the same role.   And
> will not work when you have a network file system that supports labels.
> 
> In Red Hat I can login to people.redhat.com people.fedoraproject.com
> which I should use the guest_r.  While logging into my laptop I would be
> unconfined_t and on test machines I might get staff_r or user_r.  All of
> them would use the same homedirectory.  So how would this work in this
> environment?

That's an interesting question, and I know that in some operating
systems, roles are actually separate user accounts altogether.

However, the mechanism being described here doesn't prevent you from
continuing to use a generic role (object_r or otherwise) on all files;
it just allows for people who want to apply distinct roles on files to
do so.

-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26 13:29       ` Joshua Brindle
@ 2008-03-26 13:41         ` Stephen Smalley
  2008-03-26 13:57           ` Stephen Smalley
  0 siblings, 1 reply; 27+ messages in thread
From: Stephen Smalley @ 2008-03-26 13:41 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: SE Linux, Caleb Case


On Wed, 2008-03-26 at 09:29 -0400, Joshua Brindle wrote:
> Stephen Smalley wrote:
> > On Tue, 2008-03-25 at 16:50 -0400, Joshua Brindle wrote:
> >   
> >> Stephen Smalley wrote:
> >>     
> >>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> >>>   
> >>>       
> >>>> This implements user_transition in the toolchain. It should help on
> >>>> distro's like Ubuntu that can't use run_init due to the user not knowing
> >>>> the root password. It also seems like a more eloquent way to handle
> >>>> service restarts than assigning system_r to user accounts and having the
> >>>> daemons run as someuser:system_r:foo_t.
> >>>>
> >>>> This has some issues in policy due to users not always being known in
> >>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
> >>>> give some suggestions there.
> >>>>
> >>>> The kernel patch (forthcoming after this is accepted) so far only
> >>>> implements the transition on process transitions. Later on I plan on
> >>>> doing a patch to expand role_transition to object classes (this is a
> >>>> change needed for policy rbac support to work). I suspect I'll do the
> >>>> same for user at that time. The question here is, do we think its worth
> >>>> it to do fine grained transitions like we did for range_trans? (I don't).
> >>>>
> >>>> Index: libsepol/include/sepol/policydb/policydb.h
> >>>> ===================================================================
> >>>> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
> >>>> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
> >>>> @@ -156,6 +156,14 @@
> >>>> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
> >>>> } user_datum_t;
> >>>>
> >>>> +typedef struct user_trans {
> >>>> +	uint32_t user;		/* current role */
> >>>> +	uint32_t type;		/* program executable type */
> >>>> +	uint32_t new_user;	/* new role */
> >>>> +	struct user_trans *next;
> >>>> +} user_trans_t;
> >>>> +
> >>>> +
> >>>> /* Sensitivity attributes */
> >>>> typedef struct level_datum {
> >>>> 	mls_level_t *level;	/* sensitivity and associated categories */
> >>>> @@ -225,6 +233,13 @@
> >>>> 	struct role_trans_rule *next;
> >>>> } role_trans_rule_t;
> >>>>
> >>>> +typedef struct user_trans_rule {
> >>>> +	ebitmap_t users;	/* current role */
> >>>> +	type_set_t types;	/* program executable type */
> >>>> +	uint32_t new_user;	/* new role */
> >>>> +	struct user_trans_rule *next;
> >>>> +} user_trans_rule_t;
> >>>>     
> >>>>         
> >>> Possibly crazy idea - given the current trend, would it be better to
> >>> just save the user transition rules in symbolic form in the module
> >>> format.  Would that simplify the link/expand code?
> >>>
> >>>   
> >>>       
> >> Possibly, I am hoping policyrep will supplant this code in the near 
> >> future so I didn't think about it much. This is consistent with how we 
> >> store other modular things.
> >>
> >>     
> >>>> Index: libsepol/src/policydb.c
> >>>> ===================================================================
> >>>> --- libsepol/src/policydb.c	(revision 2854)
> >>>> +++ libsepol/src/policydb.c	(working copy)
> >>>> @@ -348,6 +367,30 @@
> >>>> 	}
> >>>> }
> >>>>
> >>>> +void user_trans_rule_init(user_trans_rule_t * x)
> >>>> +{
> >>>> +	memset(x, 0, sizeof(*x));
> >>>>     
> >>>>         
> >>> Not unique to this patch, but it seems funny that we use memset followed
> >>> by explicit initializers for fields that have them.  And that as a
> >>> result of the memset here, we don't calloc when allocate the structs.
> >>>
> >>>   
> >>>       
> >> I would normally never memset a struct, rather than use an initializer 
> >> but I was going for minimal changes here, I don't plan on this code 
> >> being around for long.
> >>     
> >
> > Famous last words.  Don't ever make that assumption ;)
> > Especially given life cycles of distributions that might incorporate
> > said code.
> >   
> 
> I know, I typed it tongue-in-cheek.
> 
> > I know that this is consistent with how we store other modular things
> > and that policyrep will "make all things better".  But I'm wondering
> > whether you could have greatly simplified even this "transient"
> > implementation of user transition support by keeping it in symbolic
> > form, even within a "binary" module format, to simplify linking and
> > reduce likelihood of mapping errors.
> >
> >   
> 
> I understand and if there were more time I wouldn't mind doing it. Right 
> now I wanted to push these through as fast as possible so that we could 
> maybe get them in to Hardy, which as of right now has no solution to 
> restart services other than rebooting.

Rushing through a new feature considered harmful.  Look, Fedora has
lived for years without this feature and works fine, albeit requiring
adding system_r to user accounts and enabling DIRECT_INITRC=y in
build.conf.

> This method is well understood in this codebase and chances are in 
> mapping is broken one place its broken in five so I'm not entirely sure 
> what it would gain us now.
> 
> On the note of getting this out quickly I'm hitting this strange kernel 
> but where class_read says a common is unknown when I try to load a 23 
> policy, I'm currently working through that but building ubuntu kernels 
> takes hours :X

Cute.  But a good example of why we shouldn't rush this out.  And even
if it is implemented tomorrow, what is the likelihood that the Ubuntu
kernel folks are going to want to pull it into their existing kernel for
this release - at such a late date?

-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26 13:41         ` Stephen Smalley
@ 2008-03-26 13:57           ` Stephen Smalley
  2008-03-26 14:41             ` Joshua Brindle
  0 siblings, 1 reply; 27+ messages in thread
From: Stephen Smalley @ 2008-03-26 13:57 UTC (permalink / raw)
  To: Joshua Brindle; +Cc: SE Linux, Caleb Case


On Wed, 2008-03-26 at 09:41 -0400, Stephen Smalley wrote:
> On Wed, 2008-03-26 at 09:29 -0400, Joshua Brindle wrote:
> > Stephen Smalley wrote:
> > > On Tue, 2008-03-25 at 16:50 -0400, Joshua Brindle wrote:
> > >   
> > >> Stephen Smalley wrote:
> > >>     
> > >>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
> > >>>   
> > >>>       
> > >>>> This implements user_transition in the toolchain. It should help on
> > >>>> distro's like Ubuntu that can't use run_init due to the user not knowing
> > >>>> the root password. It also seems like a more eloquent way to handle
> > >>>> service restarts than assigning system_r to user accounts and having the
> > >>>> daemons run as someuser:system_r:foo_t.
> > >>>>
> > >>>> This has some issues in policy due to users not always being known in
> > >>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
> > >>>> give some suggestions there.
> > >>>>
> > >>>> The kernel patch (forthcoming after this is accepted) so far only
> > >>>> implements the transition on process transitions. Later on I plan on
> > >>>> doing a patch to expand role_transition to object classes (this is a
> > >>>> change needed for policy rbac support to work). I suspect I'll do the
> > >>>> same for user at that time. The question here is, do we think its worth
> > >>>> it to do fine grained transitions like we did for range_trans? (I don't).
> > >>>>
> > >>>> Index: libsepol/include/sepol/policydb/policydb.h
> > >>>> ===================================================================
> > >>>> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
> > >>>> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
> > >>>> @@ -156,6 +156,14 @@
> > >>>> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
> > >>>> } user_datum_t;
> > >>>>
> > >>>> +typedef struct user_trans {
> > >>>> +	uint32_t user;		/* current role */
> > >>>> +	uint32_t type;		/* program executable type */
> > >>>> +	uint32_t new_user;	/* new role */
> > >>>> +	struct user_trans *next;
> > >>>> +} user_trans_t;
> > >>>> +
> > >>>> +
> > >>>> /* Sensitivity attributes */
> > >>>> typedef struct level_datum {
> > >>>> 	mls_level_t *level;	/* sensitivity and associated categories */
> > >>>> @@ -225,6 +233,13 @@
> > >>>> 	struct role_trans_rule *next;
> > >>>> } role_trans_rule_t;
> > >>>>
> > >>>> +typedef struct user_trans_rule {
> > >>>> +	ebitmap_t users;	/* current role */
> > >>>> +	type_set_t types;	/* program executable type */
> > >>>> +	uint32_t new_user;	/* new role */
> > >>>> +	struct user_trans_rule *next;
> > >>>> +} user_trans_rule_t;
> > >>>>     
> > >>>>         
> > >>> Possibly crazy idea - given the current trend, would it be better to
> > >>> just save the user transition rules in symbolic form in the module
> > >>> format.  Would that simplify the link/expand code?
> > >>>
> > >>>   
> > >>>       
> > >> Possibly, I am hoping policyrep will supplant this code in the near 
> > >> future so I didn't think about it much. This is consistent with how we 
> > >> store other modular things.
> > >>
> > >>     
> > >>>> Index: libsepol/src/policydb.c
> > >>>> ===================================================================
> > >>>> --- libsepol/src/policydb.c	(revision 2854)
> > >>>> +++ libsepol/src/policydb.c	(working copy)
> > >>>> @@ -348,6 +367,30 @@
> > >>>> 	}
> > >>>> }
> > >>>>
> > >>>> +void user_trans_rule_init(user_trans_rule_t * x)
> > >>>> +{
> > >>>> +	memset(x, 0, sizeof(*x));
> > >>>>     
> > >>>>         
> > >>> Not unique to this patch, but it seems funny that we use memset followed
> > >>> by explicit initializers for fields that have them.  And that as a
> > >>> result of the memset here, we don't calloc when allocate the structs.
> > >>>
> > >>>   
> > >>>       
> > >> I would normally never memset a struct, rather than use an initializer 
> > >> but I was going for minimal changes here, I don't plan on this code 
> > >> being around for long.
> > >>     
> > >
> > > Famous last words.  Don't ever make that assumption ;)
> > > Especially given life cycles of distributions that might incorporate
> > > said code.
> > >   
> > 
> > I know, I typed it tongue-in-cheek.
> > 
> > > I know that this is consistent with how we store other modular things
> > > and that policyrep will "make all things better".  But I'm wondering
> > > whether you could have greatly simplified even this "transient"
> > > implementation of user transition support by keeping it in symbolic
> > > form, even within a "binary" module format, to simplify linking and
> > > reduce likelihood of mapping errors.
> > >
> > >   
> > 
> > I understand and if there were more time I wouldn't mind doing it. Right 
> > now I wanted to push these through as fast as possible so that we could 
> > maybe get them in to Hardy, which as of right now has no solution to 
> > restart services other than rebooting.
> 
> Rushing through a new feature considered harmful.  Look, Fedora has
> lived for years without this feature and works fine, albeit requiring
> adding system_r to user accounts and enabling DIRECT_INITRC=y in
> build.conf.

Seriously - this sounds like a recipe for disaster; the last thing we
want is to risk de-stabilizing the Ubuntu kernel with a last minute
change, making selinux unusable there.  Why not just follow the example
of Fedora (and I assume Debian?) here for now and use the above
workaround in policy, then you can switch to user transitions in the
future once this feature has had time to bake in -mm for a bit and then
gone into the mainline kernel.

> > This method is well understood in this codebase and chances are in 
> > mapping is broken one place its broken in five so I'm not entirely sure 
> > what it would gain us now.
> > 
> > On the note of getting this out quickly I'm hitting this strange kernel 
> > but where class_read says a common is unknown when I try to load a 23 
> > policy, I'm currently working through that but building ubuntu kernels 
> > takes hours :X
> 
> Cute.  But a good example of why we shouldn't rush this out.  And even
> if it is implemented tomorrow, what is the likelihood that the Ubuntu
> kernel folks are going to want to pull it into their existing kernel for
> this release - at such a late date?
> 
-- 
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26 13:57           ` Stephen Smalley
@ 2008-03-26 14:41             ` Joshua Brindle
  0 siblings, 0 replies; 27+ messages in thread
From: Joshua Brindle @ 2008-03-26 14:41 UTC (permalink / raw)
  To: Stephen Smalley; +Cc: SE Linux, Caleb Case

Stephen Smalley wrote:
> On Wed, 2008-03-26 at 09:41 -0400, Stephen Smalley wrote:
>   
>> On Wed, 2008-03-26 at 09:29 -0400, Joshua Brindle wrote:
>>     
>>> Stephen Smalley wrote:
>>>       
>>>> On Tue, 2008-03-25 at 16:50 -0400, Joshua Brindle wrote:
>>>>   
>>>>         
>>>>> Stephen Smalley wrote:
>>>>>     
>>>>>           
>>>>>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>>>>>>   
>>>>>>       
>>>>>>             
>>>>>>> This implements user_transition in the toolchain. It should help on
>>>>>>> distro's like Ubuntu that can't use run_init due to the user not knowing
>>>>>>> the root password. It also seems like a more eloquent way to handle
>>>>>>> service restarts than assigning system_r to user accounts and having the
>>>>>>> daemons run as someuser:system_r:foo_t.
>>>>>>>
>>>>>>> This has some issues in policy due to users not always being known in
>>>>>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>>>>>>> give some suggestions there.
>>>>>>>
>>>>>>> The kernel patch (forthcoming after this is accepted) so far only
>>>>>>> implements the transition on process transitions. Later on I plan on
>>>>>>> doing a patch to expand role_transition to object classes (this is a
>>>>>>> change needed for policy rbac support to work). I suspect I'll do the
>>>>>>> same for user at that time. The question here is, do we think its worth
>>>>>>> it to do fine grained transitions like we did for range_trans? (I don't).
>>>>>>>
>>>>>>> Index: libsepol/include/sepol/policydb/policydb.h
>>>>>>> ===================================================================
>>>>>>> --- libsepol/include/sepol/policydb/policydb.h	(revision 2854)
>>>>>>> +++ libsepol/include/sepol/policydb/policydb.h	(working copy)
>>>>>>> @@ -156,6 +156,14 @@
>>>>>>> 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
>>>>>>> } user_datum_t;
>>>>>>>
>>>>>>> +typedef struct user_trans {
>>>>>>> +	uint32_t user;		/* current role */
>>>>>>> +	uint32_t type;		/* program executable type */
>>>>>>> +	uint32_t new_user;	/* new role */
>>>>>>> +	struct user_trans *next;
>>>>>>> +} user_trans_t;
>>>>>>> +
>>>>>>> +
>>>>>>> /* Sensitivity attributes */
>>>>>>> typedef struct level_datum {
>>>>>>> 	mls_level_t *level;	/* sensitivity and associated categories */
>>>>>>> @@ -225,6 +233,13 @@
>>>>>>> 	struct role_trans_rule *next;
>>>>>>> } role_trans_rule_t;
>>>>>>>
>>>>>>> +typedef struct user_trans_rule {
>>>>>>> +	ebitmap_t users;	/* current role */
>>>>>>> +	type_set_t types;	/* program executable type */
>>>>>>> +	uint32_t new_user;	/* new role */
>>>>>>> +	struct user_trans_rule *next;
>>>>>>> +} user_trans_rule_t;
>>>>>>>     
>>>>>>>         
>>>>>>>               
>>>>>> Possibly crazy idea - given the current trend, would it be better to
>>>>>> just save the user transition rules in symbolic form in the module
>>>>>> format.  Would that simplify the link/expand code?
>>>>>>
>>>>>>   
>>>>>>       
>>>>>>             
>>>>> Possibly, I am hoping policyrep will supplant this code in the near 
>>>>> future so I didn't think about it much. This is consistent with how we 
>>>>> store other modular things.
>>>>>
>>>>>     
>>>>>           
>>>>>>> Index: libsepol/src/policydb.c
>>>>>>> ===================================================================
>>>>>>> --- libsepol/src/policydb.c	(revision 2854)
>>>>>>> +++ libsepol/src/policydb.c	(working copy)
>>>>>>> @@ -348,6 +367,30 @@
>>>>>>> 	}
>>>>>>> }
>>>>>>>
>>>>>>> +void user_trans_rule_init(user_trans_rule_t * x)
>>>>>>> +{
>>>>>>> +	memset(x, 0, sizeof(*x));
>>>>>>>     
>>>>>>>         
>>>>>>>               
>>>>>> Not unique to this patch, but it seems funny that we use memset followed
>>>>>> by explicit initializers for fields that have them.  And that as a
>>>>>> result of the memset here, we don't calloc when allocate the structs.
>>>>>>
>>>>>>   
>>>>>>       
>>>>>>             
>>>>> I would normally never memset a struct, rather than use an initializer 
>>>>> but I was going for minimal changes here, I don't plan on this code 
>>>>> being around for long.
>>>>>     
>>>>>           
>>>> Famous last words.  Don't ever make that assumption ;)
>>>> Especially given life cycles of distributions that might incorporate
>>>> said code.
>>>>   
>>>>         
>>> I know, I typed it tongue-in-cheek.
>>>
>>>       
>>>> I know that this is consistent with how we store other modular things
>>>> and that policyrep will "make all things better".  But I'm wondering
>>>> whether you could have greatly simplified even this "transient"
>>>> implementation of user transition support by keeping it in symbolic
>>>> form, even within a "binary" module format, to simplify linking and
>>>> reduce likelihood of mapping errors.
>>>>
>>>>   
>>>>         
>>> I understand and if there were more time I wouldn't mind doing it. Right 
>>> now I wanted to push these through as fast as possible so that we could 
>>> maybe get them in to Hardy, which as of right now has no solution to 
>>> restart services other than rebooting.
>>>       
>> Rushing through a new feature considered harmful.  Look, Fedora has
>> lived for years without this feature and works fine, albeit requiring
>> adding system_r to user accounts and enabling DIRECT_INITRC=y in
>> build.conf.
>>     
>
> Seriously - this sounds like a recipe for disaster; the last thing we
> want is to risk de-stabilizing the Ubuntu kernel with a last minute
> change, making selinux unusable there.  Why not just follow the example
> of Fedora (and I assume Debian?) here for now and use the above
> workaround in policy, then you can switch to user transitions in the
> future once this feature has had time to bake in -mm for a bit and then
> gone into the mainline kernel.
>
>   

Fair enough.

>>> This method is well understood in this codebase and chances are in 
>>> mapping is broken one place its broken in five so I'm not entirely sure 
>>> what it would gain us now.
>>>
>>> On the note of getting this out quickly I'm hitting this strange kernel 
>>> but where class_read says a common is unknown when I try to load a 23 
>>> policy, I'm currently working through that but building ubuntu kernels 
>>> takes hours :X
>>>       
>> Cute.  But a good example of why we shouldn't rush this out.  And even
>> if it is implemented tomorrow, what is the likelihood that the Ubuntu
>> kernel folks are going to want to pull it into their existing kernel for
>> this release - at such a late date?
>>
>>     



--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26  8:46           ` Daniel J Walsh
  2008-03-26 13:36             ` Stephen Smalley
@ 2008-03-27  4:43             ` Russell Coker
  2008-03-27 19:48               ` Daniel J Walsh
  1 sibling, 1 reply; 27+ messages in thread
From: Russell Coker @ 2008-03-27  4:43 UTC (permalink / raw)
  To: Daniel J Walsh; +Cc: SE Linux

On Wednesday 26 March 2008 19:46, Daniel J Walsh <dwalsh@redhat.com> wrote:
> I am not sure where this is going, but I believe that separation based
> on role in the home directory is a mistake.  It assumes that the home
> directory will always be used by the same user with the same role.   And
> will not work when you have a network file system that supports labels.
>
> In Red Hat I can login to people.redhat.com people.fedoraproject.com
> which I should use the guest_r.  While logging into my laptop I would be
> unconfined_t and on test machines I might get staff_r or user_r.  All of
> them would use the same homedirectory.  So how would this work in this
> environment?

If you have the same home directory contents (including .login, .bashrc, and 
equivalent files) and you can execute programs from the home directory, then 
how can you usefully have roles which are really different on different 
machines?

You could for example have guest_r on machine A mapping to sysadm_r on machine 
B (which I believe bears some similarity to the reclassification of documents 
when going between certain military organisations).

The idea of a network filesystem having the same labels on all machines where 
it is mounted even when there are differences in policy and/or user rights on 
those machines makes no sense to me.

-- 
russell@coker.com.au
http://etbe.coker.com.au/          My Blog

http://www.coker.com.au/sponsorship.html Sponsoring Free Software development


--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-26 13:36             ` Stephen Smalley
@ 2008-03-27 19:42               ` Daniel J Walsh
  0 siblings, 0 replies; 27+ messages in thread
From: Daniel J Walsh @ 2008-03-27 19:42 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: Joshua Brindle, SE Linux, Caleb Case, Christopher J. PeBenito

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Stephen Smalley wrote:
> On Wed, 2008-03-26 at 09:46 +0100, Daniel J Walsh wrote:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> Stephen Smalley wrote:
>>> On Tue, 2008-03-25 at 07:04 -0400, Joshua Brindle wrote:
>>>> Stephen Smalley wrote:
>>>>> On Mon, 2008-03-24 at 16:27 -0400, Joshua Brindle wrote:
>>>>>   
>>>>>> Stephen Smalley wrote:
>>>>>>     
>>>>>>> On Mon, 2008-03-24 at 13:40 -0400, Joshua Brindle wrote:
>>>>>>>   
>>>>>>>       
>>>>>>>> This implements user_transition in the toolchain. It should help on
>>>>>>>> distro's like Ubuntu that can't use run_init due to the user not knowing
>>>>>>>> the root password. It also seems like a more eloquent way to handle
>>>>>>>> service restarts than assigning system_r to user accounts and having the
>>>>>>>> daemons run as someuser:system_r:foo_t.
>>>>>>>>     
>>>>>>>>         
>>>>>>> Yes, that's something that has been wanted in Fedora for quite some
>>>>>>> time.
>>>>>>>
>>>>>>> The real issue with run_init isn't the re-authentication stage, as that
>>>>>>> can always be disabled via pam config (and was just a weak form of
>>>>>>> confirming user intent, not an authorization mechanism), but rather the
>>>>>>> difficulty in transparently interposing it into all situations where
>>>>>>> services get started/re-started.  Only Gentoo seemed to have a good
>>>>>>> story there.
>>>>>>>
>>>>>>>   
>>>>>>>       
>>>>>>>> This has some issues in policy due to users not always being known in
>>>>>>>> the policy (eg., semanage users). I hope Chris or Dan will be able to
>>>>>>>> give some suggestions there.
>>>>>>>>     
>>>>>>>>         
>>>>>>> I'm not sure why anyone needs to add users to policy via semanage users
>>>>>>> given the base set of generic users and the ability to map Linux users
>>>>>>> to them via seusers aka semanage login.
>>>>>>>
>>>>>>>   
>>>>>>>       
>>>>>>>> The kernel patch (forthcoming after this is accepted) so far only
>>>>>>>> implements the transition on process transitions. Later on I plan on
>>>>>>>> doing a patch to expand role_transition to object classes (this is a
>>>>>>>> change needed for policy rbac support to work). I suspect I'll do the
>>>>>>>> same for user at that time. The question here is, do we think its worth
>>>>>>>> it to do fine grained transitions like we did for range_trans? (I don't).
>>>>>>>>     
>>>>>>>>         
>>>>>>> Offhand, I can't see a use for per-class user transitions, if that is
>>>>>>> what you mean.
>>>>>>>
>>>>>>> I don't think per-class role transitions is really the fundamental
>>>>>>> obstacle to enabling use of roles on objects - more thought is required
>>>>>>> there.  What will be fun there is role/type and user/range validation,
>>>>>>> which presently gets to ignore everything that has object_r.
>>>>>>>   
>>>>>>>       
>>>>>> Ah, another thing. While going through the policyrep implementation the 
>>>>>> question of object_r came up. My thought is to start adding object_r 
>>>>>> magic into the toolchain (adding all types, etc) and eventually purge 
>>>>>> object_r from the kernel. at least one magic instance of object_r will 
>>>>>> be removed by object role_transitions, the others are really short 
>>>>>> circuits in the security server that can be removed after sufficient 
>>>>>> support is in the toolchain. What are your thoughts on that (for future 
>>>>>> reference)?
>>>>>>     
>>>>> Well, the interesting question is what should the default role be in the
>>>>> new context in security_compute_sid, if not object_r.  Even aside from
>>>>> the support for per-class role transitions.  User defaults to the source
>>>>> context, type defaults to the related object context, and MLS range
>>>>> defaults to the low level of the source context.  Role could be the
>>>>> subject's role or the related object's role.
>>>>>
>>>>>   
>>>> Good question. My original assumption was that we'd use the related 
>>>> object role. That would require that home directories be correctly 
>>>> labeled with the role of the user. If we start using the source role 
>>>> then things will quickly change from object_r to system_r, so maybe the 
>>>> policy should do that anyway. Chris, any opinions on this?
>>> Yes, related object role would likely cause the least breakage.  It
>>> would preserve the existing default for existing filesystems (as they
>>> already have object_r in the directory contexts), while allowing us to
>>> switch over to the user's role for home directories upon a relabel or
>>> new filesystem.  Source role might create more conflicts, as we enforce
>>> the role/type relationship for contexts and there might be a mismatch
>>> between the creating process role and the parent directory type.
>>>
>> I am not sure where this is going, but I believe that separation based
>> on role in the home directory is a mistake.  It assumes that the home
>> directory will always be used by the same user with the same role.   And
>> will not work when you have a network file system that supports labels.
>>
>> In Red Hat I can login to people.redhat.com people.fedoraproject.com
>> which I should use the guest_r.  While logging into my laptop I would be
>> unconfined_t and on test machines I might get staff_r or user_r.  All of
>> them would use the same homedirectory.  So how would this work in this
>> environment?
> 
> That's an interesting question, and I know that in some operating
> systems, roles are actually separate user accounts altogether.
> 
> However, the mechanism being described here doesn't prevent you from
> continuing to use a generic role (object_r or otherwise) on all files;
> it just allows for people who want to apply distinct roles on files to
> do so.
> 
Well I guess I will be the first one to state that if this breaks the
situation I stated above, I am not interested.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iEYEARECAAYFAkfr+LYACgkQrlYvE4MpobOpRQCfSma66Z5JG6CV1bfAbd2xMJf8
MA4AoJbRYBB6coyQnnvIdH8kw0eE3Erq
=xtQ8
-----END PGP SIGNATURE-----

--
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] 27+ messages in thread

* Re: [RFC][PATCH] user_transition support for libsepol/checkpolicy
  2008-03-27  4:43             ` Russell Coker
@ 2008-03-27 19:48               ` Daniel J Walsh
  0 siblings, 0 replies; 27+ messages in thread
From: Daniel J Walsh @ 2008-03-27 19:48 UTC (permalink / raw)
  To: russell; +Cc: SE Linux

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Russell Coker wrote:
> On Wednesday 26 March 2008 19:46, Daniel J Walsh <dwalsh@redhat.com> wrote:
>> I am not sure where this is going, but I believe that separation based
>> on role in the home directory is a mistake.  It assumes that the home
>> directory will always be used by the same user with the same role.   And
>> will not work when you have a network file system that supports labels.
>>
>> In Red Hat I can login to people.redhat.com people.fedoraproject.com
>> which I should use the guest_r.  While logging into my laptop I would be
>> unconfined_t and on test machines I might get staff_r or user_r.  All of
>> them would use the same homedirectory.  So how would this work in this
>> environment?
> 
> If you have the same home directory contents (including .login, .bashrc, and 
> equivalent files) and you can execute programs from the home directory, then 
> how can you usefully have roles which are really different on different 
> machines?
> 
If I login to people.redhat.com I will log in as guest_t this type is
not allowed to use the network, execute files in the home directory or
run any setuid apps.  If I as the guest_t user want to muck around with
the .login file so that when I login to a different machine as
unconfined_t, I don't see a problem.  This is about defining roles and
policy based on the machine you login to.
> You could for example have guest_r on machine A mapping to sysadm_r on machine 
> B (which I believe bears some similarity to the reclassification of documents 
> when going between certain military organisations).
> 
This is not an MLS issue, and this does happen on MLS environments where
they say the same user on one machine can get to Secret while on another
machine he can get to TopSecret,  I would surmise that bother users
would have the same home dir, of course on the machine that is Secret he
would not be able to access the top secret files.
> The idea of a network filesystem having the same labels on all machines where 
> it is mounted even when there are differences in policy and/or user rights on 
> those machines makes no sense to me.
> 

Well I would assume that the policy is the same on each machine except
the default context that the user logs in as.  And I have given you a
descrete example of how things work at Red Hat.  This is also how our
customers expect this to work.  CA/EATrust has made major money on this
concept...

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iEYEARECAAYFAkfr+hIACgkQrlYvE4MpobNidgCgnljhMx4GjdKbAdRzpUZUPGmN
qqoAn27gqpThN26Si285ne2uLxEr22on
=/dFC
-----END PGP SIGNATURE-----

--
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] 27+ messages in thread

end of thread, other threads:[~2008-03-27 23:03 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-03-24 17:40 [RFC][PATCH] user_transition support for libsepol/checkpolicy Joshua Brindle
2008-03-24 20:15 ` Stephen Smalley
2008-03-24 20:27   ` Joshua Brindle
2008-03-24 20:36     ` Stephen Smalley
2008-03-25 11:04       ` Joshua Brindle
2008-03-25 12:08         ` Stephen Smalley
2008-03-25 13:01           ` Christopher J. PeBenito
2008-03-25 13:52             ` Joshua Brindle
2008-03-25 16:27               ` Stephen Smalley
2008-03-26  8:46           ` Daniel J Walsh
2008-03-26 13:36             ` Stephen Smalley
2008-03-27 19:42               ` Daniel J Walsh
2008-03-27  4:43             ` Russell Coker
2008-03-27 19:48               ` Daniel J Walsh
2008-03-24 20:30   ` Joshua Brindle
2008-03-25  4:25   ` Russell Coker
2008-03-25 10:37     ` Joshua Brindle
2008-03-25 11:42     ` Stephen Smalley
2008-03-26  8:40   ` Daniel J Walsh
2008-03-26 13:33     ` Stephen Smalley
2008-03-25 16:42 ` Stephen Smalley
2008-03-25 20:50   ` Joshua Brindle
2008-03-26 12:48     ` Stephen Smalley
2008-03-26 13:29       ` Joshua Brindle
2008-03-26 13:41         ` Stephen Smalley
2008-03-26 13:57           ` Stephen Smalley
2008-03-26 14:41             ` 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.