Commit 67810693 authored by Amir Goldstein's avatar Amir Goldstein Committed by Miklos Szeredi

ovl: fix wrong use of impure dir cache in ovl_iterate()

Only upper dir can be impure, but if we are in the middle of
iterating a lower real dir, dir could be copied up and marked
impure. We only want the impure cache if we started iterating
a real upper dir to begin with.

Aditya Kali reported that the following reproducer hits the
WARN_ON(!cache->refcount) in ovl_get_cache():

 docker run --rm drupal:8.5.4-fpm-alpine \
    sh -c 'cd /var/www/html/vendor/symfony && \
           chown -R www-data:www-data . && ls -l .'
Reported-by: default avatarAditya Kali <adityakali@google.com>
Tested-by: default avatarAditya Kali <adityakali@google.com>
Fixes: 4edb83bb ('ovl: constant d_ino for non-merge dirs')
Cc: <stable@vger.kernel.org> # v4.14
Signed-off-by: default avatarAmir Goldstein <amir73il@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent ce397d21
...@@ -668,6 +668,21 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name, ...@@ -668,6 +668,21 @@ static int ovl_fill_real(struct dir_context *ctx, const char *name,
return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type); return orig_ctx->actor(orig_ctx, name, namelen, offset, ino, d_type);
} }
static bool ovl_is_impure_dir(struct file *file)
{
struct ovl_dir_file *od = file->private_data;
struct inode *dir = d_inode(file->f_path.dentry);
/*
* Only upper dir can be impure, but if we are in the middle of
* iterating a lower real dir, dir could be copied up and marked
* impure. We only want the impure cache if we started iterating
* a real upper dir to begin with.
*/
return od->is_upper && ovl_test_flag(OVL_IMPURE, dir);
}
static int ovl_iterate_real(struct file *file, struct dir_context *ctx) static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
{ {
int err; int err;
...@@ -696,7 +711,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx) ...@@ -696,7 +711,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
rdt.parent_ino = stat.ino; rdt.parent_ino = stat.ino;
} }
if (ovl_test_flag(OVL_IMPURE, d_inode(dir))) { if (ovl_is_impure_dir(file)) {
rdt.cache = ovl_cache_get_impure(&file->f_path); rdt.cache = ovl_cache_get_impure(&file->f_path);
if (IS_ERR(rdt.cache)) if (IS_ERR(rdt.cache))
return PTR_ERR(rdt.cache); return PTR_ERR(rdt.cache);
...@@ -727,7 +742,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx) ...@@ -727,7 +742,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
*/ */
if (ovl_xino_bits(dentry->d_sb) || if (ovl_xino_bits(dentry->d_sb) ||
(ovl_same_sb(dentry->d_sb) && (ovl_same_sb(dentry->d_sb) &&
(ovl_test_flag(OVL_IMPURE, d_inode(dentry)) || (ovl_is_impure_dir(file) ||
OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) { OVL_TYPE_MERGE(ovl_path_type(dentry->d_parent))))) {
return ovl_iterate_real(file, ctx); return ovl_iterate_real(file, ctx);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment