ovl: copy-up: don't unlock between lookup and link
authorMiklos Szeredi <mszeredi@redhat.com>
Wed, 28 Jun 2017 11:41:22 +0000 (13:41 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Wed, 28 Jun 2017 11:41:22 +0000 (13:41 +0200)
Nothing prevents mischief on upper layer while we are busy copying up the
data.

Move the lookup right before the looked up dentry is actually used.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Fixes: 01ad3eb8a073 ("ovl: concurrent copy up of regular files")
Cc: <stable@vger.kernel.org> # v4.11
fs/overlayfs/copy_up.c

index 7a44533f4bbf24134a95bdc030bde5779f28457a..ded8bfeb193ebde911676444174a6ea35a0540c7 100644 (file)
@@ -330,15 +330,9 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
                .link = link
        };
 
-       upper = lookup_one_len(dentry->d_name.name, upperdir,
-                              dentry->d_name.len);
-       err = PTR_ERR(upper);
-       if (IS_ERR(upper))
-               goto out;
-
        err = security_inode_copy_up(dentry, &new_creds);
        if (err < 0)
-               goto out1;
+               goto out;
 
        if (new_creds)
                old_creds = override_creds(new_creds);
@@ -362,7 +356,7 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
        }
 
        if (err)
-               goto out2;
+               goto out;
 
        if (S_ISREG(stat->mode)) {
                struct path upperpath;
@@ -403,6 +397,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
        if (err)
                goto out_cleanup;
 
+       upper = lookup_one_len(dentry->d_name.name, upperdir,
+                              dentry->d_name.len);
+       if (IS_ERR(upper)) {
+               err = PTR_ERR(upper);
+               upper = NULL;
+               goto out_cleanup;
+       }
+
        if (tmpfile)
                err = ovl_do_link(temp, udir, upper, true);
        else
@@ -416,17 +418,15 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
 
        /* Restore timestamps on parent (best effort) */
        ovl_set_timestamps(upperdir, pstat);
-out2:
+out:
        dput(temp);
-out1:
        dput(upper);
-out:
        return err;
 
 out_cleanup:
        if (!tmpfile)
                ovl_cleanup(wdir, temp);
-       goto out2;
+       goto out;
 }
 
 /*