Skip to content

Commit cf2a2c6

Browse files
Maxim Patlasovgregkh
authored andcommitted
ovl: verify upper dentry in ovl_remove_and_whiteout()
commit cfc9fde0b07c3b44b570057c5f93dda59dca1c94 upstream. 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@virtuozzo.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c12dada commit cf2a2c6

1 file changed

Lines changed: 24 additions & 30 deletions

File tree

fs/overlayfs/dir.c

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
511511
struct dentry *upper;
512512
struct dentry *opaquedir = NULL;
513513
int err;
514+
int flags = 0;
514515

515516
if (WARN_ON(!workdir))
516517
return -EROFS;
@@ -540,46 +541,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
540541
if (err)
541542
goto out_dput;
542543

543-
whiteout = ovl_whiteout(workdir, dentry);
544-
err = PTR_ERR(whiteout);
545-
if (IS_ERR(whiteout))
544+
upper = lookup_one_len(dentry->d_name.name, upperdir,
545+
dentry->d_name.len);
546+
err = PTR_ERR(upper);
547+
if (IS_ERR(upper))
546548
goto out_unlock;
547549

548-
upper = ovl_dentry_upper(dentry);
549-
if (!upper) {
550-
upper = lookup_one_len(dentry->d_name.name, upperdir,
551-
dentry->d_name.len);
552-
err = PTR_ERR(upper);
553-
if (IS_ERR(upper))
554-
goto kill_whiteout;
555-
556-
err = ovl_do_rename(wdir, whiteout, udir, upper, 0);
557-
dput(upper);
558-
if (err)
559-
goto kill_whiteout;
560-
} else {
561-
int flags = 0;
550+
err = -ESTALE;
551+
if ((opaquedir && upper != opaquedir) ||
552+
(!opaquedir && ovl_dentry_upper(dentry) &&
553+
upper != ovl_dentry_upper(dentry))) {
554+
goto out_dput_upper;
555+
}
562556

563-
if (opaquedir)
564-
upper = opaquedir;
565-
err = -ESTALE;
566-
if (upper->d_parent != upperdir)
567-
goto kill_whiteout;
557+
whiteout = ovl_whiteout(workdir, dentry);
558+
err = PTR_ERR(whiteout);
559+
if (IS_ERR(whiteout))
560+
goto out_dput_upper;
568561

569-
if (is_dir)
570-
flags |= RENAME_EXCHANGE;
562+
if (d_is_dir(upper))
563+
flags = RENAME_EXCHANGE;
571564

572-
err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
573-
if (err)
574-
goto kill_whiteout;
565+
err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
566+
if (err)
567+
goto kill_whiteout;
568+
if (flags)
569+
ovl_cleanup(wdir, upper);
575570

576-
if (is_dir)
577-
ovl_cleanup(wdir, upper);
578-
}
579571
ovl_dentry_version_inc(dentry->d_parent);
580572
out_d_drop:
581573
d_drop(dentry);
582574
dput(whiteout);
575+
out_dput_upper:
576+
dput(upper);
583577
out_unlock:
584578
unlock_rename(workdir, upperdir);
585579
out_dput:

0 commit comments

Comments
 (0)