ovl: fix wrong lowerdir number check for parameter Opt_lowerdir

JIRA: https://issues.redhat.com/browse/RHEL-83562

commit ca76ac36bb6068866feca185045e7edf2a8f392f
Author: Zhihao Cheng <chengzhihao1@huawei.com>
Date:   Fri Jul 5 09:15:09 2024 +0800

    ovl: fix wrong lowerdir number check for parameter Opt_lowerdir

    The max count of lowerdir is OVL_MAX_STACK[500], which is broken by
    commit 37f32f526438("ovl: fix memory leak in ovl_parse_param()") for
    parameter Opt_lowerdir. Since commit 819829f0319a("ovl: refactor layer
    parsing helpers") and commit 24e16e385f22("ovl: add support for
    appending lowerdirs one by one") added check ovl_mount_dir_check() in
    function ovl_parse_param_lowerdir(), the 'ctx->nr' should be smaller
    than OVL_MAX_STACK, after commit 37f32f526438("ovl: fix memory leak in
    ovl_parse_param()") is applied, the 'ctx->nr' is updated before the
    check ovl_mount_dir_check(), which leads the max count of lowerdir
    to become 499 for parameter Opt_lowerdir.
    Fix it by replacing lower layers parsing code with the existing helper
    function ovl_parse_layer().

    Fixes: 37f32f526438 ("ovl: fix memory leak in ovl_parse_param()")
    Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
    Link: https://lore.kernel.org/r/20240705011510.794025-3-chengzhihao1@huawei.com
    Reviewed-by: Amir Goldstein <amir73il@gmail.com>
    Signed-off-by: Christian Brauner <brauner@kernel.org>

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Miklos Szeredi 2025-03-14 16:48:37 +01:00
parent d503539e05
commit a44831ea14
1 changed files with 7 additions and 33 deletions

View File

@ -349,6 +349,8 @@ static void ovl_add_layer(struct fs_context *fc, enum ovl_opt layer,
case Opt_datadir_add:
ctx->nr_data++;
fallthrough;
case Opt_lowerdir:
fallthrough;
case Opt_lowerdir_add:
WARN_ON(ctx->nr >= ctx->capacity);
l = &ctx->lower[ctx->nr++];
@ -371,7 +373,7 @@ static int ovl_parse_layer(struct fs_context *fc, const char *layer_name, enum o
if (!name)
return -ENOMEM;
if (upper)
if (upper || layer == Opt_lowerdir)
err = ovl_mount_dir(name, &path);
else
err = ovl_mount_dir_noesc(name, &path);
@ -427,7 +429,6 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
{
int err;
struct ovl_fs_context *ctx = fc->fs_private;
struct ovl_fs_context_layer *l;
char *dup = NULL, *iter;
ssize_t nr_lower, nr;
bool data_layer = false;
@ -467,35 +468,11 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
goto out_err;
}
if (nr_lower > ctx->capacity) {
err = -ENOMEM;
l = krealloc_array(ctx->lower, nr_lower, sizeof(*ctx->lower),
GFP_KERNEL_ACCOUNT);
if (!l)
goto out_err;
ctx->lower = l;
ctx->capacity = nr_lower;
}
iter = dup;
l = ctx->lower;
for (nr = 0; nr < nr_lower; nr++, l++) {
ctx->nr++;
memset(l, 0, sizeof(*l));
err = ovl_mount_dir(iter, &l->path);
for (nr = 0; nr < nr_lower; nr++) {
err = ovl_parse_layer(fc, iter, Opt_lowerdir);
if (err)
goto out_put;
err = ovl_mount_dir_check(fc, &l->path, Opt_lowerdir, iter, false);
if (err)
goto out_put;
err = -ENOMEM;
l->name = kstrdup(iter, GFP_KERNEL_ACCOUNT);
if (!l->name)
goto out_put;
goto out_err;
if (data_layer)
ctx->nr_data++;
@ -513,7 +490,7 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
*/
if (ctx->nr_data > 0) {
pr_err("regular lower layers cannot follow data lower layers");
goto out_put;
goto out_err;
}
data_layer = false;
@ -527,9 +504,6 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
kfree(dup);
return 0;
out_put:
ovl_reset_lowerdirs(ctx);
out_err:
kfree(dup);