documentation: convert the Documentation directory to UTF-8
[sfrench/cifs-2.6.git] / security / selinux / selinuxfs.c
index bab7b386cb8dee7cd21a1fe21f9741960d34f59c..aca099aa2ed3d743e65d38a4c77da690e4609e2f 100644 (file)
@@ -96,12 +96,18 @@ enum sel_inos {
        SEL_COMMIT_BOOLS, /* commit new boolean values */
        SEL_MLS,        /* return if MLS policy is enabled */
        SEL_DISABLE,    /* disable SELinux until next reboot */
-       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 */
+       SEL_INO_NEXT,   /* The next inode number to use */
 };
 
+static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
+
+#define SEL_INITCON_INO_OFFSET         0x01000000
+#define SEL_BOOL_INO_OFFSET    0x02000000
+#define SEL_INO_MASK           0x00ffffff
+
 #define TMPBUFLEN      12
 static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
                                size_t count, loff_t *ppos)
@@ -161,7 +167,7 @@ out:
 #define sel_write_enforce NULL
 #endif
 
-static struct file_operations sel_enforce_ops = {
+static const struct file_operations sel_enforce_ops = {
        .read           = sel_read_enforce,
        .write          = sel_write_enforce,
 };
@@ -211,7 +217,7 @@ out:
 #define sel_write_disable NULL
 #endif
 
-static struct file_operations sel_disable_ops = {
+static const struct file_operations sel_disable_ops = {
        .write          = sel_write_disable,
 };
 
@@ -225,7 +231,7 @@ static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
        return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
-static struct file_operations sel_policyvers_ops = {
+static const struct file_operations sel_policyvers_ops = {
        .read           = sel_read_policyvers,
 };
 
@@ -242,7 +248,7 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
        return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
-static struct file_operations sel_mls_ops = {
+static const struct file_operations sel_mls_ops = {
        .read           = sel_read_mls,
 };
 
@@ -294,7 +300,7 @@ out:
        return length;
 }
 
-static struct file_operations sel_load_ops = {
+static const struct file_operations sel_load_ops = {
        .write          = sel_write_load,
 };
 
@@ -374,7 +380,7 @@ out:
        free_page((unsigned long) page);
        return length;
 }
-static struct file_operations sel_checkreqprot_ops = {
+static const struct file_operations sel_checkreqprot_ops = {
        .read           = sel_read_checkreqprot,
        .write          = sel_write_checkreqprot,
 };
@@ -423,7 +429,7 @@ out:
        free_page((unsigned long) page);
        return length;
 }
-static struct file_operations sel_compat_net_ops = {
+static const struct file_operations sel_compat_net_ops = {
        .read           = sel_read_compat_net,
        .write          = sel_write_compat_net,
 };
@@ -448,7 +454,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
 
 static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
 {
-       ino_t ino =  file->f_dentry->d_inode->i_ino;
+       ino_t ino =  file->f_path.dentry->d_inode->i_ino;
        char *data;
        ssize_t rv;
 
@@ -467,7 +473,7 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b
        return rv;
 }
 
-static struct file_operations transaction_ops = {
+static const struct file_operations transaction_ops = {
        .write          = selinux_transaction_write,
        .read           = simple_transaction_read,
        .release        = simple_transaction_release,
@@ -777,8 +783,6 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
        return ret;
 }
 
-#define BOOL_INO_OFFSET 30
-
 static ssize_t sel_read_bool(struct file *filep, char __user *buf,
                             size_t count, loff_t *ppos)
 {
@@ -805,15 +809,15 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
                goto out;
        }
 
-       inode = filep->f_dentry->d_inode;
-       cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET);
+       inode = filep->f_path.dentry->d_inode;
+       cur_enforcing = security_get_bool_value(inode->i_ino&SEL_INO_MASK);
        if (cur_enforcing < 0) {
                ret = cur_enforcing;
                goto out;
        }
 
        length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
-                         bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]);
+                         bool_pending_values[inode->i_ino&SEL_INO_MASK]);
        ret = simple_read_from_buffer(buf, count, ppos, page, length);
 out:
        mutex_unlock(&sel_mutex);
@@ -864,8 +868,8 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
        if (new_value)
                new_value = 1;
 
-       inode = filep->f_dentry->d_inode;
-       bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value;
+       inode = filep->f_path.dentry->d_inode;
+       bool_pending_values[inode->i_ino&SEL_INO_MASK] = new_value;
        length = count;
 
 out:
@@ -875,7 +879,7 @@ out:
        return length;
 }
 
-static struct file_operations sel_bool_ops = {
+static const struct file_operations sel_bool_ops = {
        .read           = sel_read_bool,
        .write          = sel_write_bool,
 };
@@ -932,7 +936,7 @@ out:
        return length;
 }
 
-static struct file_operations sel_commit_bools_ops = {
+static const struct file_operations sel_commit_bools_ops = {
        .write          = sel_commit_bools_write,
 };
 
@@ -965,7 +969,7 @@ static void sel_remove_bools(struct dentry *de)
        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_dentry;
+               struct dentry * dentry = filp->f_path.dentry;
 
                if (dentry->d_parent != de) {
                        continue;
@@ -1029,7 +1033,7 @@ static int sel_make_bools(void)
                isec->sid = sid;
                isec->initialized = 1;
                inode->i_fop = &sel_bool_ops;
-               inode->i_ino = i + BOOL_INO_OFFSET;
+               inode->i_ino = i|SEL_BOOL_INO_OFFSET;
                d_add(dentry, inode);
        }
        bool_num = num;
@@ -1131,12 +1135,12 @@ out:
        return ret;
 }
 
-static struct file_operations sel_avc_cache_threshold_ops = {
+static const struct file_operations sel_avc_cache_threshold_ops = {
        .read           = sel_read_avc_cache_threshold,
        .write          = sel_write_avc_cache_threshold,
 };
 
-static struct file_operations sel_avc_hash_stats_ops = {
+static const struct file_operations sel_avc_hash_stats_ops = {
        .read           = sel_read_avc_hash_stats,
 };
 
@@ -1198,7 +1202,7 @@ static int sel_open_avc_cache_stats(struct inode *inode, struct file *file)
        return seq_open(file, &sel_avc_cache_stats_seq_ops);
 }
 
-static struct file_operations sel_avc_cache_stats_ops = {
+static const struct file_operations sel_avc_cache_stats_ops = {
        .open           = sel_open_avc_cache_stats,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -1234,6 +1238,56 @@ static int sel_make_avc_files(struct dentry *dir)
                        goto out;
                }
                inode->i_fop = files[i].ops;
+               inode->i_ino = ++sel_last_ino;
+               d_add(dentry, inode);
+       }
+out:
+       return ret;
+}
+
+static ssize_t sel_read_initcon(struct file * file, char __user *buf,
+                               size_t count, loff_t *ppos)
+{
+       struct inode *inode;
+       char *con;
+       u32 sid, len;
+       ssize_t ret;
+
+       inode = file->f_path.dentry->d_inode;
+       sid = inode->i_ino&SEL_INO_MASK;
+       ret = security_sid_to_context(sid, &con, &len);
+       if (ret < 0)
+               return ret;
+
+       ret = simple_read_from_buffer(buf, count, ppos, con, len);
+       kfree(con);
+       return ret;
+}
+
+static const struct file_operations sel_initcon_ops = {
+       .read           = sel_read_initcon,
+};
+
+static int sel_make_initcon_files(struct dentry *dir)
+{
+       int i, ret = 0;
+
+       for (i = 1; i <= SECINITSID_NUM; i++) {
+               struct inode *inode;
+               struct dentry *dentry;
+               dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
+               if (!dentry) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
+               if (!inode) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               inode->i_fop = &sel_initcon_ops;
+               inode->i_ino = i|SEL_INITCON_INO_OFFSET;
                d_add(dentry, inode);
        }
 out:
@@ -1252,11 +1306,12 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry)
        }
        inode->i_op = &simple_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
+       inode->i_ino = ++sel_last_ino;
        /* directory inodes start off with i_nlink == 2 (for "." entry) */
-       inode->i_nlink++;
+       inc_nlink(inode);
        d_add(dentry, inode);
        /* bump link count on parent directory, too */
-       dir->i_nlink++;
+       inc_nlink(dir);
 out:
        return ret;
 }
@@ -1314,6 +1369,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
                ret = -ENOMEM;
                goto err;
        }
+       inode->i_ino = ++sel_last_ino;
        isec = (struct inode_security_struct*)inode->i_security;
        isec->sid = SECINITSID_DEVNULL;
        isec->sclass = SECCLASS_CHR_FILE;
@@ -1336,6 +1392,21 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
        ret = sel_make_avc_files(dentry);
        if (ret)
                goto err;
+
+       dentry = d_alloc_name(sb->s_root, "initial_contexts");
+       if (!dentry) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       ret = sel_make_dir(root_inode, dentry);
+       if (ret)
+               goto err;
+
+       ret = sel_make_initcon_files(dentry);
+       if (ret)
+               goto err;
+
 out:
        return ret;
 err: