浏览代码

smack: fixes for unlabeled host support

The following patch (against 2.6.29rc5) fixes a few issues in the
smack/netlabel "unlabeled host support" functionnality that was added in
2.6.29rc.  It should go in before -final.

1) smack_host_label disregard a "0.0.0.0/0 @" rule (or other label),
preventing 'tagged' tasks to access Internet (many systems drop packets with
IP options)

2) netmasks were not handled correctly, they were stored in a way _not
equivalent_ to conversion to be32 (it was equivalent for /0, /8, /16, /24,
/32 masks but not other masks)

3) smack_netlbladdr prefixes (IP/mask) were not consistent (mask&IP was not
done), so there could have been different list entries for the same IP
prefix; if those entries had different labels, well ...

4) they were not sorted

1) 2) 3) are bugs, 4) is a more cosmetic issue.
The patch :

-creates a new helper smk_netlbladdr_insert to insert a smk_netlbladdr,
-sorted by netmask length

-use the new sorted nature of  smack_netlbladdrs list to simplify
 smack_host_label : the first match _will_ be the more specific

-corrects endianness issues in smk_write_netlbladdr &  netlbladdr_seq_show

Signed-off-by: <etienne.basset@numericable.fr>
Acked-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Paul Moore <paul.moore@hp.com>
Signed-off-by: James Morris <jmorris@namei.org>
etienne 16 年之前
父节点
当前提交
113a0e4590
共有 1 个文件被更改,包括 49 次插入15 次删除
  1. 49 15
      security/smack/smackfs.c

+ 49 - 15
security/smack/smackfs.c

@@ -651,10 +651,6 @@ static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
 
 
 	return skp;
 	return skp;
 }
 }
-/*
-#define BEMASK	0x80000000
-*/
-#define BEMASK	0x00000001
 #define BEBITS	(sizeof(__be32) * 8)
 #define BEBITS	(sizeof(__be32) * 8)
 
 
 /*
 /*
@@ -664,12 +660,10 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
 {
 {
 	struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
 	struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
 	unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
 	unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
-	__be32 bebits;
-	int maskn = 0;
+	int maskn;
+	u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
 
 
-	for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1)
-		if ((skp->smk_mask.s_addr & bebits) == 0)
-			break;
+	for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++);
 
 
 	seq_printf(s, "%u.%u.%u.%u/%d %s\n",
 	seq_printf(s, "%u.%u.%u.%u/%d %s\n",
 		hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
 		hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
@@ -702,6 +696,42 @@ static int smk_open_netlbladdr(struct inode *inode, struct file *file)
 	return seq_open(file, &netlbladdr_seq_ops);
 	return seq_open(file, &netlbladdr_seq_ops);
 }
 }
 
 
+/**
+ * smk_netlbladdr_insert
+ * @new : netlabel to insert
+ *
+ * This helper insert netlabel in the smack_netlbladdrs list
+ * sorted by netmask length (longest to smallest)
+ */
+static void smk_netlbladdr_insert(struct smk_netlbladdr *new)
+{
+	struct smk_netlbladdr *m;
+
+	if (smack_netlbladdrs == NULL) {
+		smack_netlbladdrs = new;
+		return;
+	}
+
+	/* the comparison '>' is a bit hacky, but works */
+	if (new->smk_mask.s_addr > smack_netlbladdrs->smk_mask.s_addr) {
+		new->smk_next = smack_netlbladdrs;
+		smack_netlbladdrs = new;
+		return;
+	}
+	for (m = smack_netlbladdrs; m != NULL; m = m->smk_next) {
+		if (m->smk_next == NULL) {
+			m->smk_next = new;
+			return;
+		}
+		if (new->smk_mask.s_addr > m->smk_next->smk_mask.s_addr) {
+			new->smk_next = m->smk_next;
+			m->smk_next = new;
+			return;
+		}
+	}
+}
+
+
 /**
 /**
  * smk_write_netlbladdr - write() for /smack/netlabel
  * smk_write_netlbladdr - write() for /smack/netlabel
  * @file: file pointer, not actually used
  * @file: file pointer, not actually used
@@ -725,8 +755,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
 	struct netlbl_audit audit_info;
 	struct netlbl_audit audit_info;
 	struct in_addr mask;
 	struct in_addr mask;
 	unsigned int m;
 	unsigned int m;
-	__be32 bebits = BEMASK;
+	u32 mask_bits = (1<<31);
 	__be32 nsa;
 	__be32 nsa;
+	u32 temp_mask;
 
 
 	/*
 	/*
 	 * Must have privilege.
 	 * Must have privilege.
@@ -762,10 +793,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
 	if (sp == NULL)
 	if (sp == NULL)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	for (mask.s_addr = 0; m > 0; m--) {
-		mask.s_addr |= bebits;
-		bebits <<= 1;
+	for (temp_mask = 0; m > 0; m--) {
+		temp_mask |= mask_bits;
+		mask_bits >>= 1;
 	}
 	}
+	mask.s_addr = cpu_to_be32(temp_mask);
+
+	newname.sin_addr.s_addr &= mask.s_addr;
 	/*
 	/*
 	 * Only allow one writer at a time. Writes should be
 	 * Only allow one writer at a time. Writes should be
 	 * quite rare and small in any case.
 	 * quite rare and small in any case.
@@ -773,6 +807,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
 	mutex_lock(&smk_netlbladdr_lock);
 	mutex_lock(&smk_netlbladdr_lock);
 
 
 	nsa = newname.sin_addr.s_addr;
 	nsa = newname.sin_addr.s_addr;
+	/* try to find if the prefix is already in the list */
 	for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
 	for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
 		if (skp->smk_host.sin_addr.s_addr == nsa &&
 		if (skp->smk_host.sin_addr.s_addr == nsa &&
 		    skp->smk_mask.s_addr == mask.s_addr)
 		    skp->smk_mask.s_addr == mask.s_addr)
@@ -788,9 +823,8 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
 			rc = 0;
 			rc = 0;
 			skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
 			skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
 			skp->smk_mask.s_addr = mask.s_addr;
 			skp->smk_mask.s_addr = mask.s_addr;
-			skp->smk_next = smack_netlbladdrs;
 			skp->smk_label = sp;
 			skp->smk_label = sp;
-			smack_netlbladdrs = skp;
+			smk_netlbladdr_insert(skp);
 		}
 		}
 	} else {
 	} else {
 		rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
 		rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,