Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
[cascardo/linux.git] / security / selinux / selinuxfs.c
index f5f3e6d..397fd49 100644 (file)
@@ -65,6 +65,7 @@ static DEFINE_MUTEX(sel_mutex);
 /* global data for booleans */
 static struct dentry *bool_dir = NULL;
 static int bool_num = 0;
+static char **bool_pending_names;
 static int *bool_pending_values = NULL;
 
 /* global data for classes */
@@ -832,15 +833,16 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
        ssize_t length;
        ssize_t ret;
        int cur_enforcing;
-       struct inode *inode;
+       struct inode *inode = filep->f_path.dentry->d_inode;
+       unsigned index = inode->i_ino & SEL_INO_MASK;
+       const char *name = filep->f_path.dentry->d_name.name;
 
        mutex_lock(&sel_mutex);
 
-       ret = -EFAULT;
-
-       /* check to see if this file has been deleted */
-       if (!filep->f_op)
+       if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
+               ret = -EINVAL;
                goto out;
+       }
 
        if (count > PAGE_SIZE) {
                ret = -EINVAL;
@@ -851,15 +853,13 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
                goto out;
        }
 
-       inode = filep->f_path.dentry->d_inode;
-       cur_enforcing = security_get_bool_value(inode->i_ino&SEL_INO_MASK);
+       cur_enforcing = security_get_bool_value(index);
        if (cur_enforcing < 0) {
                ret = cur_enforcing;
                goto out;
        }
-
        length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
-                         bool_pending_values[inode->i_ino&SEL_INO_MASK]);
+                         bool_pending_values[index]);
        ret = simple_read_from_buffer(buf, count, ppos, page, length);
 out:
        mutex_unlock(&sel_mutex);
@@ -872,9 +872,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
                              size_t count, loff_t *ppos)
 {
        char *page = NULL;
-       ssize_t length = -EFAULT;
+       ssize_t length;
        int new_value;
-       struct inode *inode;
+       struct inode *inode = filep->f_path.dentry->d_inode;
+       unsigned index = inode->i_ino & SEL_INO_MASK;
+       const char *name = filep->f_path.dentry->d_name.name;
 
        mutex_lock(&sel_mutex);
 
@@ -882,16 +884,19 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
        if (length)
                goto out;
 
-       /* check to see if this file has been deleted */
-       if (!filep->f_op)
+       if (index >= bool_num || strcmp(name, bool_pending_names[index])) {
+               length = -EINVAL;
                goto out;
+       }
 
        if (count >= PAGE_SIZE) {
                length = -ENOMEM;
                goto out;
        }
+
        if (*ppos != 0) {
                /* No partial writes. */
+               length = -EINVAL;
                goto out;
        }
        page = (char*)get_zeroed_page(GFP_KERNEL);
@@ -900,6 +905,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
                goto out;
        }
 
+       length = -EFAULT;
        if (copy_from_user(page, buf, count))
                goto out;
 
@@ -910,8 +916,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
        if (new_value)
                new_value = 1;
 
-       inode = filep->f_path.dentry->d_inode;
-       bool_pending_values[inode->i_ino&SEL_INO_MASK] = new_value;
+       bool_pending_values[index] = new_value;
        length = count;
 
 out:
@@ -931,7 +936,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
                                      size_t count, loff_t *ppos)
 {
        char *page = NULL;
-       ssize_t length = -EFAULT;
+       ssize_t length;
        int new_value;
 
        mutex_lock(&sel_mutex);
@@ -940,10 +945,6 @@ static ssize_t sel_commit_bools_write(struct file *filep,
        if (length)
                goto out;
 
-       /* check to see if this file has been deleted */
-       if (!filep->f_op)
-               goto out;
-
        if (count >= PAGE_SIZE) {
                length = -ENOMEM;
                goto out;
@@ -958,6 +959,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
                goto out;
        }
 
+       length = -EFAULT;
        if (copy_from_user(page, buf, count))
                goto out;
 
@@ -982,11 +984,9 @@ static const struct file_operations sel_commit_bools_ops = {
        .write          = sel_commit_bools_write,
 };
 
-/* partial revoke() from fs/proc/generic.c proc_kill_inodes */
 static void sel_remove_entries(struct dentry *de)
 {
-       struct list_head *p, *node;
-       struct super_block *sb = de->d_sb;
+       struct list_head *node;
 
        spin_lock(&dcache_lock);
        node = de->d_subdirs.next;
@@ -1006,18 +1006,6 @@ static void sel_remove_entries(struct dentry *de)
        }
 
        spin_unlock(&dcache_lock);
-
-       file_list_lock();
-       list_for_each(p, &sb->s_files) {
-               struct file * filp = list_entry(p, struct file, f_u.fu_list);
-               struct dentry * dentry = filp->f_path.dentry;
-
-               if (dentry->d_parent != de) {
-                       continue;
-               }
-               filp->f_op = NULL;
-       }
-       file_list_unlock();
 }
 
 #define BOOL_DIR_NAME "booleans"
@@ -1036,7 +1024,9 @@ static int sel_make_bools(void)
        u32 sid;
 
        /* remove any existing files */
+       kfree(bool_pending_names);
        kfree(bool_pending_values);
+       bool_pending_names = NULL;
        bool_pending_values = NULL;
 
        sel_remove_entries(dir);
@@ -1078,16 +1068,17 @@ static int sel_make_bools(void)
                d_add(dentry, inode);
        }
        bool_num = num;
+       bool_pending_names = names;
        bool_pending_values = values;
 out:
        free_page((unsigned long)page);
+       return ret;
+err:
        if (names) {
                for (i = 0; i < num; i++)
                        kfree(names[i]);
                kfree(names);
        }
-       return ret;
-err:
        kfree(values);
        sel_remove_entries(dir);
        ret = -ENOMEM;
@@ -1231,7 +1222,7 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
 static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
 { }
 
-static struct seq_operations sel_avc_cache_stats_seq_ops = {
+static const struct seq_operations sel_avc_cache_stats_seq_ops = {
        .start          = sel_avc_stats_seq_start,
        .next           = sel_avc_stats_seq_next,
        .show           = sel_avc_stats_seq_show,