Commit cfc9fde0 authored by Maxim Patlasov's avatar Maxim Patlasov Committed by Miklos Szeredi

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 11f37104 ("ovl: verify upper dentry before unlink and rename").
Signed-off-by: default avatarMaxim Patlasov <mpatlasov@virtuozzo.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
Cc: <stable@vger.kernel.org>
parent 07a2daab
...@@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) ...@@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
struct dentry *upper; struct dentry *upper;
struct dentry *opaquedir = NULL; struct dentry *opaquedir = NULL;
int err; int err;
int flags = 0;
if (WARN_ON(!workdir)) if (WARN_ON(!workdir))
return -EROFS; return -EROFS;
...@@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) ...@@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
if (err) if (err)
goto out_dput; goto out_dput;
whiteout = ovl_whiteout(workdir, dentry);
err = PTR_ERR(whiteout);
if (IS_ERR(whiteout))
goto out_unlock;
upper = ovl_dentry_upper(dentry);
if (!upper) {
upper = lookup_one_len(dentry->d_name.name, upperdir, upper = lookup_one_len(dentry->d_name.name, upperdir,
dentry->d_name.len); dentry->d_name.len);
err = PTR_ERR(upper); err = PTR_ERR(upper);
if (IS_ERR(upper)) if (IS_ERR(upper))
goto kill_whiteout; goto out_unlock;
err = ovl_do_rename(wdir, whiteout, udir, upper, 0);
dput(upper);
if (err)
goto kill_whiteout;
} else {
int flags = 0;
if (opaquedir)
upper = opaquedir;
err = -ESTALE; err = -ESTALE;
if (upper->d_parent != upperdir) if ((opaquedir && upper != opaquedir) ||
goto kill_whiteout; (!opaquedir && ovl_dentry_upper(dentry) &&
upper != ovl_dentry_upper(dentry))) {
goto out_dput_upper;
}
if (is_dir) whiteout = ovl_whiteout(workdir, dentry);
flags |= RENAME_EXCHANGE; err = PTR_ERR(whiteout);
if (IS_ERR(whiteout))
goto out_dput_upper;
if (d_is_dir(upper))
flags = RENAME_EXCHANGE;
err = ovl_do_rename(wdir, whiteout, udir, upper, flags); err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
if (err) if (err)
goto kill_whiteout; goto kill_whiteout;
if (flags)
if (is_dir)
ovl_cleanup(wdir, upper); ovl_cleanup(wdir, upper);
}
ovl_dentry_version_inc(dentry->d_parent); ovl_dentry_version_inc(dentry->d_parent);
out_d_drop: out_d_drop:
d_drop(dentry); d_drop(dentry);
dput(whiteout); dput(whiteout);
out_dput_upper:
dput(upper);
out_unlock: out_unlock:
unlock_rename(workdir, upperdir); unlock_rename(workdir, upperdir);
out_dput: out_dput:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment