[PATCH 2/2] RFC: selinux: sysctl: fix selinux labeling broken by last patch

From: Lucian Adrian Grijincu
Date: Sun Jan 30 2011 - 22:27:22 EST


Eric's patch was rejected because it broke selinux labeling:
http://thread.gmane.org/gmane.linux.kernel.lsm/9807/focus=9841

This seems to break labeling. Prior to this patch, I see:

# ls -lZ /proc/1/net/rpc/nfsd.fh
-rw-------. root root system_u:object_r:sysctl_rpc_t:s0 channel

with the patch:

# ls -lZ /proc/1/net/rpc/nfsd.fh
-rw-------. root root system_u:object_r:proc_t:s0 channel

My patch seems to have fixed this problem (it correctly reports
sysctl_rpc_t in this case), but my selinux experience is Î > 0 and I
have no ideea what else it may have broken.

I ran 'find /proc | xargs ls -Z > f' on a kernel with an without
these patches:
* http://swarm.cs.pub.ro/~lucian/store/ls-Z-with-patch
* http://swarm.cs.pub.ro/~lucian/store/ls-Z-without-patch

My setup is a custom busybox live CD with selinux enabled, with
/etc/selinux and /usr/share/selinux/default copied from Ubuntu 10.10's
selinux-policy-default package. I'm sure there are lots of reasons why
this is not correcly configured, etc., but I have no experience
regarding selinux. I can make all the scripts/sources/configs/etc
available to anyone interested.

NOTE: this patch will be merged with:
security/selinux: Simplify proc inode to security label mapping

I'm only prividing this patch separately to point out the differences
to Eric W. Biederman's patch.

Both of these patches apply cleanly agains Linux 2.6.37.

Signed-off-by: Lucian Adrian Grijincu <lucian.grijincu@xxxxxxxxx>
---
fs/proc/proc_sysctl.c | 1 -
security/selinux/hooks.c | 20 ++++++++++++++++----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index b652cb0..b17619d 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -31,7 +31,6 @@ static struct inode *proc_sys_make_inode(struct super_block *sb,
ei->sysctl_entry = table;

inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_flags |= S_PRIVATE; /* tell selinux to ignore this inode */
inode->i_mode = table->mode;
if (!table->child) {
inode->i_mode |= S_IFREG;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 51615f6..5f58019 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1132,8 +1132,23 @@ static int selinux_proc_get_sid(struct dentry *dentry,
path = dentry_path(dentry, buffer, PAGE_SIZE);
if (IS_ERR(path))
rc = PTR_ERR(path);
- else
+ else {
+ /* because dentry is not hashed, dentry_path() will
+ * append "//deleted" to the end of the string. We'll
+ * remove this as no /proc/ file is named so. */
+ int pathlen = strlen(path);
+ int dellen = strlen("//deleted");
+ if ((pathlen > dellen) && strcmp(path + pathlen - dellen, "//deleted") == 0)
+ path[pathlen-dellen] = '\0';
+
+ /* each process gets a /proc/PID/ entry. Strip off the
+ * PID part to get a valid selinux labeling. */
+ while (path[1] >= '0' && path[1] <= '9') {
+ path[1] = '/';
+ path++;
+ }
rc = security_genfs_sid("proc", path, tclass, sid);
+ }
free_page((unsigned long)buffer);
return rc;
}
@@ -1464,9 +1479,6 @@ static int inode_has_perm(const struct cred *cred,

validate_creds(cred);

- if (unlikely(IS_PRIVATE(inode)))
- return 0;
-
sid = cred_sid(cred);
isec = inode->i_security;