
From: Stephen Smalley <sds@epoch.ncsc.mil>

This patch adds a member node to selinuxfs to export the security_member_sid
interface to userspace for obtaining security polyinstantiation decisions.

Signed-off-by:  Stephen Smalley <sds@epoch.ncsc.mil>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/security/selinux/selinuxfs.c |   65 +++++++++++++++++++++++++++++++++++
 1 files changed, 65 insertions(+)

diff -puN security/selinux/selinuxfs.c~selinux-add-member-node-to-selinuxfs security/selinux/selinuxfs.c
--- 25/security/selinux/selinuxfs.c~selinux-add-member-node-to-selinuxfs	Thu Dec  2 12:57:56 2004
+++ 25-akpm/security/selinux/selinuxfs.c	Thu Dec  2 12:57:56 2004
@@ -71,6 +71,7 @@ enum sel_inos {
 	SEL_MLS,	/* return if MLS policy is enabled */
 	SEL_DISABLE,	/* disable SELinux until next reboot */
 	SEL_AVC,	/* AVC management directory */
+	SEL_MEMBER,	/* compute polyinstantiation membership decision */
 };
 
 #define TMPBUFLEN	12
@@ -307,12 +308,14 @@ static ssize_t sel_write_access(struct f
 static ssize_t sel_write_create(struct file * file, char *buf, size_t size);
 static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size);
 static ssize_t sel_write_user(struct file * file, char *buf, size_t size);
+static ssize_t sel_write_member(struct file * file, char *buf, size_t size);
 
 static ssize_t (*write_op[])(struct file *, char *, size_t) = {
 	[SEL_ACCESS] = sel_write_access,
 	[SEL_CREATE] = sel_write_create,
 	[SEL_RELABEL] = sel_write_relabel,
 	[SEL_USER] = sel_write_user,
+	[SEL_MEMBER] = sel_write_member,
 };
 
 static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
@@ -582,6 +585,67 @@ out:
 	return length;
 }
 
+static ssize_t sel_write_member(struct file * file, char *buf, size_t size)
+{
+	char *scon, *tcon;
+	u32 ssid, tsid, newsid;
+	u16 tclass;
+	ssize_t length;
+	char *newcon;
+	u32 len;
+
+	length = task_has_security(current, SECURITY__COMPUTE_MEMBER);
+	if (length)
+		return length;
+
+	length = -ENOMEM;
+	scon = kmalloc(size+1, GFP_KERNEL);
+	if (!scon)
+		return length;
+	memset(scon, 0, size+1);
+
+	tcon = kmalloc(size+1, GFP_KERNEL);
+	if (!tcon)
+		goto out;
+	memset(tcon, 0, size+1);
+
+	length = -EINVAL;
+	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
+		goto out2;
+
+	length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+	if (length < 0)
+		goto out2;
+	length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+	if (length < 0)
+		goto out2;
+
+	length = security_member_sid(ssid, tsid, tclass, &newsid);
+	if (length < 0)
+		goto out2;
+
+	length = security_sid_to_context(newsid, &newcon, &len);
+	if (length < 0)
+		goto out2;
+
+	if (len > SIMPLE_TRANSACTION_LIMIT) {
+		printk(KERN_ERR "%s:  context size (%u) exceeds payload "
+		       "max\n", __FUNCTION__, len);
+		length = -ERANGE;
+		goto out3;
+	}
+
+	memcpy(buf, newcon, len);
+	length = len;
+out3:
+	kfree(newcon);
+out2:
+	kfree(tcon);
+out:
+	kfree(scon);
+	return length;
+}
+
 static struct inode *sel_make_inode(struct super_block *sb, int mode)
 {
 	struct inode *ret = new_inode(sb);
@@ -1117,6 +1181,7 @@ static int sel_fill_super(struct super_b
 		[SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
 		[SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
 		[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
+		[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
 		/* last one */ {""}
 	};
 	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
_
