[Devel] [PATCH RHEL7 COMMIT] ms/ovl: verify upper dentry in ovl_remove_and_whiteout()

Konstantin Khorenko khorenko at virtuozzo.com
Tue Aug 9 01:06:21 PDT 2016


The commit is pushed to "branch-rh7-3.10.0-327.22.2.vz7.16.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.22.2.vz7.16.3
------>
commit 81c52241a5b43adbf1fa7acbceb5072cffe8a9cf
Author: Maxim Patlasov <mpatlasov at virtuozzo.com>
Date:   Tue Aug 9 12:06:21 2016 +0400

    ms/ovl: verify upper dentry in ovl_remove_and_whiteout()
    
    Backport from git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git:
    
    commit cfc9fde0b07c3b44b570057c5f93dda59dca1c94
    Author: Maxim Patlasov <mpatlasov at virtuozzo.com>
    Date:   Thu Jul 21 18:24:26 2016 -0700
    
        ovl: verify upper dentry in ovl_remove_and_whiteout()
    
        The upper dentry may become stale before we call ovl_lock_rename_workdir.
        For example, someone could (mistakenly or maliciously) manually unlink(2)
        it directly from upperdir.
    
        To ensure it is not stale, let's lookup it after ovl_lock_rename_workdir
        and and check if it matches the upper dentry.
    
        Essentially, it is the same problem and similar solution as in
        commit 11f3710417d0 ("ovl: verify upper dentry before unlink and rename").
    
        Signed-off-by: Maxim Patlasov <mpatlasov at virtuozzo.com>
        Signed-off-by: Miklos Szeredi <mszeredi at redhat.com>
        Cc: <stable at vger.kernel.org>
    
    https://jira.sw.ru/browse/PSBM-47981
    
    Signed-off-by: Maxim Patlasov <mpatlasov at virtuozzo.com>
---
 fs/overlayfs/dir.c | 54 ++++++++++++++++++++++++------------------------------
 1 file changed, 24 insertions(+), 30 deletions(-)

diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 229b9e4..5402b9b 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -511,6 +511,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
 	struct dentry *upper;
 	struct dentry *opaquedir = NULL;
 	int err;
+	int flags = 0;
 
 	if (WARN_ON(!workdir))
 		return -EROFS;
@@ -540,46 +541,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
 	if (err)
 		goto out_dput;
 
-	whiteout = ovl_whiteout(workdir, dentry);
-	err = PTR_ERR(whiteout);
-	if (IS_ERR(whiteout))
+	upper = lookup_one_len(dentry->d_name.name, upperdir,
+			       dentry->d_name.len);
+	err = PTR_ERR(upper);
+	if (IS_ERR(upper))
 		goto out_unlock;
 
-	upper = ovl_dentry_upper(dentry);
-	if (!upper) {
-		upper = lookup_one_len(dentry->d_name.name, upperdir,
-				       dentry->d_name.len);
-		err = PTR_ERR(upper);
-		if (IS_ERR(upper))
-			goto kill_whiteout;
-
-		err = ovl_do_rename(wdir, whiteout, udir, upper, 0);
-		dput(upper);
-		if (err)
-			goto kill_whiteout;
-	} else {
-		int flags = 0;
+	err = -ESTALE;
+	if ((opaquedir && upper != opaquedir) ||
+	    (!opaquedir && ovl_dentry_upper(dentry) &&
+	     upper != ovl_dentry_upper(dentry))) {
+		goto out_dput_upper;
+	}
 
-		if (opaquedir)
-			upper = opaquedir;
-		err = -ESTALE;
-		if (upper->d_parent != upperdir)
-			goto kill_whiteout;
+	whiteout = ovl_whiteout(workdir, dentry);
+	err = PTR_ERR(whiteout);
+	if (IS_ERR(whiteout))
+		goto out_dput_upper;
 
-		if (is_dir)
-			flags |= RENAME_EXCHANGE;
+	if (d_is_dir(upper))
+		flags = RENAME_EXCHANGE;
 
-		err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
-		if (err)
-			goto kill_whiteout;
+	err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
+	if (err)
+		goto kill_whiteout;
+	if (flags)
+		ovl_cleanup(wdir, upper);
 
-		if (is_dir)
-			ovl_cleanup(wdir, upper);
-	}
 	ovl_dentry_version_inc(dentry->d_parent);
 out_d_drop:
 	d_drop(dentry);
 	dput(whiteout);
+out_dput_upper:
+	dput(upper);
 out_unlock:
 	unlock_rename(workdir, upperdir);
 out_dput:


More information about the Devel mailing list