ovl: fix wrong use of impure dir cache in ovl_iterate()
commit6781069307
upstream. 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: Aditya Kali <adityakali@google.com> Tested-by: Aditya Kali <adityakali@google.com> Fixes:4edb83bb10
('ovl: constant d_ino for non-merge dirs') Cc: <stable@vger.kernel.org> # v4.14 Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Родитель
aa9ceea207
Коммит
8840ca570f
|
@ -623,6 +623,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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
|
@ -646,7 +661,7 @@ static int ovl_iterate_real(struct file *file, struct dir_context *ctx)
|
|||
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);
|
||||
if (IS_ERR(rdt.cache))
|
||||
return PTR_ERR(rdt.cache);
|
||||
|
@ -676,7 +691,7 @@ static int ovl_iterate(struct file *file, struct dir_context *ctx)
|
|||
* entries.
|
||||
*/
|
||||
if (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)))) {
|
||||
return ovl_iterate_real(file, ctx);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче