aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxim Patlasov <mpatlasov@virtuozzo.com>2016-07-21 21:24:26 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-07-22 04:54:20 -0400
commitcfc9fde0b07c3b44b570057c5f93dda59dca1c94 (patch)
tree7f36d4f2a49719673c436767707d25ef5f5e9041
parent07a2daab49c549a37b5b744cbebb6e3f445f12bc (diff)
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@virtuozzo.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Cc: <stable@vger.kernel.org>
-rw-r--r--fs/overlayfs/dir.c54
1 files changed, 24 insertions, 30 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index c2a6b0894022..5c9d2d80ff70 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
505 struct dentry *upper; 505 struct dentry *upper;
506 struct dentry *opaquedir = NULL; 506 struct dentry *opaquedir = NULL;
507 int err; 507 int err;
508 int flags = 0;
508 509
509 if (WARN_ON(!workdir)) 510 if (WARN_ON(!workdir))
510 return -EROFS; 511 return -EROFS;
@@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
534 if (err) 535 if (err)
535 goto out_dput; 536 goto out_dput;
536 537
537 whiteout = ovl_whiteout(workdir, dentry); 538 upper = lookup_one_len(dentry->d_name.name, upperdir,
538 err = PTR_ERR(whiteout); 539 dentry->d_name.len);
539 if (IS_ERR(whiteout)) 540 err = PTR_ERR(upper);
541 if (IS_ERR(upper))
540 goto out_unlock; 542 goto out_unlock;
541 543
542 upper = ovl_dentry_upper(dentry); 544 err = -ESTALE;
543 if (!upper) { 545 if ((opaquedir && upper != opaquedir) ||
544 upper = lookup_one_len(dentry->d_name.name, upperdir, 546 (!opaquedir && ovl_dentry_upper(dentry) &&
545 dentry->d_name.len); 547 upper != ovl_dentry_upper(dentry))) {
546 err = PTR_ERR(upper); 548 goto out_dput_upper;
547 if (IS_ERR(upper)) 549 }
548 goto kill_whiteout;
549
550 err = ovl_do_rename(wdir, whiteout, udir, upper, 0);
551 dput(upper);
552 if (err)
553 goto kill_whiteout;
554 } else {
555 int flags = 0;
556 550
557 if (opaquedir) 551 whiteout = ovl_whiteout(workdir, dentry);
558 upper = opaquedir; 552 err = PTR_ERR(whiteout);
559 err = -ESTALE; 553 if (IS_ERR(whiteout))
560 if (upper->d_parent != upperdir) 554 goto out_dput_upper;
561 goto kill_whiteout;
562 555
563 if (is_dir) 556 if (d_is_dir(upper))
564 flags |= RENAME_EXCHANGE; 557 flags = RENAME_EXCHANGE;
565 558
566 err = ovl_do_rename(wdir, whiteout, udir, upper, flags); 559 err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
567 if (err) 560 if (err)
568 goto kill_whiteout; 561 goto kill_whiteout;
562 if (flags)
563 ovl_cleanup(wdir, upper);
569 564
570 if (is_dir)
571 ovl_cleanup(wdir, upper);
572 }
573 ovl_dentry_version_inc(dentry->d_parent); 565 ovl_dentry_version_inc(dentry->d_parent);
574out_d_drop: 566out_d_drop:
575 d_drop(dentry); 567 d_drop(dentry);
576 dput(whiteout); 568 dput(whiteout);
569out_dput_upper:
570 dput(upper);
577out_unlock: 571out_unlock:
578 unlock_rename(workdir, upperdir); 572 unlock_rename(workdir, upperdir);
579out_dput: 573out_dput: