ANDROID: 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)
committerAmit Pundir <amit.pundir@linaro.org>
Fri, 3 Feb 2017 09:34:29 +0000 (15:04 +0530)
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
include/linux/fs.h
include/linux/namei.h
ipc/mqueue.c
security/inode.c

index 3a6de10d38918db2dca9e3d0067b7bc0b456875f..8c58183eccb737be4946e5a0b5eb8e869adb2059 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1132,7 +1132,7 @@ EXPORT_SYMBOL(flush_old_exec);
 void would_dump(struct linux_binprm *bprm, struct file *file)
 {
        struct inode *inode = file_inode(file);
-       if (inode_permission(inode, MAY_READ) < 0) {
+       if (inode_permission2(file->f_path.mnt, inode, MAY_READ) < 0) {
                struct user_namespace *old, *user_ns;
                bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP;
 
index 0b0acba72a715aaa4ba22c6241c2ed3b10183121..3885e445d95142db081578b9fbc41e295edb5d2a 100644 (file)
@@ -373,9 +373,11 @@ EXPORT_SYMBOL(generic_permission);
  * 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);
 
@@ -399,7 +401,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;
 
@@ -411,7 +413,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;
 
@@ -419,7 +421,14 @@ int __inode_permission(struct inode *inode, int mask)
        if (retval)
                return retval;
 
-       return security_inode_permission(inode, mask);
+       retval = security_inode_permission(inode, mask);
+       return retval;
+}
+EXPORT_SYMBOL(__inode_permission2);
+
+int __inode_permission(struct inode *inode, int mask)
+{
+       return __inode_permission2(NULL, inode, mask);
 }
 EXPORT_SYMBOL(__inode_permission);
 
@@ -455,14 +464,20 @@ 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);
 
@@ -1645,13 +1660,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, 0))
                        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)
@@ -2005,11 +2020,12 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
        nd->depth = 0;
        if (flags & LOOKUP_ROOT) {
                struct dentry *root = nd->root.dentry;
+               struct vfsmount *mnt = nd->root.mnt;
                struct inode *inode = root->d_inode;
                if (*s) {
                        if (!d_can_lookup(root))
                                return ERR_PTR(-ENOTDIR);
-                       retval = inode_permission(inode, MAY_EXEC);
+                       retval = inode_permission2(mnt, inode, MAY_EXEC);
                        if (retval)
                                return ERR_PTR(retval);
                }
@@ -2280,13 +2296,14 @@ EXPORT_SYMBOL(vfs_path_lookup);
 /**
  * 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
  *
  * Note that this routine is purely a helper for filesystem usage and should
  * not be called by generic code.
  */
-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;
@@ -2320,12 +2337,18 @@ 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,
@@ -2552,7 +2575,7 @@ EXPORT_SYMBOL(__check_sticky);
  * 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, bool isdir)
+static int may_delete(struct vfsmount *mnt, struct inode *dir, struct dentry *victim, bool isdir)
 {
        struct inode *inode = d_backing_inode(victim);
        int error;
@@ -2564,7 +2587,7 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool 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))
@@ -2595,14 +2618,14 @@ static int may_delete(struct inode *dir, struct dentry *victim, bool 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);
 }
 
 /*
@@ -2649,10 +2672,10 @@ void unlock_rename(struct dentry *p1, struct dentry *p2)
 }
 EXPORT_SYMBOL(unlock_rename);
 
-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;
 
@@ -2668,11 +2691,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;
 
@@ -2701,7 +2732,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;
 
@@ -2757,7 +2788,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;
 
@@ -2943,6 +2974,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;
@@ -2990,7 +3022,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;
@@ -3252,7 +3284,7 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
                goto out;
        dir = path.dentry->d_inode;
        /* we want directory to be writable */
-       error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
+       error = inode_permission2(path.mnt, dir, MAY_WRITE | MAY_EXEC);
        if (error)
                goto out2;
        if (!dir->i_op->tmpfile) {
@@ -3486,9 +3518,9 @@ inline 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;
@@ -3512,6 +3544,12 @@ 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)
@@ -3554,10 +3592,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:
@@ -3578,9 +3616,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)
@@ -3602,6 +3640,12 @@ 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)
@@ -3620,7 +3664,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;
@@ -3659,9 +3703,9 @@ void dentry_unhash(struct dentry *dentry)
 }
 EXPORT_SYMBOL(dentry_unhash);
 
-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;
@@ -3696,6 +3740,10 @@ out:
                d_delete(dentry);
        return error;
 }
+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)
@@ -3741,7 +3789,7 @@ retry:
        error = security_path_rmdir(&path, dentry);
        if (error)
                goto exit3;
-       error = vfs_rmdir(path.dentry->d_inode, dentry);
+       error = vfs_rmdir2(path.mnt, path.dentry->d_inode, dentry);
 exit3:
        dput(dentry);
 exit2:
@@ -3780,10 +3828,10 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.
  */
-int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
+int vfs_unlink2(struct vfsmount *mnt, struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
 {
        struct inode *target = dentry->d_inode;
-       int error = may_delete(dir, dentry, 0);
+       int error = may_delete(mnt, dir, dentry, 0);
 
        if (error)
                return error;
@@ -3818,6 +3866,12 @@ out:
 
        return error;
 }
+EXPORT_SYMBOL(vfs_unlink2);
+
+int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
+{
+       return vfs_unlink2(NULL, dir, dentry, delegated_inode);
+}
 EXPORT_SYMBOL(vfs_unlink);
 
 /*
@@ -3865,7 +3919,7 @@ retry_deleg:
                error = security_path_unlink(&path, dentry);
                if (error)
                        goto exit2;
-               error = vfs_unlink(path.dentry->d_inode, dentry, &delegated_inode);
+               error = vfs_unlink2(path.mnt, path.dentry->d_inode, dentry, &delegated_inode);
 exit2:
                dput(dentry);
        }
@@ -3915,9 +3969,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;
@@ -3934,6 +3988,12 @@ 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,
@@ -3956,7 +4016,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;
@@ -3991,7 +4051,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.
  */
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
+int vfs_link2(struct vfsmount *mnt, struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
 {
        struct inode *inode = old_dentry->d_inode;
        unsigned max_links = dir->i_sb->s_max_links;
@@ -4000,7 +4060,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;
 
@@ -4043,6 +4103,12 @@ 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, struct inode **delegated_inode)
+{
+       return vfs_link2(NULL, old_dentry, dir, new_dentry, delegated_inode);
+}
 EXPORT_SYMBOL(vfs_link);
 
 /*
@@ -4098,7 +4164,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, &delegated_inode);
+       error = vfs_link2(old_path.mnt, old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
 out_dput:
        done_path_create(&new_path, new_dentry);
        if (delegated_inode) {
@@ -4173,7 +4239,8 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
  *        ->i_mutex on parents, which works but leads to some truly excessive
  *        locking].
  */
-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,
               struct inode **delegated_inode, unsigned int flags)
 {
@@ -4192,19 +4259,19 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (vfs_select_inode(old_dentry, 0) == vfs_select_inode(new_dentry, 0))
                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 (!target) {
-               error = may_create(new_dir, new_dentry);
+               error = may_create(mnt, new_dir, new_dentry);
        } else {
                new_is_dir = d_is_dir(new_dentry);
 
                if (!(flags & RENAME_EXCHANGE))
-                       error = may_delete(new_dir, new_dentry, is_dir);
+                       error = may_delete(mnt, new_dir, new_dentry, is_dir);
                else
-                       error = may_delete(new_dir, new_dentry, new_is_dir);
+                       error = may_delete(mnt, new_dir, new_dentry, new_is_dir);
        }
        if (error)
                return error;
@@ -4221,12 +4288,12 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         */
        if (new_dir != old_dir) {
                if (is_dir) {
-                       error = inode_permission(source, MAY_WRITE);
+                       error = inode_permission2(mnt, source, MAY_WRITE);
                        if (error)
                                return error;
                }
                if ((flags & RENAME_EXCHANGE) && new_is_dir) {
-                       error = inode_permission(target, MAY_WRITE);
+                       error = inode_permission2(mnt, target, MAY_WRITE);
                        if (error)
                                return error;
                }
@@ -4309,6 +4376,14 @@ out:
 
        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,
+              struct inode **delegated_inode, unsigned int flags)
+{
+       return vfs_rename2(NULL, old_dir, old_dentry, new_dir, new_dentry, delegated_inode, flags);
+}
 EXPORT_SYMBOL(vfs_rename);
 
 SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
@@ -4422,7 +4497,7 @@ retry_deleg:
                                     &new_path, new_dentry, flags);
        if (error)
                goto exit5;
-       error = vfs_rename(old_path.dentry->d_inode, old_dentry,
+       error = vfs_rename2(old_path.mnt, old_path.dentry->d_inode, old_dentry,
                           new_path.dentry->d_inode, new_dentry,
                           &delegated_inode, flags);
 exit5:
@@ -4467,7 +4542,7 @@ SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newna
 
 int vfs_whiteout(struct inode *dir, struct dentry *dentry)
 {
-       int error = may_create(dir, dentry);
+       int error = may_create(NULL, dir, dentry);
        if (error)
                return error;
 
index a64313868d3a15cefca72b5e228e798d98a43a1e..2958e7a81f9c90f02fe4004a06d533a989c9d78e 100644 (file)
@@ -488,7 +488,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 e2893f17dde24e88b2ac9e17708179db4ce11911..4c5b43d15e6e06d8ef9137f138809ee16280cc43 100644 (file)
@@ -337,7 +337,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 157b9940dd733b50b0ffe528e2e8c94fe4796ec3..df1a8c2cd56ae7e610e1f265e1c83e93020cecb8 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -68,9 +68,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))
@@ -82,7 +84,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;
 
@@ -340,6 +342,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;
 
@@ -370,6 +373,7 @@ retry:
                goto out;
 
        inode = d_backing_inode(path.dentry);
+       mnt = path.mnt;
 
        if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
                /*
@@ -381,7 +385,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;
@@ -425,7 +429,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;
 
@@ -445,6 +449,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
 {
        struct fd f = fdget_raw(fd);
        struct inode *inode;
+       struct vfsmount *mnt;
        int error = -EBADF;
 
        error = -EBADF;
@@ -452,12 +457,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:
@@ -476,7 +482,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 e26cf250d97dedbe4aa9346ddd0370355cc7e95a..eded3090afced59e15448a6f0ef048a2d962f89b 100644 (file)
@@ -1539,13 +1539,21 @@ 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_symlink2(struct vfsmount *, struct inode *, struct dentry *, const char *);
 extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **);
+extern int vfs_link2(struct vfsmount *, struct dentry *, struct inode *, struct dentry *, struct inode **);
 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 *, struct inode **);
+extern int vfs_unlink2(struct vfsmount *, struct inode *, struct dentry *, struct inode **);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
+extern int vfs_rename2(struct vfsmount *, struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
 extern int vfs_whiteout(struct inode *, struct dentry *);
 
 /*
@@ -1671,6 +1679,7 @@ struct inode_operations {
        struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
        const char * (*follow_link) (struct dentry *, void **);
        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);
@@ -2478,7 +2487,9 @@ extern sector_t bmap(struct inode *, sector_t);
 #endif
 extern int notify_change(struct dentry *, struct iattr *, struct inode **);
 extern int inode_permission(struct inode *, int);
+extern int inode_permission2(struct vfsmount *, struct inode *, int);
 extern int __inode_permission(struct inode *, int);
+extern int __inode_permission2(struct vfsmount *, struct inode *, int);
 extern int generic_permission(struct inode *, int);
 extern int __check_sticky(struct inode *dir, struct inode *inode);
 
index d53c25453aca084e9b0390473323ac9897961167..023359f185675f3f9d09f919d45212f145aa3828 100644 (file)
@@ -79,6 +79,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 161a1807e6efb0fe8e773c41dafc8b4a76b38f71..25b7a678f9efa0336b665b6af0fe236bc46043d1 100644 (file)
@@ -747,7 +747,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);
@@ -763,7 +763,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(d_inode(path->dentry), acc))
+       if (inode_permission2(path->mnt, d_inode(path->dentry), acc))
                return ERR_PTR(-EACCES);
        return dentry_open(path, oflag, current_cred());
 }
@@ -796,7 +796,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(&d_inode(root)->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;
@@ -867,7 +867,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
        if (err)
                goto out_name;
        mutex_lock_nested(&d_inode(mnt->mnt_root)->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);
@@ -879,7 +879,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
                err = -ENOENT;
        } else {
                ihold(inode);
-               err = vfs_unlink(d_inode(dentry->d_parent), dentry, NULL);
+               err = vfs_unlink2(mnt, d_inode(dentry->d_parent), dentry, NULL);
        }
        dput(dentry);
 
index 16622aef9bdea83bee67e5e0080c7b9a17d240ae..0f1a041bf6cb99ea8461756cb576d58536328c66 100644 (file)
@@ -100,7 +100,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
        dir = d_inode(parent);
 
        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;