]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/namei.c
Btrfs: fix scrub to repair raid6 corruption
[mirror_ubuntu-bionic-kernel.git] / fs / namei.c
index ed8b9488a890c2b936e249ab16e6a44a292a9521..0f9cc69c6ebecfddef31a96635a5ad6d950f8909 100644 (file)
@@ -222,9 +222,10 @@ getname_kernel(const char * filename)
        if (len <= EMBEDDED_NAME_MAX) {
                result->name = (char *)result->iname;
        } else if (len <= PATH_MAX) {
+               const size_t size = offsetof(struct filename, iname[1]);
                struct filename *tmp;
 
-               tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+               tmp = kmalloc(size, GFP_KERNEL);
                if (unlikely(!tmp)) {
                        __putname(result);
                        return ERR_PTR(-ENOMEM);
@@ -578,9 +579,10 @@ static int __nd_alloc_stack(struct nameidata *nd)
 static bool path_connected(const struct path *path)
 {
        struct vfsmount *mnt = path->mnt;
+       struct super_block *sb = mnt->mnt_sb;
 
-       /* Only bind mounts can have disconnected paths */
-       if (mnt->mnt_root == mnt->mnt_sb->s_root)
+       /* Bind mounts and multi-root filesystems can have disconnected paths */
+       if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root))
                return true;
 
        return is_subdir(path->dentry, mnt->mnt_root);
@@ -900,8 +902,8 @@ static inline void put_link(struct nameidata *nd)
                path_put(&last->link);
 }
 
-int sysctl_protected_symlinks __read_mostly = 0;
-int sysctl_protected_hardlinks __read_mostly = 0;
+int sysctl_protected_symlinks __read_mostly = 1;
+int sysctl_protected_hardlinks __read_mostly = 1;
 
 /**
  * may_follow_link - Check symlink following for unsafe situations
@@ -1129,21 +1131,9 @@ static int follow_automount(struct path *path, struct nameidata *nd,
         * of the daemon to instantiate them before they can be used.
         */
        if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
-                          LOOKUP_OPEN | LOOKUP_CREATE |
-                          LOOKUP_AUTOMOUNT))) {
-               /* Positive dentry that isn't meant to trigger an
-                * automount, EISDIR will allow it to be used,
-                * otherwise there's no mount here "now" so return
-                * ENOENT.
-                */
-               if (path->dentry->d_inode)
-                       return -EISDIR;
-               else
-                       return -ENOENT;
-       }
-
-       if (path->dentry->d_sb->s_user_ns != &init_user_ns)
-               return -EACCES;
+                          LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) &&
+           path->dentry->d_inode)
+               return -EISDIR;
 
        nd->total_link_count++;
        if (nd->total_link_count >= 40)
@@ -1210,7 +1200,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
        /* Given that we're not holding a lock here, we retain the value in a
         * local variable for each dentry as we look at it so that we don't see
         * the components of that value change under us */
-       while (managed = ACCESS_ONCE(path->dentry->d_flags),
+       while (managed = READ_ONCE(path->dentry->d_flags),
               managed &= DCACHE_MANAGED_DENTRY,
               unlikely(managed != 0)) {
                /* Allow the filesystem to manage the transit without i_mutex
@@ -1395,7 +1385,7 @@ int follow_down(struct path *path)
        unsigned managed;
        int ret;
 
-       while (managed = ACCESS_ONCE(path->dentry->d_flags),
+       while (managed = READ_ONCE(path->dentry->d_flags),
               unlikely(managed & DCACHE_MANAGED_DENTRY)) {
                /* Allow the filesystem to manage the transit without i_mutex
                 * being held.
@@ -3459,7 +3449,7 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
                goto out;
        child = vfs_tmpfile(path.dentry, op->mode, op->open_flag);
        error = PTR_ERR(child);
-       if (unlikely(IS_ERR(child)))
+       if (IS_ERR(child))
                goto out2;
        dput(path.dentry);
        path.dentry = child;
@@ -4010,10 +4000,9 @@ EXPORT_SYMBOL(vfs_unlink);
  * writeout happening, and we don't want to prevent access to the directory
  * while waiting on the I/O.
  */
-static long do_unlinkat(int dfd, const char __user *pathname)
+long do_unlinkat(int dfd, struct filename *name)
 {
        int error;
-       struct filename *name;
        struct dentry *dentry;
        struct path path;
        struct qstr last;
@@ -4022,8 +4011,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
        struct inode *delegated_inode = NULL;
        unsigned int lookup_flags = 0;
 retry:
-       name = filename_parentat(dfd, getname(pathname), lookup_flags,
-                               &path, &last, &type);
+       name = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
        if (IS_ERR(name))
                return PTR_ERR(name);
 
@@ -4065,12 +4053,12 @@ exit2:
        mnt_drop_write(path.mnt);
 exit1:
        path_put(&path);
-       putname(name);
        if (retry_estale(error, lookup_flags)) {
                lookup_flags |= LOOKUP_REVAL;
                inode = NULL;
                goto retry;
        }
+       putname(name);
        return error;
 
 slashes:
@@ -4091,12 +4079,12 @@ SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag)
        if (flag & AT_REMOVEDIR)
                return do_rmdir(dfd, pathname);
 
-       return do_unlinkat(dfd, pathname);
+       return do_unlinkat(dfd, getname(pathname));
 }
 
 SYSCALL_DEFINE1(unlink, const char __user *, pathname)
 {
-       return do_unlinkat(AT_FDCWD, pathname);
+       return do_unlinkat(AT_FDCWD, getname(pathname));
 }
 
 int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname)