Skip to contentSkip to conversation

SELinux: seperate range transition rules to a seperate function

PATCH In review Eric Paris 6 participants 26 messages Jun 11, 2010 – Jun 18, 2010 SELinux security module

lore
Share & tools
lore

Eric Paris

author
#0 lore raw

PATCH 1/4 SELinux: seperate range transition rules to a seperate function

Move the range transition rule to a separate function, range_read(), rather than doing it all in policydb_read()

---

 security/selinux/ss/policydb.c |  139 ++++++++++++++++++++++------------------
 1 files changed, 75 insertions(+), 64 deletions(-)
security/selinux/ss/policydb.c +75 -64
index c57802a..a39d38a 100644
@@ -1701,6 +1701,78 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
 	return 1U << (perdatum->value-1);
 }
 
+static int range_read(struct policydb *p, void *fp)
+{
+	struct range_trans *rt = NULL;
+	struct mls_range *r = NULL;
+	int i, rc;
+	__le32 buf[2];
+	u32 nel;
+
+	if (p->policyvers < POLICYDB_VERSION_MLS)
+		return 0;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc)
+		goto out;
+
+	nel = le32_to_cpu(buf[0]);
+	for (i = 0; i < nel; i++) {
+		rc = -ENOMEM;
+		rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+		if (!rt)
+			goto out;
+
+		rc = next_entry(buf, fp, (sizeof(u32) * 2));
+		if (rc)
+			goto out;
+
+		rt->source_type = le32_to_cpu(buf[0]);
+		rt->target_type = le32_to_cpu(buf[1]);
+		if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+			rt->target_class = le32_to_cpu(buf[0]);
+		} else
+			rt->target_class = p->process_class;
+
+		rc = -EINVAL;
+		if (!policydb_type_isvalid(p, rt->source_type) ||
+		    !policydb_type_isvalid(p, rt->target_type) ||
+		    !policydb_class_isvalid(p, rt->target_class))
+			goto out;
+
+		rc = -ENOMEM;
+		r = kzalloc(sizeof(*r), GFP_KERNEL);
+		if (!r)
+			goto out;
+
+		rc = mls_read_range_helper(r, fp);
+		if (rc)
+			goto out;
+
+		rc = -EINVAL;
+		if (!mls_range_isvalid(p, r)) {
+			printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
+			goto out;
+		}
+
+		rc = hashtab_insert(p->range_tr, rt, r);
+		if (rc)
+			goto out;
+
+		rt = NULL;
+		r = NULL;
+	}
+	rangetr_hash_eval(p->range_tr);
+	rc = 0;
+out:
+	kfree(rt);
+	kfree(r);
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1717,8 +1789,6 @@ int policydb_read(struct policydb *p, void *fp)
 	u32 len, len2, nprim, nel, nel2;
 	char *policydb_str;
 	struct policydb_compat_info *info;
-	struct range_trans *rt;
-	struct mls_range *r;
 
 	rc = policydb_init(p);
 	if (rc)
@@ -2131,68 +2201,9 @@ int policydb_read(struct policydb *p, void *fp)
 		}
 	}
 
-	if (p->policyvers >= POLICYDB_VERSION_MLS) {
-		int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel = le32_to_cpu(buf[0]);
-		for (i = 0; i < nel; i++) {
-			rt = kzalloc(sizeof(*rt), GFP_KERNEL);
-			if (!rt) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-			rc = next_entry(buf, fp, (sizeof(u32) * 2));
-			if (rc < 0) {
-				kfree(rt);
-				goto bad;
-			}
-			rt->source_type = le32_to_cpu(buf[0]);
-			rt->target_type = le32_to_cpu(buf[1]);
-			if (new_rangetr) {
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0) {
-					kfree(rt);
-					goto bad;
-				}
-				rt->target_class = le32_to_cpu(buf[0]);
-			} else
-				rt->target_class = p->process_class;
-			if (!policydb_type_isvalid(p, rt->source_type) ||
-			    !policydb_type_isvalid(p, rt->target_type) ||
-			    !policydb_class_isvalid(p, rt->target_class)) {
-				kfree(rt);
-				rc = -EINVAL;
-				goto bad;
-			}
-			r = kzalloc(sizeof(*r), GFP_KERNEL);
-			if (!r) {
-				kfree(rt);
-				rc = -ENOMEM;
-				goto bad;
-			}
-			rc = mls_read_range_helper(r, fp);
-			if (rc) {
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-			if (!mls_range_isvalid(p, r)) {
-				printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-			rc = hashtab_insert(p->range_tr, rt, r);
-			if (rc) {
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-		}
-		rangetr_hash_eval(p->range_tr);
-	}
+	rc = range_read(p, fp);
+	if (rc)
+		goto bad;
 
 	p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL);
 	if (!p->type_attr_map)

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

author
#1 lore raw

PATCH 2/4 SELinux: move genfs read to a separate function

move genfs read functionality out of policydb_read() and into a new function called genfs_read()

---

 security/selinux/ss/policydb.c |  236 ++++++++++++++++++++++------------------
 1 files changed, 131 insertions(+), 105 deletions(-)
security/selinux/ss/policydb.c +131 -105
index a39d38a..66e217b 100644
@@ -655,6 +655,9 @@ static int range_tr_destroy(void *key, void *datum, void *p)
 
 static void ocontext_destroy(struct ocontext *c, int i)
 {
+	if (!c)
+		return;
+
 	context_destroy(&c->context[0]);
 	context_destroy(&c->context[1]);
 	if (i == OCON_ISID || i == OCON_FS ||
@@ -1773,6 +1776,129 @@ out:
 	return rc;
 }
 
+static int genfs_read(struct policydb *p, void *fp)
+{
+	int i, j, rc;
+	u32 nel, nel2, len, len2;
+	__le32 buf[1];
+	struct ocontext *l, *c;
+	struct ocontext *newc = NULL;
+	struct genfs *genfs_p, *genfs;
+	struct genfs *newgenfs = NULL;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc < 0)
+		goto out;
+	nel = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < nel; i++) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+		len = le32_to_cpu(buf[0]);
+
+		rc = -ENOMEM;
+		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
+		if (!newgenfs)
+			goto out;
+
+		rc = -ENOMEM;
+		newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
+		if (!newgenfs->fstype)
+			goto out;
+
+		rc = next_entry(newgenfs->fstype, fp, len);
+		if (rc < 0)
+			goto out;
+
+		newgenfs->fstype[len] = 0;
+
+		for (genfs_p = NULL, genfs = p->genfs; genfs;
+		     genfs_p = genfs, genfs = genfs->next) {
+			rc = -EEXIST;
+			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+				printk(KERN_ERR "SELinux:  dup genfs fstype %s\n",
+				       newgenfs->fstype);
+				goto out;
+			}
+			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+				break;
+		}
+		newgenfs->next = genfs;
+		if (genfs_p)
+			genfs_p->next = newgenfs;
+		else
+			p->genfs = newgenfs;
+		genfs = newgenfs;
+		newgenfs = NULL;
+
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+
+		nel2 = le32_to_cpu(buf[0]);
+		for (j = 0; j < nel2; j++) {
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+			len = le32_to_cpu(buf[0]);
+
+			rc = -ENOMEM;
+			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
+			if (!newc)
+				goto out;
+
+			rc = -ENOMEM;
+			newc->u.name = kmalloc(len + 1, GFP_KERNEL);
+			if (!newc->u.name)
+				goto out;
+
+			rc = next_entry(newc->u.name, fp, len);
+			if (rc)
+				goto out;
+			newc->u.name[len] = 0;
+
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+
+			newc->v.sclass = le32_to_cpu(buf[0]);
+			rc = context_read_and_validate(&newc->context[0], p, fp);
+			if (rc)
+				goto out;
+
+			for (l = NULL, c = genfs->head; c;
+			     l = c, c = c->next) {
+				if (!strcmp(newc->u.name, c->u.name) &&
+				    (!c->v.sclass || !newc->v.sclass ||
+				     newc->v.sclass == c->v.sclass)) {
+					printk(KERN_ERR "SELinux:  dup genfs entry (%s,%s)\n",
+					       genfs->fstype, c->u.name);
+					goto out;
+				}
+				len = strlen(newc->u.name);
+				len2 = strlen(c->u.name);
+				if (len > len2)
+					break;
+			}
+
+			newc->next = c;
+			if (l)
+				l->next = newc;
+			else
+				genfs->head = newc;
+			newc = NULL;
+		}
+	}
+out:
+	if (newgenfs)
+		kfree(newgenfs->fstype);
+	kfree(newgenfs);
+	ocontext_destroy(newc, OCON_FSUSE);
+
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1781,12 +1907,12 @@ int policydb_read(struct policydb *p, void *fp)
 {
 	struct role_allow *ra, *lra;
 	struct role_trans *tr, *ltr;
-	struct ocontext *l, *c, *newc;
-	struct genfs *genfs_p, *genfs, *newgenfs;
+	struct ocontext *l, *c;
 	int i, j, rc;
 	__le32 buf[4];
 	u32 nodebuf[8];
-	u32 len, len2, nprim, nel, nel2;
+	u32 len, nprim, nel;
+
 	char *policydb_str;
 	struct policydb_compat_info *info;
 
@@ -2099,107 +2225,9 @@ int policydb_read(struct policydb *p, void *fp)
 		}
 	}
 
