Kdump kernel fails to load because of crash on mount of overlayfs: BUG: unable to handle kernel NULL pointer dereference at 0000000000000060 .... Call Trace: seq_path+0x64/0xb0 print_paths_option+0x79/0xa0 ovl_show_options+0x3a/0x320 show_mountinfo+0x1ee/0x290 seq_read+0x2f8/0x400 vfs_read+0x9d/0x150 ksys_read+0x4f/0xb0 do_syscall_64+0x5b/0x1a0
This is cause by OOB access of ofs->lowerpaths. We transfer to print_paths_option() ofs->numlayer as size of ->lowerpaths array, but it's not. We could probably pass 'ofs->numlayer - 1' as number of lower layers/path, but it's better to remove lowerpaths completely. All necessary information already contained in 'struct ovl_entry'. Use it to print paths instead. Fixes: 17fc61697f73 ("overlayfs: add dynamic path resolving in mount options") Fixes: 2191d729083d ("overlayfs: add mnt_id paths options") https://jira.sw.ru/browse/PSBM-123508 Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com> --- fs/overlayfs/overlayfs.h | 4 ++-- fs/overlayfs/ovl_entry.h | 1 - fs/overlayfs/super.c | 30 ++++++++++++++---------------- fs/overlayfs/util.c | 13 +++++++++---- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 7e103d002819..a708ebbd2e21 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -313,10 +313,10 @@ ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value, void print_path_option(struct seq_file *m, const char *name, struct path *path); void print_paths_option(struct seq_file *m, const char *name, - struct path *paths, unsigned int num); + struct ovl_path *paths, unsigned int num); void print_mnt_id_option(struct seq_file *m, const char *name, struct path *path); void print_mnt_ids_option(struct seq_file *m, const char *name, - struct path *paths, unsigned int num); + struct ovl_path *paths, unsigned int num); static inline bool ovl_is_impuredir(struct dentry *dentry) { diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index ea1906448ec5..4e7272c7e4dd 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -54,7 +54,6 @@ struct ovl_fs { unsigned int numlayer; /* Number of unique fs among layers including upper fs */ unsigned int numfs; - struct path *lowerpaths; const struct ovl_layer *layers; struct ovl_sb *fs; /* workbasepath is the path at workdir= mount option */ diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 3755f280036f..069d365a609d 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -241,11 +241,6 @@ static void ovl_free_fs(struct ovl_fs *ofs) ovl_inuse_unlock(ofs->upper_mnt->mnt_root); mntput(ofs->upper_mnt); path_put(&ofs->upperpath); - if (ofs->lowerpaths) { - for (i = 0; i < ofs->numlayer; i++) - path_put(&ofs->lowerpaths[i]); - kfree(ofs->lowerpaths); - } for (i = 1; i < ofs->numlayer; i++) { iput(ofs->layers[i].trap); mntput(ofs->layers[i].mnt); @@ -359,9 +354,10 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) { struct super_block *sb = dentry->d_sb; struct ovl_fs *ofs = sb->s_fs_info; + struct ovl_entry *oe = OVL_E(dentry); if (ovl_dyn_path_opts) { - print_paths_option(m, "lowerdir", ofs->lowerpaths, ofs->numlayer); + print_paths_option(m, "lowerdir", oe->lowerstack, oe->numlower); if (ofs->config.upperdir) { print_path_option(m, "upperdir", &ofs->upperpath); print_path_option(m, "workdir", &ofs->workbasepath); @@ -375,7 +371,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) } if (ovl_mnt_id_path_opts) { - print_mnt_ids_option(m, "lowerdir_mnt_id", ofs->lowerpaths, ofs->numlayer); + print_mnt_ids_option(m, "lowerdir_mnt_id", oe->lowerstack, oe->numlower); + /* * We don't need to show mnt_id for workdir because it * on the same mount as upperdir. @@ -1625,6 +1622,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, { int err; char *lowertmp, *lower; + struct path *stack = NULL; unsigned int stacklen, numlower = 0, i; struct ovl_entry *oe; @@ -1649,14 +1647,14 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, } err = -ENOMEM; - ofs->lowerpaths = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL); - if (!ofs->lowerpaths) + stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL); + if (!stack) goto out_err; err = -EINVAL; lower = lowertmp; for (numlower = 0; numlower < stacklen; numlower++) { - err = ovl_lower_dir(lower, &ofs->lowerpaths[numlower], ofs, + err = ovl_lower_dir(lower, &stack[numlower], ofs, &sb->s_stack_depth); if (err) goto out_err; @@ -1671,7 +1669,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, goto out_err; } - err = ovl_get_layers(sb, ofs, ofs->lowerpaths, numlower); + err = ovl_get_layers(sb, ofs, stack, numlower); if (err) goto out_err; @@ -1681,20 +1679,20 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, goto out_err; for (i = 0; i < numlower; i++) { - oe->lowerstack[i].dentry = dget(ofs->lowerpaths[i].dentry); + oe->lowerstack[i].dentry = dget(stack[i].dentry); oe->lowerstack[i].layer = &ofs->layers[i+1]; } out: + for (i = 0; i < numlower; i++) + path_put(&stack[i]); + kfree(stack); + kfree(lowertmp); return oe; out_err: - for (i = 0; i < numlower; i++) - path_put_init(&ofs->lowerpaths[i]); - kfree(ofs->lowerpaths); - ofs->lowerpaths = NULL; oe = ERR_PTR(err); goto out; } diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 00f6c1483691..326e308039fb 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -933,16 +933,21 @@ void print_path_option(struct seq_file *m, const char *name, struct path *path) } void print_paths_option(struct seq_file *m, const char *name, - struct path *paths, unsigned int num) + struct ovl_path *paths, unsigned int num) { int i; seq_show_option(m, name, ""); for (i = 0; i < num; i++) { + struct path tmp_path; + + tmp_path.mnt = paths[i].layer->mnt; + tmp_path.dentry = paths[i].dentry; + if (i) seq_putc(m, ':'); - seq_path(m, &paths[i], ", \t\n\\"); + seq_path(m, &tmp_path, ", \t\n\\"); } } @@ -953,7 +958,7 @@ void print_mnt_id_option(struct seq_file *m, const char *name, struct path *path } void print_mnt_ids_option(struct seq_file *m, const char *name, - struct path *paths, unsigned int num) + struct ovl_path *paths, unsigned int num) { int i; @@ -962,6 +967,6 @@ void print_mnt_ids_option(struct seq_file *m, const char *name, for (i = 0; i < num; i++) { if (i) seq_putc(m, ':'); - seq_printf(m, "%i", real_mount(paths[i].mnt)->mnt_id); + seq_printf(m, "%i", real_mount(paths[i].layer->mnt)->mnt_id); } } -- 2.26.2 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel