linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / security / selinux / selinuxfs.c
index bab7b38..b5fa02d 100644 (file)
@@ -9,19 +9,18 @@
  *     the Free Software Foundation, version 2.
  */
 
+#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
-#include <linux/mutex.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/security.h>
 #include <linux/major.h>
 #include <linux/seq_file.h>
 #include <linux/percpu.h>
-#include <linux/audit.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
 
 unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
 
-#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
-#define SELINUX_COMPAT_NET_VALUE 0
-#else
-#define SELINUX_COMPAT_NET_VALUE 1
-#endif
-
-int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
-
 static int __init checkreqprot_setup(char *str)
 {
        selinux_checkreqprot = simple_strtoul(str,NULL,0) ? 1 : 0;
@@ -52,15 +43,8 @@ static int __init checkreqprot_setup(char *str)
 }
 __setup("checkreqprot=", checkreqprot_setup);
 
-static int __init selinux_compat_net_setup(char *str)
-{
-       selinux_compat_net = simple_strtoul(str,NULL,0) ? 1 : 0;
-       return 1;
-}
-__setup("selinux_compat_net=", selinux_compat_net_setup);
-
 
-static DEFINE_MUTEX(sel_mutex);
+static DECLARE_MUTEX(sel_sem);
 
 /* global data for booleans */
 static struct dentry *bool_dir = NULL;
@@ -99,7 +83,6 @@ enum sel_inos {
        SEL_AVC,        /* AVC management directory */
        SEL_MEMBER,     /* compute polyinstantiation membership decision */
        SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
-       SEL_COMPAT_NET, /* whether to use old compat network packet controls */
 };
 
 #define TMPBUFLEN      12
@@ -143,10 +126,6 @@ static ssize_t sel_write_enforce(struct file * file, const char __user * buf,
                length = task_has_security(current, SECURITY__SETENFORCE);
                if (length)
                        goto out;
-               audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
-                       "enforcing=%d old_enforcing=%d auid=%u", new_value, 
-                       selinux_enforcing,
-                       audit_get_loginuid(current->audit_context));
                selinux_enforcing = new_value;
                if (selinux_enforcing)
                        avc_ss_reset(0);
@@ -197,9 +176,6 @@ static ssize_t sel_write_disable(struct file * file, const char __user * buf,
                length = selinux_disable();
                if (length < 0)
                        goto out;
-               audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
-                       "selinux=0 auid=%u",
-                       audit_get_loginuid(current->audit_context));
        }
 
        length = count;
@@ -254,7 +230,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
        ssize_t length;
        void *data = NULL;
 
-       mutex_lock(&sel_mutex);
+       down(&sel_sem);
 
        length = task_has_security(current, SECURITY__LOAD_POLICY);
        if (length)
@@ -285,11 +261,8 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
                length = ret;
        else
                length = count;
-       audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
-               "policy loaded auid=%u",
-               audit_get_loginuid(current->audit_context));
 out:
-       mutex_unlock(&sel_mutex);
+       up(&sel_sem);
        vfree(data);
        return length;
 }
@@ -379,55 +352,6 @@ static struct file_operations sel_checkreqprot_ops = {
        .write          = sel_write_checkreqprot,
 };
 
-static ssize_t sel_read_compat_net(struct file *filp, char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       char tmpbuf[TMPBUFLEN];
-       ssize_t length;
-
-       length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_compat_net);
-       return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
-}
-
-static ssize_t sel_write_compat_net(struct file * file, const char __user * buf,
-                                   size_t count, loff_t *ppos)
-{
-       char *page;
-       ssize_t length;
-       int new_value;
-
-       length = task_has_security(current, SECURITY__LOAD_POLICY);
-       if (length)
-               return length;
-
-       if (count >= PAGE_SIZE)
-               return -ENOMEM;
-       if (*ppos != 0) {
-               /* No partial writes. */
-               return -EINVAL;
-       }
-       page = (char*)get_zeroed_page(GFP_KERNEL);
-       if (!page)
-               return -ENOMEM;
-       length = -EFAULT;
-       if (copy_from_user(page, buf, count))
-               goto out;
-
-       length = -EINVAL;
-       if (sscanf(page, "%d", &new_value) != 1)
-               goto out;
-
-       selinux_compat_net = new_value ? 1 : 0;
-       length = count;
-out:
-       free_page((unsigned long) page);
-       return length;
-}
-static struct file_operations sel_compat_net_ops = {
-       .read           = sel_read_compat_net,
-       .write          = sel_write_compat_net,
-};
-
 /*
  * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
  */
@@ -771,6 +695,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
        if (ret) {
                ret->i_mode = mode;
                ret->i_uid = ret->i_gid = 0;
+               ret->i_blksize = PAGE_CACHE_SIZE;
                ret->i_blocks = 0;
                ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
        }
@@ -784,11 +709,12 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
 {
        char *page = NULL;
        ssize_t length;
+       ssize_t end;
        ssize_t ret;
        int cur_enforcing;
        struct inode *inode;
 
-       mutex_lock(&sel_mutex);
+       down(&sel_sem);
 
        ret = -EFAULT;
 
@@ -814,9 +740,26 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
 
        length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
                          bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
-       ret = simple_read_from_buffer(buf, count, ppos, page, length);
+       if (length < 0) {
+               ret = length;
+               goto out;
+       }
+
+       if (*ppos >= length) {
+               ret = 0;
+               goto out;
+       }
+       if (count + *ppos > length)
+               count = length - *ppos;
+       end = count + *ppos;
+       if (copy_to_user(buf, (char *) page + *ppos, count)) {
+               ret = -EFAULT;
+               goto out;
+       }
+       *ppos = end;
+       ret = count;
 out:
-       mutex_unlock(&sel_mutex);
+       up(&sel_sem);
        if (page)
                free_page((unsigned long)page);
        return ret;
@@ -830,7 +773,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
        int new_value;
        struct inode *inode;
 
-       mutex_lock(&sel_mutex);
+       down(&sel_sem);
 
        length = task_has_security(current, SECURITY__SETBOOL);
        if (length)
@@ -869,7 +812,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
        length = count;
 
 out:
-       mutex_unlock(&sel_mutex);
+       up(&sel_sem);
        if (page)
                free_page((unsigned long) page);
        return length;
@@ -888,7 +831,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
        ssize_t length = -EFAULT;
        int new_value;
 
-       mutex_lock(&sel_mutex);
+       down(&sel_sem);
 
        length = task_has_security(current, SECURITY__SETBOOL);
        if (length)
@@ -926,7 +869,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
        length = count;
 
 out:
-       mutex_unlock(&sel_mutex);
+       up(&sel_sem);
        if (page)
                free_page((unsigned long) page);
        return length;
@@ -1044,7 +987,7 @@ out:
        return ret;
 err:
        kfree(values);
-       sel_remove_bools(dir);
+       d_genocide(dir);
        ret = -ENOMEM;
        goto out;
 }
@@ -1225,38 +1168,37 @@ static int sel_make_avc_files(struct dentry *dir)
                dentry = d_alloc_name(dir, files[i].name);
                if (!dentry) {
                        ret = -ENOMEM;
-                       goto out;
+                       goto err;
                }
 
                inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
                if (!inode) {
                        ret = -ENOMEM;
-                       goto out;
+                       goto err;
                }
                inode->i_fop = files[i].ops;
                d_add(dentry, inode);
        }
 out:
        return ret;
+err:
+       d_genocide(dir);
+       goto out;
 }
 
-static int sel_make_dir(struct inode *dir, struct dentry *dentry)
+static int sel_make_dir(struct super_block *sb, struct dentry *dentry)
 {
        int ret = 0;
        struct inode *inode;
 
-       inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO);
+       inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
        if (!inode) {
                ret = -ENOMEM;
                goto out;
        }
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
-       /* directory inodes start off with i_nlink == 2 (for "." entry) */
-       inode->i_nlink++;
        d_add(dentry, inode);
-       /* bump link count on parent directory, too */
-       dir->i_nlink++;
 out:
        return ret;
 }
@@ -1265,7 +1207,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
 {
        int ret;
        struct dentry *dentry;
-       struct inode *inode, *root_inode;
+       struct inode *inode;
        struct inode_security_struct *isec;
 
        static struct tree_descr selinux_files[] = {
@@ -1282,38 +1224,34 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
                [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
                [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
                [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
-               [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR},
                /* last one */ {""}
        };
        ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
        if (ret)
-               goto err;
-
-       root_inode = sb->s_root->d_inode;
+               return ret;
 
        dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME);
-       if (!dentry) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       ret = sel_make_dir(root_inode, dentry);
-       if (ret)
-               goto err;
+       if (!dentry)
+               return -ENOMEM;
 
+       inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO);
+       if (!inode)
+               goto out;
+       inode->i_op = &simple_dir_inode_operations;
+       inode->i_fop = &simple_dir_operations;
+       d_add(dentry, inode);
        bool_dir = dentry;
+       ret = sel_make_bools();
+       if (ret)
+               goto out;
 
        dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
-       if (!dentry) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!dentry)
+               return -ENOMEM;
 
        inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
-       if (!inode) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!inode)
+               goto out;
        isec = (struct inode_security_struct*)inode->i_security;
        isec->sid = SECINITSID_DEVNULL;
        isec->sclass = SECCLASS_CHR_FILE;
@@ -1324,30 +1262,28 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
        selinux_null = dentry;
 
        dentry = d_alloc_name(sb->s_root, "avc");
-       if (!dentry) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!dentry)
+               return -ENOMEM;
 
-       ret = sel_make_dir(root_inode, dentry);
+       ret = sel_make_dir(sb, dentry);
        if (ret)
-               goto err;
+               goto out;
 
        ret = sel_make_avc_files(dentry);
        if (ret)
-               goto err;
+               goto out;
+
+       return 0;
 out:
-       return ret;
-err:
+       dput(dentry);
        printk(KERN_ERR "%s:  failed while creating inodes\n", __FUNCTION__);
-       goto out;
+       return -ENOMEM;
 }
 
-static int sel_get_sb(struct file_system_type *fs_type,
-                     int flags, const char *dev_name, void *data,
-                     struct vfsmount *mnt)
+static struct super_block *sel_get_sb(struct file_system_type *fs_type,
+                                     int flags, const char *dev_name, void *data)
 {
-       return get_sb_single(fs_type, flags, data, sel_fill_super, mnt);
+       return get_sb_single(fs_type, flags, data, sel_fill_super);
 }
 
 static struct file_system_type sel_fs_type = {