aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-11-29 04:20:24 -0500
committerMiklos Szeredi <mszeredi@redhat.com>2016-11-29 04:20:24 -0500
commitc4fcfc1619ea43a8a89ad2f83ff23905eee088bd (patch)
treeabf4c9aeaa627cb0c8b56cd06e0325570f055031 /fs
parentbc33b0ca11e3df467777a4fa7639ba488c9d4911 (diff)
ovl: fix d_real() for stacked fs
Handling of recursion in d_real() is completely broken. Recursion is only done in the 'inode != NULL' case. But when opening the file we have 'inode == NULL' hence d_real() will return an overlay dentry. This won't work since overlayfs doesn't define its own file operations, so all file ops will fail. Fix by doing the recursion first and the check against the inode second. Bash script to reproduce the issue written by Quentin: - 8< - - - - - 8< - - - - - 8< - - - - - 8< - - - - tmpdir=$(mktemp -d) pushd ${tmpdir} mkdir -p {upper,lower,work} echo -n 'rocks' > lower/ksplice mount -t overlay level_zero upper -o lowerdir=lower,upperdir=upper,workdir=work cat upper/ksplice tmpdir2=$(mktemp -d) pushd ${tmpdir2} mkdir -p {upper,work} mount -t overlay level_one upper -o lowerdir=${tmpdir}/upper,upperdir=upper,workdir=work ls -l upper/ksplice cat upper/ksplice - 8< - - - - - 8< - - - - - 8< - - - - - 8< - - - - Reported-by: Quentin Casasnovas <quentin.casasnovas@oracle.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Fixes: 2d902671ce1c ("vfs: merge .d_select_inode() into .d_real()") Cc: <stable@vger.kernel.org> # v4.8+
Diffstat (limited to 'fs')
-rw-r--r--fs/overlayfs/super.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index edd46a0e951d..0e100856c7b8 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -328,11 +328,11 @@ static struct dentry *ovl_d_real(struct dentry *dentry,
328 if (!real) 328 if (!real)
329 goto bug; 329 goto bug;
330 330
331 /* Handle recursion */
332 real = d_real(real, inode, open_flags);
333
331 if (!inode || inode == d_inode(real)) 334 if (!inode || inode == d_inode(real))
332 return real; 335 return real;
333
334 /* Handle recursion */
335 return d_real(real, inode, open_flags);
336bug: 336bug:
337 WARN(1, "ovl_d_real(%pd4, %s:%lu): real dentry not found\n", dentry, 337 WARN(1, "ovl_d_real(%pd4, %s:%lu): real dentry not found\n", dentry,
338 inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); 338 inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0);