Skip to content

Commit dbf72a4

Browse files
Miklos Szeredigregkh
authored andcommitted
ovl: verify upper dentry before unlink and rename
commit 11f3710417d026ea2f4fcf362d866342c5274185 upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 38da63e commit dbf72a4

1 file changed

Lines changed: 38 additions & 21 deletions

File tree

fs/overlayfs/dir.c

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -590,21 +590,25 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
590590
{
591591
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
592592
struct inode *dir = upperdir->d_inode;
593-
struct dentry *upper = ovl_dentry_upper(dentry);
593+
struct dentry *upper;
594594
int err;
595595

596596
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
597+
upper = lookup_one_len(dentry->d_name.name, upperdir,
598+
dentry->d_name.len);
599+
err = PTR_ERR(upper);
600+
if (IS_ERR(upper))
601+
goto out_unlock;
602+
597603
err = -ESTALE;
598-
if (upper->d_parent == upperdir) {
599-
/* Don't let d_delete() think it can reset d_inode */
600-
dget(upper);
604+
if (upper == ovl_dentry_upper(dentry)) {
601605
if (is_dir)
602606
err = vfs_rmdir(dir, upper);
603607
else
604608
err = vfs_unlink(dir, upper, NULL);
605-
dput(upper);
606609
ovl_dentry_version_inc(dentry->d_parent);
607610
}
611+
dput(upper);
608612

609613
/*
610614
* Keeping this dentry hashed would mean having to release
@@ -614,6 +618,7 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
614618
*/
615619
if (!err)
616620
d_drop(dentry);
621+
out_unlock:
617622
mutex_unlock(&dir->i_mutex);
618623

619624
return err;
@@ -834,29 +839,39 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
834839

835840
trap = lock_rename(new_upperdir, old_upperdir);
836841

837-
olddentry = ovl_dentry_upper(old);
838-
newdentry = ovl_dentry_upper(new);
839-
if (newdentry) {
842+
843+
olddentry = lookup_one_len(old->d_name.name, old_upperdir,
844+
old->d_name.len);
845+
err = PTR_ERR(olddentry);
846+
if (IS_ERR(olddentry))
847+
goto out_unlock;
848+
849+
err = -ESTALE;
850+
if (olddentry != ovl_dentry_upper(old))
851+
goto out_dput_old;
852+
853+
newdentry = lookup_one_len(new->d_name.name, new_upperdir,
854+
new->d_name.len);
855+
err = PTR_ERR(newdentry);
856+
if (IS_ERR(newdentry))
857+
goto out_dput_old;
858+
859+
err = -ESTALE;
860+
if (ovl_dentry_upper(new)) {
840861
if (opaquedir) {
841-
newdentry = opaquedir;
842-
opaquedir = NULL;
862+
if (newdentry != opaquedir)
863+
goto out_dput;
843864
} else {
844-
dget(newdentry);
865+
if (newdentry != ovl_dentry_upper(new))
866+
goto out_dput;
845867
}
846868
} else {
847869
new_create = true;
848-
newdentry = lookup_one_len(new->d_name.name, new_upperdir,
849-
new->d_name.len);
850-
err = PTR_ERR(newdentry);
851-
if (IS_ERR(newdentry))
852-
goto out_unlock;
870+
if (!d_is_negative(newdentry) &&
871+
(!new_opaque || !ovl_is_whiteout(newdentry)))
872+
goto out_dput;
853873
}
854874

855-
err = -ESTALE;
856-
if (olddentry->d_parent != old_upperdir)
857-
goto out_dput;
858-
if (newdentry->d_parent != new_upperdir)
859-
goto out_dput;
860875
if (olddentry == trap)
861876
goto out_dput;
862877
if (newdentry == trap)
@@ -919,6 +934,8 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
919934

920935
out_dput:
921936
dput(newdentry);
937+
out_dput_old:
938+
dput(olddentry);
922939
out_unlock:
923940
unlock_rename(new_upperdir, old_upperdir);
924941
out_revert_creds:

0 commit comments

Comments
 (0)