-	rc = next_entry(buf, fp, sizeof(u32));
-	if (rc < 0)
+	rc = genfs_read(p, fp);
+	if (rc)
 		goto bad;
-	nel = le32_to_cpu(buf[0]);
-	genfs_p = NULL;
-	rc = -EINVAL;
-	for (i = 0; i < nel; i++) {
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		len = le32_to_cpu(buf[0]);
-		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
-		if (!newgenfs) {
-			rc = -ENOMEM;
-			goto bad;
-		}
-
-		newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
-		if (!newgenfs->fstype) {
-			rc = -ENOMEM;
-			kfree(newgenfs);
-			goto bad;
-		}
-		rc = next_entry(newgenfs->fstype, fp, len);
-		if (rc < 0) {
-			kfree(newgenfs->fstype);
-			kfree(newgenfs);
-			goto bad;
-		}
-		newgenfs->fstype[len] = 0;
-		for (genfs_p = NULL, genfs = p->genfs; genfs;
-		     genfs_p = genfs, genfs = genfs->next) {
-			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
-				printk(KERN_ERR "SELinux:  dup genfs "
-				       "fstype %s\n", newgenfs->fstype);
-				kfree(newgenfs->fstype);
-				kfree(newgenfs);
-				goto bad;
-			}
-			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
-				break;
-		}
-		newgenfs->next = genfs;
-		if (genfs_p)
-			genfs_p->next = newgenfs;
-		else
-			p->genfs = newgenfs;
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel2 = le32_to_cpu(buf[0]);
-		for (j = 0; j < nel2; j++) {
-			rc = next_entry(buf, fp, sizeof(u32));
-			if (rc < 0)
-				goto bad;
-			len = le32_to_cpu(buf[0]);
-
-			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
-			if (!newc) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-
-			newc->u.name = kmalloc(len + 1, GFP_KERNEL);
-			if (!newc->u.name) {
-				rc = -ENOMEM;
-				goto bad_newc;
-			}
-			rc = next_entry(newc->u.name, fp, len);
-			if (rc < 0)
-				goto bad_newc;
-			newc->u.name[len] = 0;
-			rc = next_entry(buf, fp, sizeof(u32));
-			if (rc < 0)
-				goto bad_newc;
-			newc->v.sclass = le32_to_cpu(buf[0]);
-			if (context_read_and_validate(&newc->context[0], p, fp))
-				goto bad_newc;
-			for (l = NULL, c = newgenfs->head; c;
-			     l = c, c = c->next) {
-				if (!strcmp(newc->u.name, c->u.name) &&
-				    (!c->v.sclass || !newc->v.sclass ||
-				     newc->v.sclass == c->v.sclass)) {
-					printk(KERN_ERR "SELinux:  dup genfs "
-					       "entry (%s,%s)\n",
-					       newgenfs->fstype, c->u.name);
-					goto bad_newc;
-				}
-				len = strlen(newc->u.name);
-				len2 = strlen(c->u.name);
-				if (len > len2)
-					break;
-			}
-
-			newc->next = c;
-			if (l)
-				l->next = newc;
-			else
-				newgenfs->head = newc;
-		}
-	}
 
 	rc = range_read(p, fp);
 	if (rc)
@@ -2227,8 +2255,6 @@ int policydb_read(struct policydb *p, void *fp)
 	rc = 0;
 out:
 	return rc;
-bad_newc:
-	ocontext_destroy(newc, OCON_FSUSE);
 bad:
 	if (!rc)
 		rc = -EINVAL;

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#2 lore raw

Re: [PATCH 2/4] SELinux: move genfs read to a separate function

Quoted 106 lines · Eric Paris

move genfs read functionality out of policydb_read() and into a new function called genfs_read()

---

 security/selinux/ss/policydb.c |  236 ++++++++++++++++++++++------------------
 1 files changed, 131 insertions(+), 105 deletions(-)
security/selinux/ss/policydb.c +89 -0
index a39d38a..66e217b 100644
@@ -1773,6 +1776,129 @@ out:
 	return rc;
 }
 
+static int genfs_read(struct policydb *p, void *fp)
+{
+	int i, j, rc;
+	u32 nel, nel2, len, len2;
+	__le32 buf[1];
+	struct ocontext *l, *c;
+	struct ocontext *newc = NULL;
+	struct genfs *genfs_p, *genfs;
+	struct genfs *newgenfs = NULL;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc < 0)
+		goto out;
+	nel = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < nel; i++) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+		len = le32_to_cpu(buf[0]);
+
+		rc = -ENOMEM;
+		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
+		if (!newgenfs)
+			goto out;
+
+		rc = -ENOMEM;
+		newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
+		if (!newgenfs->fstype)
+			goto out;
+
+		rc = next_entry(newgenfs->fstype, fp, len);
+		if (rc < 0)
+			goto out;
+
+		newgenfs->fstype[len] = 0;
+
+		for (genfs_p = NULL, genfs = p->genfs; genfs;
+		     genfs_p = genfs, genfs = genfs->next) {
+			rc = -EEXIST;
+			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+				printk(KERN_ERR "SELinux:  dup genfs fstype %s\n",
+				       newgenfs->fstype);
+				goto out;
+			}
+			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+				break;
+		}
+		newgenfs->next = genfs;
+		if (genfs_p)
+			genfs_p->next = newgenfs;
+		else
+			p->genfs = newgenfs;
+		genfs = newgenfs;
+		newgenfs = NULL;
+
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+
+		nel2 = le32_to_cpu(buf[0]);
+		for (j = 0; j < nel2; j++) {
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+			len = le32_to_cpu(buf[0]);
+
+			rc = -ENOMEM;
+			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
+			if (!newc)
+				goto out;
+
+			rc = -ENOMEM;
+			newc->u.name = kmalloc(len + 1, GFP_KERNEL);
+			if (!newc->u.name)
+				goto out;
+
+			rc = next_entry(newc->u.name, fp, len);
+			if (rc)
+				goto out;
+			newc->u.name[len] = 0;
+
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+
+			newc->v.sclass = le32_to_cpu(buf[0]);
+			rc = context_read_and_validate(&newc->context[0], p, fp);
+			if (rc)

security/selinux/ss/policydb.c out: · line 1877

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+				goto out;
+
+			for (l = NULL, c = genfs->head; c;
+			     l = c, c = c->next) {
+				if (!strcmp(newc->u.name, c->u.name) &&
+				    (!c->v.sclass || !newc->v.sclass ||
+				     newc->v.sclass == c->v.sclass)) {
+					printk(KERN_ERR "SELinux:  dup genfs entry (%s,%s)\n",
+					       genfs->fstype, c->u.name);
+					goto out;

rc wasn't set.

Quoted 162 lines
security/selinux/ss/policydb.c +29 -105
+				}
+				len = strlen(newc->u.name);
+				len2 = strlen(c->u.name);
+				if (len > len2)
+					break;
+			}
+
+			newc->next = c;
+			if (l)
+				l->next = newc;
+			else
+				genfs->head = newc;
+			newc = NULL;
+		}
+	}
+out:
+	if (newgenfs)
+		kfree(newgenfs->fstype);
+	kfree(newgenfs);
+	ocontext_destroy(newc, OCON_FSUSE);
+
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1781,12 +1907,12 @@ int policydb_read(struct policydb *p, void *fp)
 {
 	struct role_allow *ra, *lra;
 	struct role_trans *tr, *ltr;
-	struct ocontext *l, *c, *newc;
-	struct genfs *genfs_p, *genfs, *newgenfs;
+	struct ocontext *l, *c;
 	int i, j, rc;
 	__le32 buf[4];
 	u32 nodebuf[8];
-	u32 len, len2, nprim, nel, nel2;
+	u32 len, nprim, nel;
+
 	char *policydb_str;
 	struct policydb_compat_info *info;
 
@@ -2099,107 +2225,9 @@ int policydb_read(struct policydb *p, void *fp)
 		}
 	}
 
-	rc = next_entry(buf, fp, sizeof(u32));
-	if (rc < 0)
+	rc = genfs_read(p, fp);
+	if (rc)
 		goto bad;
-	nel = le32_to_cpu(buf[0]);
-	genfs_p = NULL;
-	rc = -EINVAL;
-	for (i = 0; i < nel; i++) {
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		len = le32_to_cpu(buf[0]);
-		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
-		if (!newgenfs) {
-			rc = -ENOMEM;
-			goto bad;
-		}
-
-		newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
-		if (!newgenfs->fstype) {
-			rc = -ENOMEM;
-			kfree(newgenfs);
-			goto bad;
-		}
-		rc = next_entry(newgenfs->fstype, fp, len);
-		if (rc < 0) {
-			kfree(newgenfs->fstype);
-			kfree(newgenfs);
-			goto bad;
-		}
-		newgenfs->fstype[len] = 0;
-		for (genfs_p = NULL, genfs = p->genfs; genfs;
-		     genfs_p = genfs, genfs = genfs->next) {
-			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
-				printk(KERN_ERR "SELinux:  dup genfs "
-				       "fstype %s\n", newgenfs->fstype);
-				kfree(newgenfs->fstype);
-				kfree(newgenfs);
-				goto bad;
-			}
-			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
-				break;
-		}
-		newgenfs->next = genfs;
-		if (genfs_p)
-			genfs_p->next = newgenfs;
-		else
-			p->genfs = newgenfs;
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel2 = le32_to_cpu(buf[0]);
-		for (j = 0; j < nel2; j++) {
-			rc = next_entry(buf, fp, sizeof(u32));
-			if (rc < 0)
-				goto bad;
-			len = le32_to_cpu(buf[0]);
-
-			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
-			if (!newc) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-
-			newc->u.name = kmalloc(len + 1, GFP_KERNEL);
-			if (!newc->u.name) {
-				rc = -ENOMEM;
-				goto bad_newc;
-			}
-			rc = next_entry(newc->u.name, fp, len);
-			if (rc < 0)
-				goto bad_newc;
-			newc->u.name[len] = 0;
-			rc = next_entry(buf, fp, sizeof(u32));
-			if (rc < 0)
-				goto bad_newc;
-			newc->v.sclass = le32_to_cpu(buf[0]);
-			if (context_read_and_validate(&newc->context[0], p, fp))
-				goto bad_newc;
-			for (l = NULL, c = newgenfs->head; c;
-			     l = c, c = c->next) {
-				if (!strcmp(newc->u.name, c->u.name) &&
-				    (!c->v.sclass || !newc->v.sclass ||
-				     newc->v.sclass == c->v.sclass)) {
-					printk(KERN_ERR "SELinux:  dup genfs "
-					       "entry (%s,%s)\n",
-					       newgenfs->fstype, c->u.name);
-					goto bad_newc;
-				}
-				len = strlen(newc->u.name);
-				len2 = strlen(c->u.name);
-				if (len > len2)
-					break;
-			}
-
-			newc->next = c;
-			if (l)
-				l->next = newc;
-			else
-				newgenfs->head = newc;
-		}
-	}
 
 	rc = range_read(p, fp);
 	if (rc)
@@ -2227,8 +2255,6 @@ int policydb_read(struct policydb *p, void *fp)
 	rc = 0;
 out:
 	return rc;
-bad_newc:
-	ocontext_destroy(newc, OCON_FSUSE);
 bad:
 	if (!rc)
 		rc = -EINVAL;
Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#3 lore raw

Re: [PATCH 2/4] SELinux: move genfs read to a separate function

Quoted 120 lines · Stephen Smalley
Quoted 106 lines · Eric Paris

move genfs read functionality out of policydb_read() and into a new function called genfs_read()

---

 security/selinux/ss/policydb.c |  236 ++++++++++++++++++++++------------------
 1 files changed, 131 insertions(+), 105 deletions(-)
security/selinux/ss/policydb.c +89 -0
index a39d38a..66e217b 100644
@@ -1773,6 +1776,129 @@ out:
 	return rc;
 }
 
+static int genfs_read(struct policydb *p, void *fp)
+{
+	int i, j, rc;
+	u32 nel, nel2, len, len2;
+	__le32 buf[1];
+	struct ocontext *l, *c;
+	struct ocontext *newc = NULL;
+	struct genfs *genfs_p, *genfs;
+	struct genfs *newgenfs = NULL;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc < 0)
+		goto out;
+	nel = le32_to_cpu(buf[0]);
+
+	for (i = 0; i < nel; i++) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+		len = le32_to_cpu(buf[0]);
+
+		rc = -ENOMEM;
+		newgenfs = kzalloc(sizeof(*newgenfs), GFP_KERNEL);
+		if (!newgenfs)
+			goto out;
+
+		rc = -ENOMEM;
+		newgenfs->fstype = kmalloc(len + 1, GFP_KERNEL);
+		if (!newgenfs->fstype)
+			goto out;
+
+		rc = next_entry(newgenfs->fstype, fp, len);
+		if (rc < 0)
+			goto out;
+
+		newgenfs->fstype[len] = 0;
+
+		for (genfs_p = NULL, genfs = p->genfs; genfs;
+		     genfs_p = genfs, genfs = genfs->next) {
+			rc = -EEXIST;
+			if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
+				printk(KERN_ERR "SELinux:  dup genfs fstype %s\n",
+				       newgenfs->fstype);
+				goto out;
+			}
+			if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
+				break;
+		}
+		newgenfs->next = genfs;
+		if (genfs_p)
+			genfs_p->next = newgenfs;
+		else
+			p->genfs = newgenfs;
+		genfs = newgenfs;
+		newgenfs = NULL;
+
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+
+		nel2 = le32_to_cpu(buf[0]);
+		for (j = 0; j < nel2; j++) {
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+			len = le32_to_cpu(buf[0]);
+
+			rc = -ENOMEM;
+			newc = kzalloc(sizeof(*newc), GFP_KERNEL);
+			if (!newc)
+				goto out;
+
+			rc = -ENOMEM;
+			newc->u.name = kmalloc(len + 1, GFP_KERNEL);
+			if (!newc->u.name)
+				goto out;
+
+			rc = next_entry(newc->u.name, fp, len);
+			if (rc)
+				goto out;
+			newc->u.name[len] = 0;
+
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+
+			newc->v.sclass = le32_to_cpu(buf[0]);
+			rc = context_read_and_validate(&newc->context[0], p, fp);
+			if (rc)

security/selinux/ss/policydb.c out: · line 1877

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+				goto out;
+
+			for (l = NULL, c = genfs->head; c;
+			     l = c, c = c->next) {
+				if (!strcmp(newc->u.name, c->u.name) &&
+				    (!c->v.sclass || !newc->v.sclass ||
+				     newc->v.sclass == c->v.sclass)) {
+					printk(KERN_ERR "SELinux:  dup genfs entry (%s,%s)\n",
+					       genfs->fstype, c->u.name);
+					goto out;

rc wasn't set.

Quoted 15 lines
Quoted 5 lines
security/selinux/ss/policydb.c +5 -0
+				}
+				len = strlen(newc->u.name);
+				len2 = strlen(c->u.name);
+				if (len > len2)
+					break;

security/selinux/ss/policydb.c out: · line 1892

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+			}
+
+			newc->next = c;
+			if (l)
+				l->next = newc;
+			else
+				genfs->head = newc;
+			newc = NULL;
+		}
+	}

Also, for safety, shouldn't we explicitly set rc = 0; here so that no prior assignment of rc will fall through. Regardless of whether that is possible with the current code - just do it now for maintainability.

Quoted 12 lines
Quoted 12 lines
security/selinux/ss/policydb.c +9 -0
+out:
+	if (newgenfs)
+		kfree(newgenfs->fstype);
+	kfree(newgenfs);
+	ocontext_destroy(newc, OCON_FSUSE);
+
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#4 lore raw

PATCH 3/4 SELinux: break ocontext reading into a separate function

In reply to Eric Paris

Move the reading of ocontext type data out of policydb_read() in a separate function ocontext_read()

---

 security/selinux/ss/policydb.c |  242 ++++++++++++++++++++++------------------
 1 files changed, 131 insertions(+), 111 deletions(-)
security/selinux/ss/policydb.c +131 -111
index 66e217b..99fff0c 100644
@@ -1899,6 +1899,134 @@ out:
 	return rc;
 }
 
+static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
+			 void *fp)
+{
+	int i, j, rc;
+	u32 nel, len;
+	__le32 buf[3];
+	struct ocontext *l, *c;
+	u32 nodebuf[8];
+
+	for (i = 0; i < info->ocon_num; i++) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+		nel = le32_to_cpu(buf[0]);
+
+		l = NULL;
+		for (j = 0; j < nel; j++) {
+			rc = -ENOMEM;
+			c = kzalloc(sizeof(*c), GFP_KERNEL);
+			if (!c)
+				goto out;
+			if (l)
+				l->next = c;
+			else
+				p->ocontexts[i] = c;
+			l = c;
+
+			switch (i) {
+			case OCON_ISID:
+				rc = next_entry(buf, fp, sizeof(u32));
+				if (rc)
+					goto out;
+
+				c->sid[0] = le32_to_cpu(buf[0]);
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_FS:
+			case OCON_NETIF:
+				rc = next_entry(buf, fp, sizeof(u32));
+				if (rc)
+					goto out;
+				len = le32_to_cpu(buf[0]);
+
+				rc = -ENOMEM;
+				c->u.name = kmalloc(len + 1, GFP_KERNEL);
+				if (!c->u.name)
+					goto out;
+
+				rc = next_entry(c->u.name, fp, len);
+				if (rc)
+					goto out;
+
+				c->u.name[len] = 0;
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				rc = context_read_and_validate(&c->context[1], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_PORT:
+				rc = next_entry(buf, fp, sizeof(u32)*3);
+				if (rc)
+					goto out;
+				c->u.port.protocol = le32_to_cpu(buf[0]);
+				c->u.port.low_port = le32_to_cpu(buf[1]);
+				c->u.port.high_port = le32_to_cpu(buf[2]);
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_NODE:
+				rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
+				if (rc)
+					goto out;
+				c->u.node.addr = nodebuf[0]; /* network order */
+				c->u.node.mask = nodebuf[1]; /* network order */
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_FSUSE:
+				rc = next_entry(buf, fp, sizeof(u32)*2);
+				if (rc)
+					goto out;
+				c->v.behavior = le32_to_cpu(buf[0]);
+				if (c->v.behavior > SECURITY_FS_USE_NONE)
+					goto out;
+
+				rc = -ENOMEM;
+				len = le32_to_cpu(buf[1]);
+				c->u.name = kmalloc(len + 1, GFP_KERNEL);
+				if (!c->u.name)
+					goto out;
+
+				rc = next_entry(c->u.name, fp, len);
+				if (rc)
+					goto out;
+				c->u.name[len] = 0;
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_NODE6: {
+				int k;
+
+				rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
+				if (rc)
+					goto out;
+				for (k = 0; k < 4; k++)
+					c->u.node6.addr[k] = nodebuf[k];
+				for (k = 0; k < 4; k++)
+					c->u.node6.mask[k] = nodebuf[k+4];
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			}
+			}
+		}
+	}
+	rc = 0;
+out:
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1907,10 +2035,8 @@ int policydb_read(struct policydb *p, void *fp)
 {
 	struct role_allow *ra, *lra;
 	struct role_trans *tr, *ltr;
-	struct ocontext *l, *c;
 	int i, j, rc;
 	__le32 buf[4];
-	u32 nodebuf[8];
 	u32 len, nprim, nel;
 
 	char *policydb_str;
@@ -2115,115 +2241,9 @@ int policydb_read(struct policydb *p, void *fp)
 	if (!p->process_trans_perms)
 		goto bad;
 
-	for (i = 0; i < info->ocon_num; i++) {
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel = le32_to_cpu(buf[0]);
-		l = NULL;
-		for (j = 0; j < nel; j++) {
-			c = kzalloc(sizeof(*c), GFP_KERNEL);
-			if (!c) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-			if (l)
-				l->next = c;
-			else
-				p->ocontexts[i] = c;
-			l = c;
-			rc = -EINVAL;
-			switch (i) {
-			case OCON_ISID:
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0)
-					goto bad;
-				c->sid[0] = le32_to_cpu(buf[0]);
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_FS:
-			case OCON_NETIF:
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0)
-					goto bad;
-				len = le32_to_cpu(buf[0]);
-				c->u.name = kmalloc(len + 1, GFP_KERNEL);
-				if (!c->u.name) {
-					rc = -ENOMEM;
-					goto bad;
-				}
-				rc = next_entry(c->u.name, fp, len);
-				if (rc < 0)
-					goto bad;
-				c->u.name[len] = 0;
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				rc = context_read_and_validate(&c->context[1], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_PORT:
-				rc = next_entry(buf, fp, sizeof(u32)*3);
-				if (rc < 0)
-					goto bad;
-				c->u.port.protocol = le32_to_cpu(buf[0]);
-				c->u.port.low_port = le32_to_cpu(buf[1]);
-				c->u.port.high_port = le32_to_cpu(buf[2]);
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_NODE:
-				rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
-				if (rc < 0)
-					goto bad;
-				c->u.node.addr = nodebuf[0]; /* network order */
-				c->u.node.mask = nodebuf[1]; /* network order */
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_FSUSE:
-				rc = next_entry(buf, fp, sizeof(u32)*2);
-				if (rc < 0)
-					goto bad;
-				c->v.behavior = le32_to_cpu(buf[0]);
-				if (c->v.behavior > SECURITY_FS_USE_NONE)
-					goto bad;
-				len = le32_to_cpu(buf[1]);
-				c->u.name = kmalloc(len + 1, GFP_KERNEL);
-				if (!c->u.name) {
-					rc = -ENOMEM;
-					goto bad;
-				}
-				rc = next_entry(c->u.name, fp, len);
-				if (rc < 0)
-					goto bad;
-				c->u.name[len] = 0;
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_NODE6: {
-				int k;
-
-				rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
-				if (rc < 0)
-					goto bad;
-				for (k = 0; k < 4; k++)
-					c->u.node6.addr[k] = nodebuf[k];
-				for (k = 0; k < 4; k++)
-					c->u.node6.mask[k] = nodebuf[k+4];
-				if (context_read_and_validate(&c->context[0], p, fp))
-					goto bad;
-				break;
-			}
-			}
-		}
-	}
+	rc = ocontext_read(p, info, fp);
+	if (rc)
+		goto bad;
 
 	rc = genfs_read(p, fp);
 	if (rc)

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#5 lore raw

Re: [PATCH 3/4] SELinux: break ocontext reading into a separate function

Quoted 97 lines · Eric Paris

Move the reading of ocontext type data out of policydb_read() in a separate function ocontext_read()

---

 security/selinux/ss/policydb.c |  242 ++++++++++++++++++++++------------------
 1 files changed, 131 insertions(+), 111 deletions(-)
security/selinux/ss/policydb.c +80 -0
index 66e217b..99fff0c 100644
@@ -1899,6 +1899,134 @@ out:
 	return rc;
 }
 
+static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
+			 void *fp)
+{
+	int i, j, rc;
+	u32 nel, len;
+	__le32 buf[3];
+	struct ocontext *l, *c;
+	u32 nodebuf[8];
+
+	for (i = 0; i < info->ocon_num; i++) {
+		rc = next_entry(buf, fp, sizeof(u32));
+		if (rc)
+			goto out;
+		nel = le32_to_cpu(buf[0]);
+
+		l = NULL;
+		for (j = 0; j < nel; j++) {
+			rc = -ENOMEM;
+			c = kzalloc(sizeof(*c), GFP_KERNEL);
+			if (!c)
+				goto out;
+			if (l)
+				l->next = c;
+			else
+				p->ocontexts[i] = c;
+			l = c;
+
+			switch (i) {
+			case OCON_ISID:
+				rc = next_entry(buf, fp, sizeof(u32));
+				if (rc)
+					goto out;
+
+				c->sid[0] = le32_to_cpu(buf[0]);
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_FS:
+			case OCON_NETIF:
+				rc = next_entry(buf, fp, sizeof(u32));
+				if (rc)
+					goto out;
+				len = le32_to_cpu(buf[0]);
+
+				rc = -ENOMEM;
+				c->u.name = kmalloc(len + 1, GFP_KERNEL);
+				if (!c->u.name)
+					goto out;
+
+				rc = next_entry(c->u.name, fp, len);
+				if (rc)
+					goto out;
+
+				c->u.name[len] = 0;
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				rc = context_read_and_validate(&c->context[1], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_PORT:
+				rc = next_entry(buf, fp, sizeof(u32)*3);
+				if (rc)
+					goto out;
+				c->u.port.protocol = le32_to_cpu(buf[0]);
+				c->u.port.low_port = le32_to_cpu(buf[1]);
+				c->u.port.high_port = le32_to_cpu(buf[2]);
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_NODE:
+				rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
+				if (rc)
+					goto out;
+				c->u.node.addr = nodebuf[0]; /* network order */
+				c->u.node.mask = nodebuf[1]; /* network order */
+				rc = context_read_and_validate(&c->context[0], p, fp);

security/selinux/ss/policydb.c out: · line 1991

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+				if (rc)
+					goto out;
+				break;
+			case OCON_FSUSE:
+				rc = next_entry(buf, fp, sizeof(u32)*2);
+				if (rc)
+					goto out;
+				c->v.behavior = le32_to_cpu(buf[0]);
+				if (c->v.behavior > SECURITY_FS_USE_NONE)
+					goto out;

rc is not set here.

Quoted 171 lines
security/selinux/ss/policydb.c +41 -111
+
+				rc = -ENOMEM;
+				len = le32_to_cpu(buf[1]);
+				c->u.name = kmalloc(len + 1, GFP_KERNEL);
+				if (!c->u.name)
+					goto out;
+
+				rc = next_entry(c->u.name, fp, len);
+				if (rc)
+					goto out;
+				c->u.name[len] = 0;
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			case OCON_NODE6: {
+				int k;
+
+				rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
+				if (rc)
+					goto out;
+				for (k = 0; k < 4; k++)
+					c->u.node6.addr[k] = nodebuf[k];
+				for (k = 0; k < 4; k++)
+					c->u.node6.mask[k] = nodebuf[k+4];
+				rc = context_read_and_validate(&c->context[0], p, fp);
+				if (rc)
+					goto out;
+				break;
+			}
+			}
+		}
+	}
+	rc = 0;
+out:
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1907,10 +2035,8 @@ int policydb_read(struct policydb *p, void *fp)
 {
 	struct role_allow *ra, *lra;
 	struct role_trans *tr, *ltr;
-	struct ocontext *l, *c;
 	int i, j, rc;
 	__le32 buf[4];
-	u32 nodebuf[8];
 	u32 len, nprim, nel;
 
 	char *policydb_str;
@@ -2115,115 +2241,9 @@ int policydb_read(struct policydb *p, void *fp)
 	if (!p->process_trans_perms)
 		goto bad;
 
-	for (i = 0; i < info->ocon_num; i++) {
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel = le32_to_cpu(buf[0]);
-		l = NULL;
-		for (j = 0; j < nel; j++) {
-			c = kzalloc(sizeof(*c), GFP_KERNEL);
-			if (!c) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-			if (l)
-				l->next = c;
-			else
-				p->ocontexts[i] = c;
-			l = c;
-			rc = -EINVAL;
-			switch (i) {
-			case OCON_ISID:
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0)
-					goto bad;
-				c->sid[0] = le32_to_cpu(buf[0]);
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_FS:
-			case OCON_NETIF:
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0)
-					goto bad;
-				len = le32_to_cpu(buf[0]);
-				c->u.name = kmalloc(len + 1, GFP_KERNEL);
-				if (!c->u.name) {
-					rc = -ENOMEM;
-					goto bad;
-				}
-				rc = next_entry(c->u.name, fp, len);
-				if (rc < 0)
-					goto bad;
-				c->u.name[len] = 0;
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				rc = context_read_and_validate(&c->context[1], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_PORT:
-				rc = next_entry(buf, fp, sizeof(u32)*3);
-				if (rc < 0)
-					goto bad;
-				c->u.port.protocol = le32_to_cpu(buf[0]);
-				c->u.port.low_port = le32_to_cpu(buf[1]);
-				c->u.port.high_port = le32_to_cpu(buf[2]);
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_NODE:
-				rc = next_entry(nodebuf, fp, sizeof(u32) * 2);
-				if (rc < 0)
-					goto bad;
-				c->u.node.addr = nodebuf[0]; /* network order */
-				c->u.node.mask = nodebuf[1]; /* network order */
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_FSUSE:
-				rc = next_entry(buf, fp, sizeof(u32)*2);
-				if (rc < 0)
-					goto bad;
-				c->v.behavior = le32_to_cpu(buf[0]);
-				if (c->v.behavior > SECURITY_FS_USE_NONE)
-					goto bad;
-				len = le32_to_cpu(buf[1]);
-				c->u.name = kmalloc(len + 1, GFP_KERNEL);
-				if (!c->u.name) {
-					rc = -ENOMEM;
-					goto bad;
-				}
-				rc = next_entry(c->u.name, fp, len);
-				if (rc < 0)
-					goto bad;
-				c->u.name[len] = 0;
-				rc = context_read_and_validate(&c->context[0], p, fp);
-				if (rc)
-					goto bad;
-				break;
-			case OCON_NODE6: {
-				int k;
-
-				rc = next_entry(nodebuf, fp, sizeof(u32) * 8);
-				if (rc < 0)
-					goto bad;
-				for (k = 0; k < 4; k++)
-					c->u.node6.addr[k] = nodebuf[k];
-				for (k = 0; k < 4; k++)
-					c->u.node6.mask[k] = nodebuf[k+4];
-				if (context_read_and_validate(&c->context[0], p, fp))
-					goto bad;
-				break;
-			}
-			}
-		}
-	}
+	rc = ocontext_read(p, info, fp);
+	if (rc)
+		goto bad;
 
 	rc = genfs_read(p, fp);
 	if (rc)
Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#6 lore raw

PATCH 4/4 SELinux: allow userspace to read policy back out of the kernel

In reply to Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

---

 include/linux/kernel.h              |    1 
 security/selinux/include/security.h |    1 
 security/selinux/selinuxfs.c        |   46 ++
 security/selinux/ss/avtab.c         |   42 ++
 security/selinux/ss/avtab.h         |    2 
 security/selinux/ss/conditional.c   |  123 +++++
 security/selinux/ss/conditional.h   |    2 
 security/selinux/ss/ebitmap.c       |   83 +++
 security/selinux/ss/ebitmap.h       |    1 
 security/selinux/ss/policydb.c      |  838 +++++++++++++++++++++++++++++++++++
 security/selinux/ss/policydb.h      |   22 +
 security/selinux/ss/services.c      |   25 +
 12 files changed, 1183 insertions(+), 3 deletions(-)
include/linux/kernel.h +1 -0
index 8317ec4..235f39f 100644
@@ -59,6 +59,7 @@ extern const char linux_proc_banner[];
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
 #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define rounddown(x, y) ((x) - ((x) % (y)))
 #define DIV_ROUND_CLOSEST(x, divisor)(			\
 {							\
 	typeof(divisor) __divisor = divisor;		\
security/selinux/include/security.h +1 -0
index 1f7c249..9ff9a39 100644
@@ -82,6 +82,7 @@ extern int selinux_policycap_openperm;
 int security_mls_enabled(void);
 
 int security_load_policy(void *data, size_t len);
+int security_read_policy(void *data, ssize_t *len);
 
 int security_policycap_supported(unsigned int req_cap);
 
security/selinux/selinuxfs.c +46 -0

64 lines not on this page · raw message

security/selinux/ss/avtab.c +42 -0

48 lines not on this page · raw message

security/selinux/ss/avtab.h +2 -0
index cd4f734..de1f8b6 100644
@@ -71,6 +71,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
 		    void *p);
 
 int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
+int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp);
+int avtab_write(struct policydb *p, struct avtab *a, void *fp);
 
 struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
 					  struct avtab_datum *datum);
security/selinux/ss/conditional.c +123 -0

129 lines not on this page · raw message

security/selinux/ss/conditional.h +2 -0
index 53ddb01..3f209c6 100644
@@ -69,6 +69,8 @@ int cond_index_bool(void *key, void *datum, void *datap);
 
 int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
 int cond_read_list(struct policydb *p, void *fp);
+int cond_write_bool(void *key, void *datum, void *ptr);
+int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
 
 void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
 
security/selinux/ss/ebitmap.c +81 -2

100 lines not on this page · raw message

security/selinux/ss/ebitmap.h +1 -0
index f283b43..1f4e93c 100644
@@ -123,6 +123,7 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
 int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
 void ebitmap_destroy(struct ebitmap *e);
 int ebitmap_read(struct ebitmap *e, void *fp);
+int ebitmap_write(struct ebitmap *e, void *fp);
 
 #ifdef CONFIG_NETLABEL
 int ebitmap_netlbl_export(struct ebitmap *ebmap,
security/selinux/ss/policydb.c +838 -0

847 lines not on this page · raw message

security/selinux/ss/policydb.h +22 -0
index 26d9adf..9911768 100644
@@ -268,6 +268,7 @@ extern int policydb_class_isvalid(struct policydb *p, unsigned int class);
 extern int policydb_type_isvalid(struct policydb *p, unsigned int type);
 extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
 extern int policydb_read(struct policydb *p, void *fp);
+extern int policydb_write(struct policydb *p, void *fp);
 
 #define PERM_SYMTAB_SIZE 32
 
@@ -288,6 +289,11 @@ struct policy_file {
 	size_t len;
 };
 
+struct policy_data {
+	struct policydb *p;
+	void *fp;
+};
+
 static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
 {
 	if (bytes > fp->len)
@@ -299,6 +305,22 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
 	return 0;
 }
 
+static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp)
+{
+	size_t len = bytes * num;
+
+	if (len > fp->len) {
+		printk(KERN_DEBUG "%s: policy was larger than allowed in single read\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	memcpy(fp->data, buf, len);
+	fp->data += len;
+	fp->len -= len;
+	return 0;
+}
+
 extern u16 string_to_security_class(struct policydb *p, const char *name);
 extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name);
 
security/selinux/ss/services.c +24 -1
index 1de60ce..2e022db 100644
@@ -87,7 +87,6 @@ int ss_initialized;
  */
 static u32 latest_granting;
 
-/* Forward declaration. */
 static int context_struct_to_string(struct context *context, char **scontext,
 				    u32 *scontext_len);
 
@@ -3126,3 +3125,27 @@ netlbl_sid_to_secattr_failure:
 	return rc;
 }
 #endif /* CONFIG_NETLABEL */
+
+/**
+ * security_read_policy - read the policy.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ */
+int security_read_policy(void *data, ssize_t *len)
+{
+	int rc = 0;
+	struct policy_file file = { data, *len }, *fp = &file;
+
+	if (!ss_initialized)
+		return -EINVAL;
+
+	read_lock_irq(&policy_rwlock);
+	rc = policydb_write(&policydb, fp);
+	read_unlock_irq(&policy_rwlock);
+
+	*len = (unsigned long)fp->data - (unsigned long)data;
+
+	return rc;
+
+}

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#7 lore raw

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

Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

Why a new node vs a read op for /selinux/load?

Quoted 26 lines

---

security/selinux/ss/services.c +14 -0
index 1de60ce..2e022db 100644
@@ -3126,3 +3125,27 @@ netlbl_sid_to_secattr_failure:
 	return rc;
 }
 #endif /* CONFIG_NETLABEL */
+
+/**
+ * security_read_policy - read the policy.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ */
+int security_read_policy(void *data, ssize_t *len)
+{
+	int rc = 0;
+	struct policy_file file = { data, *len }, *fp = &file;
+
+	if (!ss_initialized)
+		return -EINVAL;

security/selinux/ss/services.c netlbl_sid_to_secattr_failure: · line 3151

Quoted 10 lines
security/selinux/ss/services.c +10 -0
+
+	read_lock_irq(&policy_rwlock);
+	rc = policydb_write(&policydb, fp);
+	read_unlock_irq(&policy_rwlock);
+
+	*len = (unsigned long)fp->data - (unsigned long)data;
+
+	return rc;
+
+}

Why _irq?

Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#8 lore raw

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

Quoted 7 lines · Stephen Smalley
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

Why a new node vs a read op for /selinux/load?

No reason why I couldn't. Just 'load' seemed to imply a connotation which wasn't appropriate. If you prefer I'll switch it when I do another version.

-Eric

Quoted 31 lines
Quoted 31 lines

---

security/selinux/ss/services.c +18 -0
index 1de60ce..2e022db 100644
@@ -3126,3 +3125,27 @@ netlbl_sid_to_secattr_failure:
 	return rc;
 }
 #endif /* CONFIG_NETLABEL */
