summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-05-09 23:55:49 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-05-09 23:55:49 -0700
commitdef3f08e2365e7c602603e73755eb111781249b2 (patch)
tree00fc3d66015db999603e4554cac3767fae0e4046 /security
parente461abeb62ef330c4c1b1e9dae2a0a7a10213e79 (diff)
[PATCH] selinux: reopen descriptors closed on exec to /dev/null
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.
Diffstat (limited to 'security')
-rw-r--r--security/selinux/hooks.c85
-rw-r--r--security/selinux/include/flask.h3
-rw-r--r--security/selinux/include/initial_sid_to_string.h1
3 files changed, 85 insertions, 4 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8880f37ddf94..e895d0b32c52 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -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(struct linux_binprm *bprm)
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_files(struct files_struct * files)
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 --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index 43ef2d661027..6425c7869e8a 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -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 --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h
index ec010c0e2c22..d4fac82793ae 100644
--- a/security/selinux/include/initial_sid_to_string.h
+++ b/security/selinux/include/initial_sid_to_string.h
@@ -28,5 +28,6 @@ static char *initial_sid_to_string[] =
"kmod",
"policy",
"scmp_packet",
+ "devnull",
};