vfs: Add permission2 for filesystems with per mount permissions
authorDaniel Rosenberg <drosen@google.com>
Wed, 26 Oct 2016 23:27:45 +0000 (16:27 -0700)
committerStricted <info@stricted.net>
Thu, 11 Oct 2018 16:03:53 +0000 (18:03 +0200)
This allows filesystems to use their mount private data to
influence the permssions they return in permission2. It has
been separated into a new call to avoid disrupting current
permission users.

Change-Id: I9d416e3b8b6eca84ef3e336bd2af89ddd51df6ca
Signed-off-by: Daniel Rosenberg <drosen@google.com>
fs/exec.c
fs/namei.c
fs/notify/fanotify/fanotify_user.c
fs/notify/inotify/inotify_user.c
fs/open.c
fs/utimes.c
include/linux/fs.h
include/linux/namei.h
ipc/mqueue.c
security/inode.c

index c4bb850a17a84db5da3ead055eabcfcbdf467f82..a0deb405adaeb14fa47e452b925ca829f896074f 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1109,7 +1109,7 @@ EXPORT_SYMBOL(flush_old_exec);
 
 void would_dump(struct linux_binprm *bprm, struct file *file)
 {
-       if (inode_permission(file_inode(file), MAY_READ) < 0)
+       if (inode_permission2(file->f_path.mnt, file_inode(file), MAY_READ) < 0)
                bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
 }
 EXPORT_SYMBOL(would_dump);
index 31710ee3ba4ff19498e924c25a568484b789643e..02f2bce3e8814aef5580ee158d428848475edcca 100644 (file)
@@ -356,9 +356,11 @@ int generic_permission(struct inode *inode, int mask)
  * flag in inode->i_opflags, that says "this has not special
  * permission function, use the fast case".
  */
-static inline int do_inode_permission(struct inode *inode, int mask)
+static inline int do_inode_permission(struct vfsmount *mnt, struct inode *inode, int mask)
 {
        if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) {
+               if (likely(mnt && inode->i_op->permission2))
+                       return inode->i_op->permission2(mnt, inode, mask);
                if (likely(inode->i_op->permission))
                        return inode->i_op->permission(inode, mask);
 
@@ -382,7 +384,7 @@ static inline int do_inode_permission(struct inode *inode, int mask)
  * This does not check for a read-only file system.  You probably want
  * inode_permission().
  */
-int __inode_permission(struct inode *inode, int mask)
+int __inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
 {
        int retval;
 
@@ -394,7 +396,7 @@ int __inode_permission(struct inode *inode, int mask)
                        return -EACCES;
        }
 
-       retval = do_inode_permission(inode, mask);
+       retval = do_inode_permission(mnt, inode, mask);
        if (retval)
                return retval;
 
@@ -404,6 +406,13 @@ int __inode_permission(struct inode *inode, int mask)
 
        return security_inode_permission(inode, mask);
 }
+EXPORT_SYMBOL(__inode_permission2);
+
+int __inode_permission(struct inode *inode, int mask)
+{
+       return __inode_permission2(NULL, inode, mask);
+}
+EXPORT_SYMBOL(__inode_permission);
 
 /**
  * sb_permission - Check superblock-level permissions
@@ -437,15 +446,22 @@ static int sb_permission(struct super_block *sb, struct inode *inode, int mask)
  *
  * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask.
  */
-int inode_permission(struct inode *inode, int mask)
+int inode_permission2(struct vfsmount *mnt, struct inode *inode, int mask)
 {
        int retval;
 
        retval = sb_permission(inode->i_sb, inode, mask);
        if (retval)
                return retval;
-       return __inode_permission(inode, mask);
+       return __inode_permission2(mnt, inode, mask);
 }
+EXPORT_SYMBOL(inode_permission2);
+
+int inode_permission(struct inode *inode, int mask)
+{
+       return inode_permission2(NULL, inode, mask);
+}
+EXPORT_SYMBOL(inode_permission);
 
 /**
  * path_get - get a reference to a path
@@ -1485,13 +1501,13 @@ static int lookup_slow(struct nameidata *nd, struct path *path)
 static inline int may_lookup(struct nameidata *nd)
 {
        if (nd->flags & LOOKUP_RCU) {
-               int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
+               int err = inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
                if (err != -ECHILD)
                        return err;
                if (unlazy_walk(nd, NULL))
                        return -ECHILD;
        }
-       return inode_permission(nd->inode, MAY_EXEC);
+       return inode_permission2(nd->path.mnt, nd->inode, MAY_EXEC);
 }
 
 static inline int handle_dots(struct nameidata *nd, int type)
@@ -1865,10 +1881,11 @@ static int path_init(int dfd, const char *name, unsigned int flags,
        nd->depth = 0;
        if (flags & LOOKUP_ROOT) {
                struct inode *inode = nd->root.dentry->d_inode;
+               struct vfsmount *mnt = nd->root.mnt;
                if (*name) {
                        if (!can_lookup(inode))
                                return -ENOTDIR;
-                       retval = inode_permission(inode, MAY_EXEC);
+                       retval = inode_permission2(mnt, inode, MAY_EXEC);
                        if (retval)
                                return retval;
                }
@@ -2110,6 +2127,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
 /**
  * lookup_one_len - filesystem helper to lookup single pathname component
  * @name:      pathname component to lookup
+ * @mnt:       mount we are looking up on
  * @base:      base directory to lookup from
  * @len:       maximum length @len should be interpreted to
  *
@@ -2118,7 +2136,7 @@ static struct dentry *lookup_hash(struct nameidata *nd)
  * nameidata argument is passed to the filesystem methods and a filesystem
  * using this helper needs to be prepared for that.
  */
-struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+struct dentry *lookup_one_len2(const char *name, struct vfsmount *mnt, struct dentry *base, int len)
 {
        struct qstr this;
        unsigned int c;
@@ -2152,12 +2170,19 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
                        return ERR_PTR(err);
        }
 
-       err = inode_permission(base->d_inode, MAY_EXEC);
+       err = inode_permission2(mnt, base->d_inode, MAY_EXEC);
        if (err)
                return ERR_PTR(err);
 
        return __lookup_hash(&this, base, 0);
 }
+EXPORT_SYMBOL(lookup_one_len2);
+
+struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
+{
+       return lookup_one_len2(name, NULL, base, len);
+}
+EXPORT_SYMBOL(lookup_one_len);
 
 int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
                 struct path *path, int *empty)
@@ -2247,7 +2272,7 @@ static inline int check_sticky(struct inode *dir, struct inode *inode)
  * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
  *     nfs_async_unlink().
  */
-static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
+static int may_delete(struct vfsmount *mnt, struct inode *dir,struct dentry *victim,int isdir)
 {
        int error;
 
@@ -2257,7 +2282,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
        BUG_ON(victim->d_parent->d_inode != dir);
        audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
 
-       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       error = inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
        if (IS_APPEND(dir))
@@ -2287,14 +2312,14 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
  *  3. We should have write and exec permissions on dir
  *  4. We can't do it if dir is immutable (done in permission())
  */
-static inline int may_create(struct inode *dir, struct dentry *child)
+static inline int may_create(struct vfsmount *mnt, struct inode *dir, struct dentry *child)
 {
        audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
        if (child->d_inode)
                return -EEXIST;
        if (IS_DEADDIR(dir))
                return -ENOENT;
-       return inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       return inode_permission2(mnt, dir, MAY_WRITE | MAY_EXEC);
 }
 
 /*
@@ -2339,10 +2364,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
        }
 }
 
-int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
-               bool want_excl)
+int vfs_create2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry,
+               umode_t mode, bool want_excl)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
        if (error)
                return error;
 
@@ -2358,10 +2383,19 @@ int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
                fsnotify_create(dir, dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_create2);
+
+int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+               bool want_excl)
+{
+       return vfs_create2(NULL, dir, dentry, mode, want_excl);
+}
+EXPORT_SYMBOL(vfs_create);
 
 static int may_open(struct path *path, int acc_mode, int flag)
 {
        struct dentry *dentry = path->dentry;
+       struct vfsmount *mnt = path->mnt;
        struct inode *inode = dentry->d_inode;
        int error;
 
@@ -2390,7 +2424,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
                break;
        }
 
-       error = inode_permission(inode, acc_mode);
+       error = inode_permission2(mnt, inode, acc_mode);
        if (error)
                return error;
 
@@ -2446,7 +2480,7 @@ static int may_o_create(struct path *dir, struct dentry *dentry, umode_t mode)
        if (error)
                return error;
 
-       error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
+       error = inode_permission2(dir->mnt, dir->dentry->d_inode, MAY_WRITE | MAY_EXEC);
        if (error)
                return error;
 
@@ -2634,6 +2668,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
                        bool got_write, int *opened)
 {
        struct dentry *dir = nd->path.dentry;
+       struct vfsmount *mnt = nd->path.mnt;
        struct inode *dir_inode = dir->d_inode;
        struct dentry *dentry;
        int error;
@@ -2681,7 +2716,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
                error = security_path_mknod(&nd->path, dentry, mode, 0);
                if (error)
                        goto out_dput;
-               error = vfs_create(dir->d_inode, dentry, mode,
+               error = vfs_create2(mnt, dir->d_inode, dentry, mode,
                                   nd->flags & LOOKUP_EXCL);
                if (error)
                        goto out_dput;
@@ -3142,9 +3177,9 @@ struct dentry *user_path_create(int dfd, const char __user *pathname,
 }
 EXPORT_SYMBOL(user_path_create);
 
-int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
+int vfs_mknod2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
 
        if (error)
                return error;
@@ -3168,6 +3203,13 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
                fsnotify_create(dir, dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_mknod2);
+
+int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
+{
+       return vfs_mknod2(NULL, dir, dentry, mode, dev);
+}
+EXPORT_SYMBOL(vfs_mknod);
 
 static int may_mknod(umode_t mode)
 {
@@ -3209,10 +3251,10 @@ retry:
                goto out;
        switch (mode & S_IFMT) {
                case 0: case S_IFREG:
-                       error = vfs_create(path.dentry->d_inode,dentry,mode,true);
+                       error = vfs_create2(path.mnt, path.dentry->d_inode,dentry,mode,true);
                        break;
                case S_IFCHR: case S_IFBLK:
-                       error = vfs_mknod(path.dentry->d_inode,dentry,mode,
+                       error = vfs_mknod2(path.mnt, path.dentry->d_inode,dentry,mode,
                                        new_decode_dev(dev));
                        break;
                case S_IFIFO: case S_IFSOCK:
@@ -3233,9 +3275,9 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d
        return sys_mknodat(AT_FDCWD, filename, mode, dev);
 }
 
-int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+int vfs_mkdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, umode_t mode)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
        unsigned max_links = dir->i_sb->s_max_links;
 
        if (error)
@@ -3257,6 +3299,13 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
                fsnotify_mkdir(dir, dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_mkdir2);
+
+int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       return vfs_mkdir2(NULL, dir, dentry, mode);
+}
+EXPORT_SYMBOL(vfs_mkdir);
 
 SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode)
 {
@@ -3274,7 +3323,7 @@ retry:
                mode &= ~current_umask();
        error = security_path_mkdir(&path, dentry, mode);
        if (!error)
-               error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
+               error = vfs_mkdir2(path.mnt, path.dentry->d_inode, dentry, mode);
        done_path_create(&path, dentry);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
@@ -3312,9 +3361,9 @@ void dentry_unhash(struct dentry *dentry)
        spin_unlock(&dentry->d_lock);
 }
 
-int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+int vfs_rmdir2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry)
 {
-       int error = may_delete(dir, dentry, 1);
+       int error = may_delete(mnt, dir, dentry, 1);
 
        if (error)
                return error;
@@ -3348,6 +3397,13 @@ out:
                d_delete(dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_rmdir2);
+
+int vfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       return vfs_rmdir2(NULL, dir, dentry);
+}
+EXPORT_SYMBOL(vfs_rmdir);
 
 static long do_rmdir(int dfd, const char __user *pathname)
 {
@@ -3392,11 +3448,7 @@ retry:
        error = security_path_rmdir(&nd.path, dentry);
        if (error)
                goto exit3;
-       if (nd.path.dentry->d_sb->s_op->unlink_callback) {
-               path_buf = kmalloc(PATH_MAX, GFP_KERNEL);
-               propagate_path = dentry_path_raw(dentry, path_buf, PATH_MAX);
-       }
-       error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
+       error = vfs_rmdir2(nd.path.mnt, nd.path.dentry->d_inode, dentry);
 exit3:
        dput(dentry);
 exit2:
@@ -3425,9 +3477,9 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
        return do_rmdir(AT_FDCWD, pathname);
 }
 
-int vfs_unlink(struct inode *dir, struct dentry *dentry)
+int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry)
 {
-       int error = may_delete(dir, dentry, 0);
+       int error = may_delete(mnt, dir, dentry, 0);
 
        if (error)
                return error;
@@ -3456,6 +3508,13 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
 
        return error;
 }
+EXPORT_SYMBOL(vfs_unlink2);
+
+int vfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       return vfs_unlink2(NULL, dir, dentry);
+}
+EXPORT_SYMBOL(vfs_unlink);
 
 /*
  * Make sure that the actual truncation of the file will occur outside its
@@ -3505,7 +3564,7 @@ retry:
                error = security_path_unlink(&nd.path, dentry);
                if (error)
                        goto exit2;
-               error = vfs_unlink(nd.path.dentry->d_inode, dentry);
+               error = vfs_unlink2(nd.path.mnt, nd.path.dentry->d_inode, dentry);
 exit2:
                dput(dentry);
        }
@@ -3552,9 +3611,9 @@ SYSCALL_DEFINE1(unlink, const char __user *, pathname)
        return do_unlinkat(AT_FDCWD, pathname);
 }
 
-int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+int vfs_symlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, const char *oldname)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(mnt, dir, dentry);
 
        if (error)
                return error;
@@ -3571,6 +3630,13 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
                fsnotify_create(dir, dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_symlink2);
+
+int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)
+{
+       return vfs_symlink2(NULL, dir, dentry, oldname);
+}
+EXPORT_SYMBOL(vfs_symlink);
 
 SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,
                int, newdfd, const char __user *, newname)
@@ -3592,7 +3658,7 @@ retry:
 
        error = security_path_symlink(&path, dentry, from->name);
        if (!error)
-               error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
+               error = vfs_symlink2(path.mnt, path.dentry->d_inode, dentry, from->name);
        done_path_create(&path, dentry);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
@@ -3608,7 +3674,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
        return sys_symlinkat(oldname, AT_FDCWD, newname);
 }
 
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
        struct inode *inode = old_dentry->d_inode;
        unsigned max_links = dir->i_sb->s_max_links;
@@ -3617,7 +3683,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
        if (!inode)
                return -ENOENT;
 
-       error = may_create(dir, new_dentry);
+       error = may_create(mnt, dir, new_dentry);
        if (error)
                return error;
 
@@ -3651,6 +3717,13 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
                fsnotify_link(dir, inode, new_dentry);
        return error;
 }
+EXPORT_SYMBOL(vfs_link2);
+
+int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
+{
+       return vfs_link2(NULL, old_dentry, dir, new_dentry);
+}
+EXPORT_SYMBOL(vfs_link);
 
 /*
  * Hardlinks are often used in delicate situations.  We avoid
@@ -3704,7 +3777,7 @@ retry:
        error = security_path_link(old_path.dentry, &new_path, new_dentry);
        if (error)
                goto out_dput;
-       error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
+       error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry);
 out_dput:
        done_path_create(&new_path, new_dentry);
        if (retry_estale(error, how)) {
@@ -3750,8 +3823,9 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
  *        ->i_mutex on parents, which works but leads to some truly excessive
  *        locking].
  */
-static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
-                         struct inode *new_dir, struct dentry *new_dentry)
+static int vfs_rename_dir(struct vfsmount *mnt,
+              struct inode *old_dir, struct dentry *old_dentry,
+              struct inode *new_dir, struct dentry *new_dentry)
 {
        int error = 0;
        struct inode *target = new_dentry->d_inode;
@@ -3762,7 +3836,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
         * we'll need to flip '..'.
         */
        if (new_dir != old_dir) {
-               error = inode_permission(old_dentry->d_inode, MAY_WRITE);
+               error = inode_permission2(mnt, old_dentry->d_inode, MAY_WRITE);
                if (error)
                        return error;
        }
@@ -3837,7 +3911,8 @@ out:
        return error;
 }
 
-int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+int vfs_rename2(struct vfsmount *mnt,
+              struct inode *old_dir, struct dentry *old_dentry,
               struct inode *new_dir, struct dentry *new_dentry)
 {
        int error;
@@ -3847,14 +3922,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (old_dentry->d_inode == new_dentry->d_inode)
                return 0;
  
-       error = may_delete(old_dir, old_dentry, is_dir);
+       error = may_delete(mnt, old_dir, old_dentry, is_dir);
        if (error)
                return error;
 
        if (!new_dentry->d_inode)
-               error = may_create(new_dir, new_dentry);
+               error = may_create(mnt, new_dir, new_dentry);
        else
-               error = may_delete(new_dir, new_dentry, is_dir);
+               error = may_delete(mnt, new_dir, new_dentry, is_dir);
        if (error)
                return error;
 
@@ -3864,7 +3939,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        old_name = fsnotify_oldname_init(old_dentry->d_name.name);
 
        if (is_dir)
-               error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
+               error = vfs_rename_dir(mnt, old_dir,old_dentry,new_dir,new_dentry);
        else
                error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
        if (!error)
@@ -3874,6 +3949,14 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        return error;
 }
+EXPORT_SYMBOL(vfs_rename2);
+
+int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+              struct inode *new_dir, struct dentry *new_dentry)
+{
+       return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry);
+}
+EXPORT_SYMBOL(vfs_rename);
 
 SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
                int, newdfd, const char __user *, newname)
@@ -3956,7 +4039,7 @@ retry:
                                     &newnd.path, new_dentry);
        if (error)
                goto exit5;
-       error = vfs_rename(old_dir->d_inode, old_dentry,
+       error = vfs_rename2(oldnd.path.mnt, old_dir->d_inode, old_dentry,
                                   new_dir->d_inode, new_dentry);
 exit5:
        dput(new_dentry);
@@ -4130,7 +4213,6 @@ EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(get_write_access); /* nfsd */
 EXPORT_SYMBOL(lock_rename);
-EXPORT_SYMBOL(lookup_one_len);
 EXPORT_SYMBOL(page_follow_link_light);
 EXPORT_SYMBOL(page_put_link);
 EXPORT_SYMBOL(page_readlink);
@@ -4139,18 +4221,9 @@ EXPORT_SYMBOL(page_symlink);
 EXPORT_SYMBOL(page_symlink_inode_operations);
 EXPORT_SYMBOL(kern_path);
 EXPORT_SYMBOL(vfs_path_lookup);
-EXPORT_SYMBOL(inode_permission);
 EXPORT_SYMBOL(unlock_rename);
-EXPORT_SYMBOL(vfs_create);
 EXPORT_SYMBOL(vfs_follow_link);
-EXPORT_SYMBOL(vfs_link);
-EXPORT_SYMBOL(vfs_mkdir);
-EXPORT_SYMBOL(vfs_mknod);
 EXPORT_SYMBOL(generic_permission);
 EXPORT_SYMBOL(vfs_readlink);
-EXPORT_SYMBOL(vfs_rename);
-EXPORT_SYMBOL(vfs_rmdir);
-EXPORT_SYMBOL(vfs_symlink);
-EXPORT_SYMBOL(vfs_unlink);
 EXPORT_SYMBOL(dentry_unhash);
 EXPORT_SYMBOL(generic_readlink);
index 9be6b4163406fe216dc699355e4e0b45e9e16df8..92d31fa7cb1a3e06a64a5a556fe440dbee1c510c 100644 (file)
@@ -490,7 +490,7 @@ static int fanotify_find_path(int dfd, const char __user *filename,
        }
 
        /* you can only watch an inode if you have read permissions on it */
-       ret = inode_permission(path->dentry->d_inode, MAY_READ);
+       ret = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ);
        if (ret)
                path_put(path);
 out:
index fce2b85022371a216721e8dc342c1fee2d6e3423..941e59d7ffe7f86eb20bed7f9b6ec8a8929cf81d 100644 (file)
@@ -349,7 +349,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
        if (error)
                return error;
        /* you can only watch an inode if you have read permissions on it */
-       error = inode_permission(path->dentry->d_inode, MAY_READ);
+       error = inode_permission2(path->mnt, path->dentry->d_inode, MAY_READ);
        if (error)
                path_put(path);
        return error;
index 86092bde31f4827eec31eec454ec60e2c1dcb1e8..4198b0616c83ec91d23e0f4e0d19b9915d79de47 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -65,9 +65,11 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
 long vfs_truncate(struct path *path, loff_t length)
 {
        struct inode *inode;
+       struct vfsmount *mnt;
        long error;
 
        inode = path->dentry->d_inode;
+       mnt = path->mnt;
 
        /* For directories it's -EISDIR, for other non-regulars - -EINVAL */
        if (S_ISDIR(inode->i_mode))
@@ -79,7 +81,7 @@ long vfs_truncate(struct path *path, loff_t length)
        if (error)
                goto out;
 
-       error = inode_permission(inode, MAY_WRITE);
+       error = inode_permission2(mnt, inode, MAY_WRITE);
        if (error)
                goto mnt_drop_write_and_out;
 
@@ -302,6 +304,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
        struct cred *override_cred;
        struct path path;
        struct inode *inode;
+       struct vfsmount *mnt;
        int res;
        unsigned int lookup_flags = LOOKUP_FOLLOW;
 
@@ -332,6 +335,7 @@ retry:
                goto out;
 
        inode = path.dentry->d_inode;
+       mnt = path.mnt;
 
        if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
                /*
@@ -343,7 +347,7 @@ retry:
                        goto out_path_release;
        }
 
-       res = inode_permission(inode, mode | MAY_ACCESS);
+       res = inode_permission2(mnt, inode, mode | MAY_ACCESS);
        /* SuS v2 requires we report a read only fs too */
        if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
                goto out_path_release;
@@ -387,7 +391,7 @@ retry:
        if (error)
                goto out;
 
-       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
+       error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
        if (error)
                goto dput_and_out;
 
@@ -407,6 +411,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
 {
        struct fd f = fdget_raw(fd);
        struct inode *inode;
+       struct vfsmount *mnt;
        int error = -EBADF;
 
        error = -EBADF;
@@ -414,12 +419,13 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
                goto out;
 
        inode = file_inode(f.file);
+       mnt = f.file->f_path.mnt;
 
        error = -ENOTDIR;
        if (!S_ISDIR(inode->i_mode))
                goto out_putf;
 
-       error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
+       error = inode_permission2(mnt, inode, MAY_EXEC | MAY_CHDIR);
        if (!error)
                set_fs_pwd(current->fs, &f.file->f_path);
 out_putf:
@@ -438,7 +444,7 @@ retry:
        if (error)
                goto out;
 
-       error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
+       error = inode_permission2(path.mnt, path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
        if (error)
                goto dput_and_out;
 
index f4fb7eca10e832f5b9c4405092627b94f4a163dc..67250973d966f309ed9921abd6278fb5bdfcf858 100644 (file)
@@ -96,7 +96,7 @@ static int utimes_common(struct path *path, struct timespec *times)
                        goto mnt_drop_write_and_out;
 
                if (!inode_owner_or_capable(inode)) {
-                       error = inode_permission(inode, MAY_WRITE);
+                       error = inode_permission2(path->mnt, inode, MAY_WRITE);
                        if (error)
                                goto mnt_drop_write_and_out;
                }
index abf286d24ce4411d3cc91f7347aac2eaf96ba08b..6238c7307ecd5d78d1e638ffa89d47b73abf4754 100644 (file)
@@ -1471,13 +1471,20 @@ extern bool inode_owner_or_capable(const struct inode *inode);
  * VFS helper functions..
  */
 extern int vfs_create(struct inode *, struct dentry *, umode_t, bool);
+extern int vfs_create2(struct vfsmount *, struct inode *, struct dentry *, umode_t, bool);
 extern int vfs_mkdir(struct inode *, struct dentry *, umode_t);
+extern int vfs_mkdir2(struct vfsmount *, struct inode *, struct dentry *, umode_t);
 extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
+extern int vfs_mknod2(struct vfsmount *, struct inode *, struct dentry *, umode_t, dev_t);
 extern int vfs_symlink(struct inode *, struct dentry *, const char *);
 extern int vfs_link(struct dentry *, struct inode *, struct dentry *);
+extern int vfs_link2(struct vfsmount *, struct dentry *, struct inode *, struct dentry *);
 extern int vfs_rmdir(struct inode *, struct dentry *);
+extern int vfs_rmdir2(struct vfsmount *, struct inode *, struct dentry *);
 extern int vfs_unlink(struct inode *, struct dentry *);
+extern int vfs_unlink2(struct vfsmount *, struct inode *, struct dentry *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
+extern int vfs_rename2(struct vfsmount *, struct inode *, struct dentry *, struct inode *, struct dentry *);
 
 /*
  * VFS dentry helper functions.
@@ -1571,6 +1578,7 @@ struct inode_operations {
        struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
        void * (*follow_link) (struct dentry *, struct nameidata *);
        int (*permission) (struct inode *, int);
+       int (*permission2) (struct vfsmount *, struct inode *, int);
        struct posix_acl * (*get_acl)(struct inode *, int);
 
        int (*readlink) (struct dentry *, char __user *,int);
@@ -2240,6 +2248,7 @@ extern sector_t bmap(struct inode *, sector_t);
 #endif
 extern int notify_change(struct dentry *, struct iattr *);
 extern int inode_permission(struct inode *, int);
+extern int inode_permission2(struct vfsmount *, struct inode *, int);
 extern int generic_permission(struct inode *, int);
 
 static inline bool execute_ok(struct inode *inode)
index 5a5ff57ceed4e74f76237437fc3b22453ec27a66..f10c7f29f5e07681b7f66fe5aab09ccdd944b606 100644 (file)
@@ -74,6 +74,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
                           const char *, unsigned int, struct path *);
 
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
+extern struct dentry *lookup_one_len2(const char *, struct vfsmount *mnt, struct dentry *, int);
 
 extern int follow_down_one(struct path *);
 extern int follow_down(struct path *);
index bb0248fc5187724950d88a6f15cac85bedbf98b9..88d97d21a3990f65bf647c8c48d649a6676a87aa 100644 (file)
@@ -754,7 +754,7 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct inode *dir,
        }
 
        mode &= ~current_umask();
-       ret = vfs_create(dir, path->dentry, mode, true);
+       ret = vfs_create2(path->mnt, dir, path->dentry, mode, true);
        path->dentry->d_fsdata = NULL;
        if (ret)
                return ERR_PTR(ret);
@@ -770,7 +770,7 @@ static struct file *do_open(struct path *path, int oflag)
        if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY))
                return ERR_PTR(-EINVAL);
        acc = oflag2acc[oflag & O_ACCMODE];
-       if (inode_permission(path->dentry->d_inode, acc))
+       if (inode_permission2(path->mnt, path->dentry->d_inode, acc))
                return ERR_PTR(-EACCES);
        return dentry_open(path, oflag, current_cred());
 }
@@ -803,7 +803,7 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, umode_t, mode,
        ro = mnt_want_write(mnt);       /* we'll drop it in any case */
        error = 0;
        mutex_lock(&root->d_inode->i_mutex);
-       path.dentry = lookup_one_len(name->name, root, strlen(name->name));
+       path.dentry = lookup_one_len2(name->name, mnt, root, strlen(name->name));
        if (IS_ERR(path.dentry)) {
                error = PTR_ERR(path.dentry);
                goto out_putfd;
@@ -874,7 +874,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
        if (err)
                goto out_name;
        mutex_lock_nested(&mnt->mnt_root->d_inode->i_mutex, I_MUTEX_PARENT);
-       dentry = lookup_one_len(name->name, mnt->mnt_root,
+       dentry = lookup_one_len2(name->name, mnt, mnt->mnt_root,
                                strlen(name->name));
        if (IS_ERR(dentry)) {
                err = PTR_ERR(dentry);
@@ -886,7 +886,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
                err = -ENOENT;
        } else {
                ihold(inode);
-               err = vfs_unlink(dentry->d_parent->d_inode, dentry);
+               err = vfs_unlink2(mnt, dentry->d_parent->d_inode, dentry);
        }
        dput(dentry);
 
index 43ce6e19015fc81e80786c26a07e2ac47e71109b..94466a5eed508cd8ef544c89424946064a97dfab 100644 (file)
@@ -105,7 +105,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
        dir = parent->d_inode;
 
        mutex_lock(&dir->i_mutex);
-       dentry = lookup_one_len(name, parent, strlen(name));
+       dentry = lookup_one_len2(name, mount, parent, strlen(name));
        if (IS_ERR(dentry))
                goto out;