aboutsummaryrefslogtreecommitdiffstats
path: root/fs/overlayfs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-03-21 12:31:44 -0400
committerMiklos Szeredi <miklos@szeredi.hu>2016-03-21 12:31:44 -0400
commit11f3710417d026ea2f4fcf362d866342c5274185 (patch)
tree9f0904f868dd155bf00b0b10caf264d2a4065355 /fs/overlayfs
parent3c2de27d793bf55167804fc47954711e94f27be7 (diff)
ovl: verify upper dentry before unlink and rename
Unlink and rename in overlayfs checked the upper dentry for staleness by verifying upper->d_parent against upperdir. However the dentry can go stale also by being unhashed, for example. Expand the verification to actually look up the name again (under parent lock) and check if it matches the upper dentry. This matches what the VFS does before passing the dentry to filesytem's unlink/rename methods, which excludes any inconsistency caused by overlayfs. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/overlayfs')
-rw-r--r--fs/overlayfs/dir.c59
1 files changed, 38 insertions, 21 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 52f6de5d40a9..bc1758a160f6 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -596,21 +596,25 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
596{ 596{
597 struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); 597 struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
598 struct inode *dir = upperdir->d_inode; 598 struct inode *dir = upperdir->d_inode;
599 struct dentry *upper = ovl_dentry_upper(dentry); 599 struct dentry *upper;
600 int err; 600 int err;
601 601
602 inode_lock_nested(dir, I_MUTEX_PARENT); 602 inode_lock_nested(dir, I_MUTEX_PARENT);
603 upper = lookup_one_len(dentry->d_name.name, upperdir,
604 dentry->d_name.len);
605 err = PTR_ERR(upper);
606 if (IS_ERR(upper))
607 goto out_unlock;
608
603 err = -ESTALE; 609 err = -ESTALE;
604 if (upper->d_parent == upperdir) { 610 if (upper == ovl_dentry_upper(dentry)) {
605 /* Don't let d_delete() think it can reset d_inode */
606 dget(upper);
607 if (is_dir) 611 if (is_dir)
608 err = vfs_rmdir(dir, upper); 612 err = vfs_rmdir(dir, upper);
609 else 613 else
610 err = vfs_unlink(dir, upper, NULL); 614 err = vfs_unlink(dir, upper, NULL);
611 dput(upper);
612 ovl_dentry_version_inc(dentry->d_parent); 615 ovl_dentry_version_inc(dentry->d_parent);
613 } 616 }
617 dput(upper);
614 618
615 /* 619 /*
616 * Keeping this dentry hashed would mean having to release 620 * Keeping this dentry hashed would mean having to release
@@ -620,6 +624,7 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
620 */ 624 */
621 if (!err) 625 if (!err)
622 d_drop(dentry); 626 d_drop(dentry);
627out_unlock:
623 inode_unlock(dir); 628 inode_unlock(dir);
624 629
625 return err; 630 return err;
@@ -840,29 +845,39 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
840 845
841 trap = lock_rename(new_upperdir, old_upperdir); 846 trap = lock_rename(new_upperdir, old_upperdir);
842 847
843 olddentry = ovl_dentry_upper(old); 848
844 newdentry = ovl_dentry_upper(new); 849 olddentry = lookup_one_len(old->d_name.name, old_upperdir,
845 if (newdentry) { 850 old->d_name.len);
851 err = PTR_ERR(olddentry);
852 if (IS_ERR(olddentry))
853 goto out_unlock;
854
855 err = -ESTALE;
856 if (olddentry != ovl_dentry_upper(old))
857 goto out_dput_old;
858
859 newdentry = lookup_one_len(new->d_name.name, new_upperdir,
860 new->d_name.len);
861 err = PTR_ERR(newdentry);
862 if (IS_ERR(newdentry))
863 goto out_dput_old;
864
865 err = -ESTALE;
866 if (ovl_dentry_upper(new)) {
846 if (opaquedir) { 867 if (opaquedir) {
847 newdentry = opaquedir; 868 if (newdentry != opaquedir)
848 opaquedir = NULL; 869 goto out_dput;
849 } else { 870 } else {
850 dget(newdentry); 871 if (newdentry != ovl_dentry_upper(new))
872 goto out_dput;
851 } 873 }
852 } else { 874 } else {
853 new_create = true; 875 new_create = true;
854 newdentry = lookup_one_len(new->d_name.name, new_upperdir, 876 if (!d_is_negative(newdentry) &&
855 new->d_name.len); 877 (!new_opaque || !ovl_is_whiteout(newdentry)))
856 err = PTR_ERR(newdentry); 878 goto out_dput;
857 if (IS_ERR(newdentry))
858 goto out_unlock;
859 } 879 }
860 880
861 err = -ESTALE;
862 if (olddentry->d_parent != old_upperdir)
863 goto out_dput;
864 if (newdentry->d_parent != new_upperdir)
865 goto out_dput;
866 if (olddentry == trap) 881 if (olddentry == trap)
867 goto out_dput; 882 goto out_dput;
868 if (newdentry == trap) 883 if (newdentry == trap)
@@ -925,6 +940,8 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
925 940
926out_dput: 941out_dput:
927 dput(newdentry); 942 dput(newdentry);
943out_dput_old:
944 dput(olddentry);
928out_unlock: 945out_unlock:
929 unlock_rename(new_upperdir, old_upperdir); 946 unlock_rename(new_upperdir, old_upperdir);
930out_revert_creds: 947out_revert_creds: