[Devel] [PATCH v2 v2] fs/ovelayfs: Fix crash on overlayfs mount
Kdump kernel fails to load because of crash on mount of overlayfs: BUG: unable to handle kernel NULL pointer dereference at 0060 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. The correct number of lowerpaths elements is ->numlower in 'struct ovl_entry'. So move lowerpaths there and use oe->numlower as array size. 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 --- fs/overlayfs/ovl_entry.h | 2 +- fs/overlayfs/super.c | 37 - 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index ea1906448ec5..2315089a0211 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 */ @@ -98,6 +97,7 @@ struct ovl_entry { struct rcu_head rcu; }; unsigned numlower; + struct path *lowerpaths; struct ovl_path lowerstack[]; }; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 3755f280036f..fb419617564c 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -70,8 +70,12 @@ static void ovl_entry_stack_free(struct ovl_entry *oe) { unsigned int i; - for (i = 0; i < oe->numlower; i++) + for (i = 0; i < oe->numlower; i++) { dput(oe->lowerstack[i].dentry); + if (oe->lowerpaths) + path_put(&oe->lowerpaths[i]); + } + kfree(oe->lowerpaths); } static bool ovl_metacopy_def = IS_ENABLED(CONFIG_OVERLAY_FS_METACOPY); @@ -241,11 +245,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 +358,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->lowerpaths, oe->numlower); if (ofs->config.upperdir) { print_path_option(m, "upperdir", &ofs->upperpath); print_path_option(m, "workdir", &ofs->workbasepath); @@ -375,7 +375,7 @@ 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->lowerpaths, oe->numlower); /* * We don't need to show mnt_id for workdir because it * on the same mount as upperdir. @@ -1626,6 +1626,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb, int err; char *lowertmp, *lower; unsigned int stacklen, numlower = 0, i; + struct path *stack = NULL; struct ovl_entry *oe; err = -ENOMEM; @@ -1649,14 +1650,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 +1672,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *
[Devel] [VZ8 PATCH 1/3] ve/cgroup: unmark ve-root cgroups at container stop
fixes: 915a1130c7ee4ffb6de3f69a5bd98c5ee42a723f Signed-off-by: Valeriy Vdovin Reviewed-by: Kirill Tkhai Cherry-picked from 5dceccf5dd794673ebb1b0e6840d96aa654ec33e) Signed-off-by: Valeriy Vdovin --- include/linux/cgroup.h | 1 + kernel/cgroup/cgroup.c | 24 kernel/ve/ve.c | 3 +++ 3 files changed, 28 insertions(+) diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 4f0dd51338bf..c0a42c3d43fa 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -867,6 +867,7 @@ int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, #ifdef CONFIG_VE extern void cgroup_mark_ve_root(struct ve_struct *ve); +void cgroup_unmark_ve_roots(struct ve_struct *ve); #endif #else /* !CONFIG_CGROUPS */ diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 0335a07f64e6..4488df184235 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -1908,6 +1908,30 @@ void cgroup_mark_ve_root(struct ve_struct *ve) spin_unlock_irq(&css_set_lock); } +void cgroup_unmark_ve_roots(struct ve_struct *ve) +{ + struct cgrp_cset_link *link; + struct css_set *cset; + struct cgroup *cgrp; + + spin_lock_irq(&css_set_lock); + + rcu_read_lock(); + cset = rcu_dereference(ve->ve_ns)->cgroup_ns->root_cset; + if (WARN_ON(!cset)) + goto unlock; + + list_for_each_entry(link, &cset->cgrp_links, cgrp_link) { + cgrp = link->cgrp; + clear_bit(CGRP_VE_ROOT, &cgrp->flags); + } + link_ve_root_cpu_cgroup(cset->subsys[cpu_cgrp_id]); +unlock: + rcu_read_unlock(); + + spin_unlock_irq(&css_set_lock); +} + struct cgroup *cgroup_get_ve_root1(struct cgroup *cgrp) { struct cgroup *ve_root = NULL; diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c index 3f53641455ad..b922653acf49 100644 --- a/kernel/ve/ve.c +++ b/kernel/ve/ve.c @@ -519,6 +519,9 @@ void ve_exit_ns(struct pid_namespace *pid_ns) */ if (!ve_ns || ve_ns->pid_ns_for_children != pid_ns) goto unlock; + + cgroup_unmark_ve_roots(ve); + /* * At this point all userspace tasks in container are dead. */ -- 2.27.0 ___ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel
[Devel] [VZ8 PATCH 3/3] cgroup: port CGROUP_REMOVED flag from vz7
The flag will be used in subsequent porting patches for release_agent functionality Signed-off-by: Valeriy Vdovin --- include/linux/cgroup-defs.h | 2 ++ include/linux/cgroup.h | 5 + kernel/cgroup/cgroup.c | 1 + 3 files changed, 8 insertions(+) diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index a3b309ab1a90..5ee5f10e3de7 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -57,6 +57,8 @@ enum { /* bits in struct cgroup flags field */ enum { + /* Control Cgroup is dead */ + CGRP_REMOVED, /* Control Group requires release notifications to userspace */ CGRP_NOTIFY_ON_RELEASE, /* diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index c0a42c3d43fa..dfd9460986ee 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -922,6 +922,11 @@ static inline bool cgroup_task_frozen(struct task_struct *task) return task->frozen; } +static inline int cgroup_is_removed(const struct cgroup *cgrp) +{ + return test_bit(CGRP_REMOVED, &cgrp->flags); +} + #else /* !CONFIG_CGROUPS */ static inline void cgroup_enter_frozen(void) { } diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 797a3971ab46..447c8f003496 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -5562,6 +5562,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) tcgrp->freezer.nr_frozen_descendants--; } spin_unlock_irq(&css_set_lock); + set_bit(CGRP_REMOVED, &cgrp->flags); cgroup1_check_for_release(parent); -- 2.27.0 ___ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel
[Devel] [VZ8 PATCH 2/3] cgroup/cfs: added 'activate' option to cgroup_add_file
In kernfs files get created in 'deactivated' state, which means they are not visible. Add option to activate the file after creation immediately making it visible in the parent directory. Will be used in later patches. Signed-off-by: Valeriy Vdovin --- kernel/cgroup/cgroup.c | 6 -- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index 4488df184235..797a3971ab46 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -3824,7 +3824,7 @@ static void cgroup_file_notify_timer(struct timer_list *timer) } static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp, - struct cftype *cft) + struct cftype *cft, bool activate) { char name[CGROUP_FILE_NAME_MAX]; struct kernfs_node *kn; @@ -3866,6 +3866,8 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp, if (IS_ERR(kn_link)) return PTR_ERR(kn_link); } + if (activate) + kernfs_activate(kn); return 0; } @@ -3903,7 +3905,7 @@ static int cgroup_addrm_files(struct cgroup_subsys_state *css, if ((cft->flags & CFTYPE_DEBUG) && !cgroup_debug) continue; if (is_add) { - ret = cgroup_add_file(css, cgrp, cft); + ret = cgroup_add_file(css, cgrp, cft, false); if (ret) { pr_warn("%s: failed to add %s, err=%d\n", __func__, cft->name, ret); -- 2.27.0 ___ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel