From: Zhihao Cheng chengzhihao1@huawei.com
maillist inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IAGHK5 CVE: NA
Reference: https://lore.kernel.org/linux-unionfs/20240705011510.794025-1-chengzhihao1@h...
--------------------------------
The max count of lowerdir is OVL_MAX_STACK[500], which is broken by commit 1db49495be1c("ovl: fix memory leak in ovl_parse_param()") for parameter Opt_lowerdir. Since commit ac1365ec2ab5("ovl: refactor layer parsing helpers") and commit 7341cd58f28e("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 1db49495be1c("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: 1db49495be1c ("ovl: fix memory leak in ovl_parse_param()") Signed-off-by: Christian Brauner brauner@kernel.org Signed-off-by: Zhihao Cheng chengzhihao1@huawei.com Reviewed-by: Amir Goldstein amir73il@gmail.com Signed-off-by: Zhihao Cheng chengzhihao@huaweicloud.com --- fs/overlayfs/params.c | 40 +++++++--------------------------------- 1 file changed, 7 insertions(+), 33 deletions(-)
diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c index 17b9c1838182..39919a10ce1c 100644 --- a/fs/overlayfs/params.c +++ b/fs/overlayfs/params.c @@ -357,6 +357,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++]; @@ -379,7 +381,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); @@ -435,7 +437,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; @@ -475,35 +476,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++; @@ -521,7 +498,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; @@ -535,9 +512,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);