procfs: don't allow to use proc_create, create_proc_entry, etc. for directories
Al Viro [Sun, 31 Mar 2013 01:20:14 +0000 (21:20 -0400)]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

fs/proc/generic.c
fs/proc/inode.c

index 21e1a8f..6bce607 100644 (file)
@@ -541,19 +541,18 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
                return ret;
 
        if (S_ISDIR(dp->mode)) {
-               if (dp->proc_iops == NULL) {
-                       dp->proc_fops = &proc_dir_operations;
-                       dp->proc_iops = &proc_dir_inode_operations;
-               }
+               dp->proc_fops = &proc_dir_operations;
+               dp->proc_iops = &proc_dir_inode_operations;
                dir->nlink++;
        } else if (S_ISLNK(dp->mode)) {
-               if (dp->proc_iops == NULL)
-                       dp->proc_iops = &proc_link_inode_operations;
+               dp->proc_iops = &proc_link_inode_operations;
        } else if (S_ISREG(dp->mode)) {
                if (dp->proc_fops == NULL)
                        dp->proc_fops = &proc_file_operations;
-               if (dp->proc_iops == NULL)
-                       dp->proc_iops = &proc_file_inode_operations;
+               dp->proc_iops = &proc_file_inode_operations;
+       } else {
+               WARN_ON(1);
+               return -EINVAL;
        }
 
        spin_lock(&proc_subdir_lock);
@@ -680,21 +679,19 @@ struct proc_dir_entry *create_proc_entry(const char *name, umode_t mode,
                                         struct proc_dir_entry *parent)
 {
        struct proc_dir_entry *ent;
-       nlink_t nlink;
 
-       if (S_ISDIR(mode)) {
-               if ((mode & S_IALLUGO) == 0)
-                       mode |= S_IRUGO | S_IXUGO;
-               nlink = 2;
-       } else {
-               if ((mode & S_IFMT) == 0)
-                       mode |= S_IFREG;
-               if ((mode & S_IALLUGO) == 0)
-                       mode |= S_IRUGO;
-               nlink = 1;
+       if ((mode & S_IFMT) == 0)
+               mode |= S_IFREG;
+
+       if (!S_ISREG(mode)) {
+               WARN_ON(1);     /* use proc_mkdir(), damnit */
+               return NULL;
        }
 
-       ent = __proc_create(&parent, name, mode, nlink);
+       if ((mode & S_IALLUGO) == 0)
+               mode |= S_IRUGO;
+
+       ent = __proc_create(&parent, name, mode, 1);
        if (ent) {
                if (proc_register(parent, ent) < 0) {
                        kfree(ent);
@@ -711,21 +708,17 @@ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
                                        void *data)
 {
        struct proc_dir_entry *pde;
-       nlink_t nlink;
+       if ((mode & S_IFMT) == 0)
+               mode |= S_IFREG;
 
-       if (S_ISDIR(mode)) {
-               if ((mode & S_IALLUGO) == 0)
-                       mode |= S_IRUGO | S_IXUGO;
-               nlink = 2;
-       } else {
-               if ((mode & S_IFMT) == 0)
-                       mode |= S_IFREG;
-               if ((mode & S_IALLUGO) == 0)
-                       mode |= S_IRUGO;
-               nlink = 1;
+       if (!S_ISREG(mode)) {
+               WARN_ON(1);     /* use proc_mkdir() */
+               return NULL;
        }
 
-       pde = __proc_create(&parent, name, mode, nlink);
+       if ((mode & S_IALLUGO) == 0)
+               mode |= S_IRUGO;
+       pde = __proc_create(&parent, name, mode, 1);
        if (!pde)
                goto out;
        pde->proc_fops = proc_fops;
index 908e974..a4aaaee 100644 (file)
@@ -462,8 +462,8 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
                        inode->i_size = de->size;
                if (de->nlink)
                        set_nlink(inode, de->nlink);
-               if (de->proc_iops)
-                       inode->i_op = de->proc_iops;
+               WARN_ON(!de->proc_iops);
+               inode->i_op = de->proc_iops;
                if (de->proc_fops) {
                        if (S_ISREG(inode->i_mode)) {
 #ifdef CONFIG_COMPAT