+
+/**
+ * security_read_policy - read the policy.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ */
+int security_read_policy(void *data, ssize_t *len)
+{
+	int rc = 0;
+	struct policy_file file = { data, *len }, *fp = &file;
+
+	if (!ss_initialized)
+		return -EINVAL;
+
+	read_lock_irq(&policy_rwlock);
+	rc = policydb_write(&policydb, fp);
+	read_unlock_irq(&policy_rwlock);
Quoted 8 lines

security/selinux/ss/services.c netlbl_sid_to_secattr_failure: · line 3151

Quoted 6 lines
security/selinux/ss/services.c +6 -0
+
+	*len = (unsigned long)fp->data - (unsigned long)data;
+
+	return rc;
+
+}

Why _irq?

Stolen from security_load_policy() and shouldn't have been. Will fix.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#9 lore raw

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

Quoted 9 lines · Eric Paris
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

Quoted 7 lines
Quoted 2 lines

Why a new node vs a read op for /selinux/load?

No reason why I couldn't. Just 'load' seemed to imply a connotation which wasn't appropriate. If you prefer I'll switch it when I do another version.

If it makes any difference Smack /smack/load does read as well as write. You have the opportunity to make 2 or 3 users less confused if you do things consistently. After all, Smack uses load because SELinux does, the name is actually arbitrary, and why do something differently when it doesn't really matter?

Quoted 42 lines

-Eric

Quoted 30 lines
Quoted 30 lines

---

security/selinux/ss/services.c +18 -0
index 1de60ce..2e022db 100644
@@ -3126,3 +3125,27 @@ netlbl_sid_to_secattr_failure:
 	return rc;
 }
 #endif /* CONFIG_NETLABEL */
+
+/**
+ * security_read_policy - read the policy.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ */
+int security_read_policy(void *data, ssize_t *len)
+{
+	int rc = 0;
+	struct policy_file file = { data, *len }, *fp = &file;
+
+	if (!ss_initialized)
+		return -EINVAL;
+
+	read_lock_irq(&policy_rwlock);
+	rc = policydb_write(&policydb, fp);
+	read_unlock_irq(&policy_rwlock);
Quoted 9 lines

security/selinux/ss/services.c netlbl_sid_to_secattr_failure: · line 3151

Quoted 7 lines
security/selinux/ss/services.c +6 -0
+
+	*len = (unsigned long)fp->data - (unsigned long)data;
+
+	return rc;
+
+}

Why _irq?

Quoted 10 lines

Stolen from security_load_policy() and shouldn't have been. Will fix.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] 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 [email protected] with the words "unsubscribe selinux" without quotes as the message.

author
#10 lore raw

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

Quoted 18 lines · Casey Schaufler
Quoted 9 lines · Eric Paris
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

Quoted 7 lines
Quoted 2 lines

Why a new node vs a read op for /selinux/load?

No reason why I couldn't. Just 'load' seemed to imply a connotation which wasn't appropriate. If you prefer I'll switch it when I do another version.

Quoted 5 lines

If it makes any difference Smack /smack/load does read as well as write. You have the opportunity to make 2 or 3 users less confused if you do things consistently. After all, Smack uses load because SELinux does, the name is actually arbitrary, and why do something differently when it doesn't really matter?

I did two things yesterday. First I switch the read
from /selinux/policy to /selinux/load. Then I undid that change and started generating the in kernel policy buffer on open() rather than on read(). It allowed me to use cat /etc/policy > policy rather than using my own half ass hacked utility. The reason I undid the policy->load change was because I didn't really want to store the old policy on open if they were going to write() a new policy. I can probably make the determination based on the f_mode, but didn't really play with it yet. I try to do both in the next go-round.

I'm still trying to figure out what I did to make malformed policies. Must have screwed something up ripping out my prink's and debug hooks, because it isn't working for me now either....

Unrelated note, can we take patches 1,2,3 ? They are just cleanups....

-Eric

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#11 lore raw

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

Quoted 25 lines · Eric Paris
Quoted 18 lines · Casey Schaufler
Quoted 9 lines · Eric Paris
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

Quoted 7 lines
Quoted 2 lines

Why a new node vs a read op for /selinux/load?

No reason why I couldn't. Just 'load' seemed to imply a connotation which wasn't appropriate. If you prefer I'll switch it when I do another version.

Quoted 5 lines

If it makes any difference Smack /smack/load does read as well as write. You have the opportunity to make 2 or 3 users less confused if you do things consistently. After all, Smack uses load because SELinux does, the name is actually arbitrary, and why do something differently when it doesn't really matter?

Quoted 9 lines

I did two things yesterday. First I switch the read
from /selinux/policy to /selinux/load. Then I undid that change and started generating the in kernel policy buffer on open() rather than on read(). It allowed me to use cat /etc/policy > policy rather than using my own half ass hacked utility. The reason I undid the policy->load change was because I didn't really want to store the old policy on open if they were going to write() a new policy. I can probably make the determination based on the f_mode, but didn't really play with it yet. I try to do both in the next go-round.

Unfortunately it appears that libselinux security_load_policy() does open("/selinux/load", O_RDWR). Don't ask me why.

Quoted 3 lines

I'm still trying to figure out what I did to make malformed policies. Must have screwed something up ripping out my prink's and debug hooks, because it isn't working for me now either....

Assuming you've just reused the userspace policydb_write() code with minor cleanups for everything except the new ebitmap format, I'd look more closely there.
KaiGai - this is the first time where we need to convert the new kernel ebitmap format back to the old one for generating a policy image from the kernel policydb that can be compared to a policy file.

Quoted 1 line

Unrelated note, can we take patches 1,2,3 ? They are just cleanups....

Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#12 lore raw

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

Quoted 12 lines · Stephen Smalley
Quoted 9 lines · Eric Paris

I did two things yesterday. First I switch the read
from /selinux/policy to /selinux/load. Then I undid that change and started generating the in kernel policy buffer on open() rather than on read(). It allowed me to use cat /etc/policy > policy rather than using my own half ass hacked utility. The reason I undid the policy->load change was because I didn't really want to store the old policy on open if they were going to write() a new policy. I can probably make the determination based on the f_mode, but didn't really play with it yet. I try to do both in the next go-round.

Quoted 2 lines

Unfortunately it appears that libselinux security_load_policy() does open("/selinux/load", O_RDWR). Don't ask me why.

I could still generate the policy on open() if it was opened O_RDONLY. If it was opened O_RDWR read() I 'could' make read() work if the buf was large enough in a single shot. Is that quirk worth the trouble of not creating a new node in /selinux?

Quoted 10 lines
Quoted 3 lines

I'm still trying to figure out what I did to make malformed policies. Must have screwed something up ripping out my prink's and debug hooks, because it isn't working for me now either....

Assuming you've just reused the userspace policydb_write() code with minor cleanups for everything except the new ebitmap format, I'd look more closely there.
KaiGai - this is the first time where we need to convert the new kernel ebitmap format back to the old one for generating a policy image from the kernel policydb that can be compared to a policy file.

No question wrapping my head around the new ebitmap format was the tough part. I added printk's to display every ebitmap and node as it was read in and as I wrote them out. Got the same thing for the couple thousand lines I could show in dmesg, so I think I'm ok there.

I was trying to use gdb yesterday to figure out what was wrong, but could get the darn thing to break where I wanted it to. I'll debug like I'm used to (in the kernel) and see what I did....

-Eric

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#13 lore raw

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

Quoted 13 lines · Eric Paris
Quoted 12 lines · Stephen Smalley
Quoted 9 lines · Eric Paris

I did two things yesterday. First I switch the read
from /selinux/policy to /selinux/load. Then I undid that change and started generating the in kernel policy buffer on open() rather than on read(). It allowed me to use cat /etc/policy > policy rather than using my own half ass hacked utility. The reason I undid the policy->load change was because I didn't really want to store the old policy on open if they were going to write() a new policy. I can probably make the determination based on the f_mode, but didn't really play with it yet. I try to do both in the next go-round.

Quoted 7 lines
Quoted 2 lines

Unfortunately it appears that libselinux security_load_policy() does open("/selinux/load", O_RDWR). Don't ask me why.

I could still generate the policy on open() if it was opened O_RDONLY. If it was opened O_RDWR read() I 'could' make read() work if the buf was large enough in a single shot. Is that quirk worth the trouble of not creating a new node in /selinux?

Probably not.

Quoted 11 lines
Quoted 10 lines
Quoted 3 lines

I'm still trying to figure out what I did to make malformed policies. Must have screwed something up ripping out my prink's and debug hooks, because it isn't working for me now either....

Assuming you've just reused the userspace policydb_write() code with minor cleanups for everything except the new ebitmap format, I'd look more closely there.
KaiGai - this is the first time where we need to convert the new kernel ebitmap format back to the old one for generating a policy image from the kernel policydb that can be compared to a policy file.

Quoted 8 lines

No question wrapping my head around the new ebitmap format was the tough part. I added printk's to display every ebitmap and node as it was read in and as I wrote them out. Got the same thing for the couple thousand lines I could show in dmesg, so I think I'm ok there.

I was trying to use gdb yesterday to figure out what was wrong, but could get the darn thing to break where I wanted it to. I'll debug like I'm used to (in the kernel) and see what I did....

Oh, I found it. mls_write_level() in your patch sets buf[1] rather than buf[0] and then writes buf[0].

Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#14 lore raw

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

Quoted 7 lines · Stephen Smalley
Quoted 5 lines · Eric Paris

No question wrapping my head around the new ebitmap format was the tough part. I added printk's to display every ebitmap and node as it was read in and as I wrote them out. Got the same thing for the couple thousand lines I could show in dmesg, so I think I'm ok there.

Quoted 6 lines
Quoted 3 lines

I was trying to use gdb yesterday to figure out what was wrong, but could get the darn thing to break where I wanted it to. I'll debug like I'm used to (in the kernel) and see what I did....

Oh, I found it. mls_write_level() in your patch sets buf[1] rather than buf[0] and then writes buf[0].

/me feels like the compiler should have been able to find that particular one....

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#15 lore raw

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

In reply to Stephen Smalley
Quoted 43 lines · Stephen Smalley
Quoted 25 lines · Eric Paris
Quoted 18 lines · Casey Schaufler
Quoted 9 lines · Eric Paris
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

Quoted 7 lines
Quoted 2 lines

Why a new node vs a read op for /selinux/load?

No reason why I couldn't. Just 'load' seemed to imply a connotation which wasn't appropriate. If you prefer I'll switch it when I do another version.

Quoted 5 lines

If it makes any difference Smack /smack/load does read as well as write. You have the opportunity to make 2 or 3 users less confused if you do things consistently. After all, Smack uses load because SELinux does, the name is actually arbitrary, and why do something differently when it doesn't really matter?

Quoted 9 lines

I did two things yesterday. First I switch the read
from /selinux/policy to /selinux/load. Then I undid that change and started generating the in kernel policy buffer on open() rather than on read(). It allowed me to use cat /etc/policy> policy rather than using my own half ass hacked utility. The reason I undid the policy->load change was because I didn't really want to store the old policy on open if they were going to write() a new policy. I can probably make the determination based on the f_mode, but didn't really play with it yet. I try to do both in the next go-round.

Unfortunately it appears that libselinux security_load_policy() does open("/selinux/load", O_RDWR). Don't ask me why.

Quoted 3 lines

I'm still trying to figure out what I did to make malformed policies. Must have screwed something up ripping out my prink's and debug hooks, because it isn't working for me now either....

Quoted 7 lines

Assuming you've just reused the userspace policydb_write() code with minor cleanups for everything except the new ebitmap format, I'd look more closely there.
KaiGai - this is the first time where we need to convert the new kernel ebitmap format back to the old one for generating a policy image from the kernel policydb that can be compared to a policy file.

I have a question. Is it necessary the following command being succeeded?

% diff /etc/selinux/targeted/policy/policy.24 /selinux/load

Although it was a few years ago I worked for the ebitmap improvement, it seems to me the new ebitmap_write() correctly writes back entries of the given ebitmap object.

However, it is unclear for me whether this routine can correctly repair the original file image, or not.
For example, if startbit of each ebitmap_node was not aligned to u64 on the policy file, it will be fixed up on ebitmap_read(), so we lost an information that what was the actual startbit of ebitmap_node in the result.

Of course, it might be too much requirement, if we don't need the above diff command returns success.

Thanks,

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#16 lore raw

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

Quoted 66 lines · KaiGai Kohei
Quoted 43 lines · Stephen Smalley
Quoted 25 lines · Eric Paris
Quoted 18 lines · Casey Schaufler
Quoted 9 lines · Eric Paris
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

Quoted 7 lines
Quoted 2 lines

Why a new node vs a read op for /selinux/load?

No reason why I couldn't. Just 'load' seemed to imply a connotation which wasn't appropriate. If you prefer I'll switch it when I do another version.

Quoted 5 lines

If it makes any difference Smack /smack/load does read as well as write. You have the opportunity to make 2 or 3 users less confused if you do things consistently. After all, Smack uses load because SELinux does, the name is actually arbitrary, and why do something differently when it doesn't really matter?

Quoted 9 lines

I did two things yesterday. First I switch the read
from /selinux/policy to /selinux/load. Then I undid that change and started generating the in kernel policy buffer on open() rather than on read(). It allowed me to use cat /etc/policy> policy rather than using my own half ass hacked utility. The reason I undid the policy->load change was because I didn't really want to store the old policy on open if they were going to write() a new policy. I can probably make the determination based on the f_mode, but didn't really play with it yet. I try to do both in the next go-round.

Unfortunately it appears that libselinux security_load_policy() does open("/selinux/load", O_RDWR). Don't ask me why.

Quoted 3 lines

I'm still trying to figure out what I did to make malformed policies. Must have screwed something up ripping out my prink's and debug hooks, because it isn't working for me now either....

Quoted 7 lines

Assuming you've just reused the userspace policydb_write() code with minor cleanups for everything except the new ebitmap format, I'd look more closely there.
KaiGai - this is the first time where we need to convert the new kernel ebitmap format back to the old one for generating a policy image from the kernel policydb that can be compared to a policy file.

I have a question. Is it necessary the following command being succeeded?

% diff /etc/selinux/targeted/policy/policy.24 /selinux/load

Although it was a few years ago I worked for the ebitmap improvement, it seems to me the new ebitmap_write() correctly writes back entries of the given ebitmap object.

However, it is unclear for me whether this routine can correctly repair the original file image, or not.
For example, if startbit of each ebitmap_node was not aligned to u64 on the policy file, it will be fixed up on ebitmap_read(), so we lost an information that what was the actual startbit of ebitmap_node in the result.

Quoted 2 lines

Of course, it might be too much requirement, if we don't need the above diff command returns success.

They do NOT need to be the same (because I deem it so). We already know that range transition rules will likely be reordered in /selinux/load vs policy.24 so minor non-meaningful differences in ebitmaps should not be a problem.

If at some point a person has a reason to require they be the same binary I suggest we change userspace rather than try to maintain needless quirks in the kernel.

-Eric

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#17 lore raw

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

In reply to Eric Paris
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

How do you expect this to be used? As with /selinux/load, we can't use coreutils utilities to manipulate it unfortunately. Nor can we do things like checkpolicy -b /selinux/policy since it doesn't support mmap.

Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#18 lore raw

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

Quoted 10 lines · Stephen Smalley
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

How do you expect this to be used? As with /selinux/load, we can't use coreutils utilities to manipulate it unfortunately. Nor can we do things like checkpolicy -b /selinux/policy since it doesn't support mmap.

It doesn't seem useful if I can't do things like:
seinfo /selinux/policy
cmp /selinux/policy /etc/selinux/$SELINUXTYPE/policy/policy.24 sediff /selinux/policy \; /etc/selinux/$SELINUXTYPE/poilcy/policy.24

Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#19 lore raw

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

In reply to Stephen Smalley
Quoted 10 lines · Stephen Smalley
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

How do you expect this to be used? As with /selinux/load, we can't use coreutils utilities to manipulate it unfortunately. Nor can we do things like checkpolicy -b /selinux/policy since it doesn't support mmap.

I used my own program to pull it out to a file and poke it after it was out. I can certainly take a look at generating the policy on open() which would allow us to support ppos easily (and maybe mmap, but I've never written an mmap handler)

#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define BUFLEN (10 * 1024 * 1024)

int main(int argc, char *argv[])

{
	char *buf;
	ssize_t len;
	int polfd;
	int outfd;
	int ret;

	polfd = open("/selinux/policy", O_RDONLY);
	if (polfd < 0)
		return 1;

	outfd = open("policy.from.kern", O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
	if (outfd < 0)
		return 2;

	ret = ftruncate(outfd, BUFLEN);
	if (ret) {
		perror("ftruncate");
		return 3;
	}

	buf =  mmap(NULL, BUFLEN, PROT_WRITE, MAP_SHARED, outfd, 0);
	if (buf == MAP_FAILED) {
		perror("mmap");
		return 4;
	}

	ret = read(polfd, buf, BUFLEN);
	if (ret < 0) {
		perror("write");
		return 5;
	}

	len = ret;

	msync(buf, len, MS_SYNC);

	ftruncate(outfd, len);

	return 0;
}

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#20 lore raw

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

Quoted 12 lines · Eric Paris
Quoted 10 lines · Stephen Smalley
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

How do you expect this to be used? As with /selinux/load, we can't use coreutils utilities to manipulate it unfortunately. Nor can we do things like checkpolicy -b /selinux/policy since it doesn't support mmap.

Quoted 4 lines

I used my own program to pull it out to a file and poke it after it was out. I can certainly take a look at generating the policy on open() which would allow us to support ppos easily (and maybe mmap, but I've never written an mmap handler)

Hmm...the resulting policy.from.kern doesn't match the binary policy file that was loaded, nor is it a well-formed policy.

Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
author
#21 lore raw

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

Quoted 13 lines · Stephen Smalley
Quoted 12 lines · Eric Paris
Quoted 10 lines · Stephen Smalley
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

How do you expect this to be used? As with /selinux/load, we can't use coreutils utilities to manipulate it unfortunately. Nor can we do things like checkpolicy -b /selinux/policy since it doesn't support mmap.

Quoted 7 lines
Quoted 4 lines

I used my own program to pull it out to a file and poke it after it was out. I can certainly take a look at generating the policy on open() which would allow us to support ppos easily (and maybe mmap, but I've never written an mmap handler)

Hmm...the resulting policy.from.kern doesn't match the binary policy file that was loaded, nor is it a well-formed policy.

It won't be a binary perfect match since we switched range transition rules to a hashtab and we lose ordering in the kernel. (although the second load and resulting read should be the same binary policy)

What is not well-formed about your result? I got back the same policy (according to sediff) but I was using selinux-policy-minimum....

-Eric

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#22 lore raw

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

Quoted 22 lines · Eric Paris
Quoted 13 lines · Stephen Smalley
Quoted 12 lines · Eric Paris
Quoted 10 lines · Stephen Smalley
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

How do you expect this to be used? As with /selinux/load, we can't use coreutils utilities to manipulate it unfortunately. Nor can we do things like checkpolicy -b /selinux/policy since it doesn't support mmap.

Quoted 7 lines
Quoted 4 lines

I used my own program to pull it out to a file and poke it after it was out. I can certainly take a look at generating the policy on open() which would allow us to support ppos easily (and maybe mmap, but I've never written an mmap handler)

Hmm...the resulting policy.from.kern doesn't match the binary policy file that was loaded, nor is it a well-formed policy.

Quoted 6 lines

It won't be a binary perfect match since we switched range transition rules to a hashtab and we lose ordering in the kernel. (although the second load and resulting read should be the same binary policy)

What is not well-formed about your result? I got back the same policy (according to sediff) but I was using selinux-policy-minimum....

Breakpoint 2, sens_index (key=0x6ac120 "s0", datum=0x6ac100, datap=0x658960)

    at policydb.c:753

753 return -EINVAL;
(gdb) print *levdatum->level
$1 = {sens = 1501285952, cat = {node = 0x6ac160, highbit = 1024}} (gdb) where
#0 sens_index (key=0x6ac120 "s0", datum=0x6ac100, datap=0x658960)

    at policydb.c:753
#1  0x0000000000423915 in hashtab_map (h=0x65e7a0, 
    apply=0x42f5d3 <sens_index>, args=0x658960) at hashtab.c:235
#2  0x000000000042fdb3 in policydb_index_others (handle=0x0, p=0x658960, 
    verbose=1) at policydb.c:917
#3  0x0000000000436571 in policydb_read (p=0x658960, fp=0x7fffffffe0d0, 
    verbose=1) at policydb.c:3486

#4 0x0000000000401f85 in main (argc=3, argv=0x7fffffffe3e8)
at checkpolicy.c:526

Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#23 lore raw

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

In reply to Eric Paris
Quoted 22 lines · Eric Paris
Quoted 13 lines · Stephen Smalley
Quoted 12 lines · Eric Paris
Quoted 10 lines · Stephen Smalley
Quoted 4 lines · Eric Paris

There is interest in being able to see what the actual policy is that was loaded into the kernel. The patch creates a new selinuxfs file /selinux/policy which can be read by userspace. The actual policy that is loaded into the kernel will be written back out to userspace.

How do you expect this to be used? As with /selinux/load, we can't use coreutils utilities to manipulate it unfortunately. Nor can we do things like checkpolicy -b /selinux/policy since it doesn't support mmap.

Quoted 7 lines
Quoted 4 lines

I used my own program to pull it out to a file and poke it after it was out. I can certainly take a look at generating the policy on open() which would allow us to support ppos easily (and maybe mmap, but I've never written an mmap handler)

Hmm...the resulting policy.from.kern doesn't match the binary policy file that was loaded, nor is it a well-formed policy.

Quoted 6 lines

It won't be a binary perfect match since we switched range transition rules to a hashtab and we lose ordering in the kernel. (although the second load and resulting read should be the same binary policy)

What is not well-formed about your result? I got back the same policy (according to sediff) but I was using selinux-policy-minimum....

I'm just catching up, but a word of warning: sediff does not diff constraints yet.

Signature · 9 lines
Chris PeBenito
Tresys Technology, LLC
www.tresys.com | oss.tresys.com


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
Acked-by on v1 1/4
#24 lore raw
In reply to Eric Paris
Quoted 4 lines · Eric Paris

Move the range transition rule to a separate function, range_read(), rather than doing it all in policydb_read()

Quoted 169 lines

---

 security/selinux/ss/policydb.c |  139 ++++++++++++++++++++++------------------
 1 files changed, 75 insertions(+), 64 deletions(-)
security/selinux/ss/policydb.c +75 -64
index c57802a..a39d38a 100644
@@ -1701,6 +1701,78 @@ u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name)
 	return 1U << (perdatum->value-1);
 }
 
+static int range_read(struct policydb *p, void *fp)
+{
+	struct range_trans *rt = NULL;
+	struct mls_range *r = NULL;
+	int i, rc;
+	__le32 buf[2];
+	u32 nel;
+
+	if (p->policyvers < POLICYDB_VERSION_MLS)
+		return 0;
+
+	rc = next_entry(buf, fp, sizeof(u32));
+	if (rc)
+		goto out;
+
+	nel = le32_to_cpu(buf[0]);
+	for (i = 0; i < nel; i++) {
+		rc = -ENOMEM;
+		rt = kzalloc(sizeof(*rt), GFP_KERNEL);
+		if (!rt)
+			goto out;
+
+		rc = next_entry(buf, fp, (sizeof(u32) * 2));
+		if (rc)
+			goto out;
+
+		rt->source_type = le32_to_cpu(buf[0]);
+		rt->target_type = le32_to_cpu(buf[1]);
+		if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
+			rc = next_entry(buf, fp, sizeof(u32));
+			if (rc)
+				goto out;
+			rt->target_class = le32_to_cpu(buf[0]);
+		} else
+			rt->target_class = p->process_class;
+
+		rc = -EINVAL;
+		if (!policydb_type_isvalid(p, rt->source_type) ||
+		    !policydb_type_isvalid(p, rt->target_type) ||
+		    !policydb_class_isvalid(p, rt->target_class))
+			goto out;
+
+		rc = -ENOMEM;
+		r = kzalloc(sizeof(*r), GFP_KERNEL);
+		if (!r)
+			goto out;
+
+		rc = mls_read_range_helper(r, fp);
+		if (rc)
+			goto out;
+
+		rc = -EINVAL;
+		if (!mls_range_isvalid(p, r)) {
+			printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
+			goto out;
+		}
+
+		rc = hashtab_insert(p->range_tr, rt, r);
+		if (rc)
+			goto out;
+
+		rt = NULL;
+		r = NULL;
+	}
+	rangetr_hash_eval(p->range_tr);
+	rc = 0;
+out:
+	kfree(rt);
+	kfree(r);
+	return rc;
+}
+
 /*
  * Read the configuration data from a policy database binary
  * representation file into a policy database structure.
@@ -1717,8 +1789,6 @@ int policydb_read(struct policydb *p, void *fp)
 	u32 len, len2, nprim, nel, nel2;
 	char *policydb_str;
 	struct policydb_compat_info *info;
-	struct range_trans *rt;
-	struct mls_range *r;
 
 	rc = policydb_init(p);
 	if (rc)
@@ -2131,68 +2201,9 @@ int policydb_read(struct policydb *p, void *fp)
 		}
 	}
 
-	if (p->policyvers >= POLICYDB_VERSION_MLS) {
-		int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
-		rc = next_entry(buf, fp, sizeof(u32));
-		if (rc < 0)
-			goto bad;
-		nel = le32_to_cpu(buf[0]);
-		for (i = 0; i < nel; i++) {
-			rt = kzalloc(sizeof(*rt), GFP_KERNEL);
-			if (!rt) {
-				rc = -ENOMEM;
-				goto bad;
-			}
-			rc = next_entry(buf, fp, (sizeof(u32) * 2));
-			if (rc < 0) {
-				kfree(rt);
-				goto bad;
-			}
-			rt->source_type = le32_to_cpu(buf[0]);
-			rt->target_type = le32_to_cpu(buf[1]);
-			if (new_rangetr) {
-				rc = next_entry(buf, fp, sizeof(u32));
-				if (rc < 0) {
-					kfree(rt);
-					goto bad;
-				}
-				rt->target_class = le32_to_cpu(buf[0]);
-			} else
-				rt->target_class = p->process_class;
-			if (!policydb_type_isvalid(p, rt->source_type) ||
-			    !policydb_type_isvalid(p, rt->target_type) ||
-			    !policydb_class_isvalid(p, rt->target_class)) {
-				kfree(rt);
-				rc = -EINVAL;
-				goto bad;
-			}
-			r = kzalloc(sizeof(*r), GFP_KERNEL);
-			if (!r) {
-				kfree(rt);
-				rc = -ENOMEM;
-				goto bad;
-			}
-			rc = mls_read_range_helper(r, fp);
-			if (rc) {
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-			if (!mls_range_isvalid(p, r)) {
-				printk(KERN_WARNING "SELinux:  rangetrans:  invalid range\n");
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-			rc = hashtab_insert(p->range_tr, rt, r);
-			if (rc) {
-				kfree(rt);
-				kfree(r);
-				goto bad;
-			}
-		}
-		rangetr_hash_eval(p->range_tr);
-	}
+	rc = range_read(p, fp);
+	if (rc)
+		goto bad;
 
 	p->type_attr_map = kmalloc(p->p_types.nprim * sizeof(struct ebitmap), GFP_KERNEL);
 	if (!p->type_attr_map)
Signature · 8 lines
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 [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#25 lore raw
In reply to Eric Paris
Quoted 4 lines · Eric Paris

Move the range transition rule to a separate function, range_read(), rather than doing it all in policydb_read()

Applied to
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#next

Signature · 7 lines
James Morris
<[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.