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

This patch changes the SELinux module to try to reset any descriptors it
closes on exec (due to a lack of permission by the new domain to the inherited
open file) to refer to the null device.  This counters the problem of SELinux
inducing program misbehavior, particularly due to having descriptors 0-2
closed when the new domain is not allowed access to the caller's tty.  This is
primarily to address the case where the caller is trusted with respect to the
new domain, as the untrusted caller case is already handled via AT_SECURE and
glibc secure mode.  The code is partly based on the OpenWall LSM, which in
turn drew from the OpenWall kernel patch.  Note that the code does not
guarantee that the descriptor is always re-opened to /dev/null; it merely
makes a reasonable effort to do so, but can fail under various conditions. 


---

 25-akpm/security/selinux/hooks.c                         |   85 ++++++++++++++-
 25-akpm/security/selinux/include/flask.h                 |    3 
 25-akpm/security/selinux/include/initial_sid_to_string.h |    1 
 3 files changed, 85 insertions(+), 4 deletions(-)

diff -puN security/selinux/hooks.c~re-open-descriptors-closed-on-exec-by-selinux-to security/selinux/hooks.c
--- 25/security/selinux/hooks.c~re-open-descriptors-closed-on-exec-by-selinux-to	Mon May  3 14:36:07 2004
+++ 25-akpm/security/selinux/hooks.c	Mon May  3 14:36:07 2004
@@ -62,6 +62,7 @@
 #include <linux/nfs_mount.h>
 #include <net/ipv6.h>
 #include <linux/hugetlb.h>
+#include <linux/major.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -1712,18 +1713,77 @@ static void selinux_bprm_free_security(s
 	kfree(bsec);
 }
 
+/* Create an open file that refers to the null device.
+   Derived from the OpenWall LSM. */
+struct file *open_devnull(void)
+{
+	struct inode *inode;
+	struct dentry *dentry;
+	struct file *file = NULL;
+	struct inode_security_struct *isec;
+	dev_t dev;
+
+	inode = new_inode(current->fs->rootmnt->mnt_sb);
+	if (!inode)
+		goto out;
+
+	dentry = dget(d_alloc_root(inode));
+	if (!dentry)
+		goto out_iput;
+
+	file = get_empty_filp();
+	if (!file)
+		goto out_dput;
+
+	dev = MKDEV(MEM_MAJOR, 3); /* null device */
+
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_blksize = PAGE_SIZE;
+	inode->i_blocks = 0;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_state = I_DIRTY; /* so that mark_inode_dirty won't touch us */
+
+	isec = inode->i_security;
+	isec->sid = SECINITSID_DEVNULL;
+	isec->sclass = SECCLASS_CHR_FILE;
+	isec->initialized = 1;
+
+	file->f_flags = O_RDWR;
+	file->f_mode = FMODE_READ | FMODE_WRITE;
+	file->f_dentry = dentry;
+	file->f_vfsmnt = mntget(current->fs->rootmnt);
+	file->f_pos = 0;
+
+	init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, dev);
+	if (inode->i_fop->open(inode, file))
+		goto out_fput;
+
+out:
+	return file;
+out_fput:
+	mntput(file->f_vfsmnt);
+	put_filp(file);
+out_dput:
+	dput(dentry);
+out_iput:
+	iput(inode);
+	file = NULL;
+	goto out;
+}
+
 /* Derived from fs/exec.c:flush_old_files. */
 static inline void flush_unauthorized_files(struct files_struct * files)
 {
 	struct avc_audit_data ad;
-	struct file *file;
+	struct file *file, *devnull = NULL;
 	long j = -1;
 
 	AVC_AUDIT_DATA_INIT(&ad,FS);
 
 	spin_lock(&files->file_lock);
 	for (;;) {
-		unsigned long set, i;
+		unsigned long set, i, fd;
 
 		j++;
 		i = j * __NFDBITS;
@@ -1740,8 +1800,27 @@ static inline void flush_unauthorized_fi
 					continue;
 				if (file_has_perm(current,
 						  file,
-						  file_to_av(file)))
+						  file_to_av(file))) {
 					sys_close(i);
+					fd = get_unused_fd();
+					if (fd != i) {
+						if (fd >= 0)
+							put_unused_fd(fd);
+						fput(file);
+						continue;
+					}
+					if (devnull) {
+						atomic_inc(&devnull->f_count);
+					} else {
+						devnull = open_devnull();
+						if (!devnull) {
+							put_unused_fd(fd);
+							fput(file);
+							continue;
+						}
+					}
+					fd_install(fd, devnull);
+				}
 				fput(file);
 			}
 		}
diff -puN security/selinux/include/flask.h~re-open-descriptors-closed-on-exec-by-selinux-to security/selinux/include/flask.h
--- 25/security/selinux/include/flask.h~re-open-descriptors-closed-on-exec-by-selinux-to	Mon May  3 14:36:07 2004
+++ 25-akpm/security/selinux/include/flask.h	Mon May  3 14:36:07 2004
@@ -65,7 +65,8 @@
 #define SECINITSID_KMOD                                 24
 #define SECINITSID_POLICY                               25
 #define SECINITSID_SCMP_PACKET                          26
+#define SECINITSID_DEVNULL                              27
 
-#define SECINITSID_NUM                                  26
+#define SECINITSID_NUM                                  27
 
 #endif
diff -puN security/selinux/include/initial_sid_to_string.h~re-open-descriptors-closed-on-exec-by-selinux-to security/selinux/include/initial_sid_to_string.h
--- 25/security/selinux/include/initial_sid_to_string.h~re-open-descriptors-closed-on-exec-by-selinux-to	Mon May  3 14:36:07 2004
+++ 25-akpm/security/selinux/include/initial_sid_to_string.h	Mon May  3 14:36:07 2004
@@ -28,5 +28,6 @@ static char *initial_sid_to_string[] =
     "kmod",
     "policy",
     "scmp_packet",
+    "devnull",
 };
 

_