diff options
| author | Vladimir Davydov <vdavydov@parallels.com> | 2013-12-12 14:17:08 -0500 |
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2013-12-13 15:46:49 -0500 |
| commit | 10bf2f7e7db993273419ca9f51f5934e4cf71768 (patch) | |
| tree | 3d6f820b4409859fc97e4dfc8a3c90d936d27b24 | |
| parent | 0be8669dd530f60cf3f59f084518570c1dfb47ee (diff) | |
cgroup: fix fail path in cgroup_load_subsys()
Calling cgroup_unload_subsys() from cgroup_load_subsys() after
online_css() failure will result in a NULL ptr dereference on attempt to
offline_css(), because online_css() only assigns css to cgroup on
success. Let's fix that by skipping calls to offline_css() and
css_free() in cgroup_unload_subsys() if there is no css, and freeing css
in cgroup_load_subsys() on online_css() failure.
Signed-off-by: Vladimir Davydov <vdavydov@parallels.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
| -rw-r--r-- | kernel/cgroup.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 402f7aab8b2d..7030f04f2890 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
| @@ -4652,8 +4652,10 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) | |||
| 4652 | write_unlock(&css_set_lock); | 4652 | write_unlock(&css_set_lock); |
| 4653 | 4653 | ||
| 4654 | ret = online_css(css); | 4654 | ret = online_css(css); |
| 4655 | if (ret) | 4655 | if (ret) { |
| 4656 | ss->css_free(css); | ||
| 4656 | goto err_unload; | 4657 | goto err_unload; |
| 4658 | } | ||
| 4657 | 4659 | ||
| 4658 | /* success! */ | 4660 | /* success! */ |
| 4659 | mutex_unlock(&cgroup_root_mutex); | 4661 | mutex_unlock(&cgroup_root_mutex); |
| @@ -4680,6 +4682,7 @@ EXPORT_SYMBOL_GPL(cgroup_load_subsys); | |||
| 4680 | void cgroup_unload_subsys(struct cgroup_subsys *ss) | 4682 | void cgroup_unload_subsys(struct cgroup_subsys *ss) |
| 4681 | { | 4683 | { |
| 4682 | struct cgrp_cset_link *link; | 4684 | struct cgrp_cset_link *link; |
| 4685 | struct cgroup_subsys_state *css; | ||
| 4683 | 4686 | ||
| 4684 | BUG_ON(ss->module == NULL); | 4687 | BUG_ON(ss->module == NULL); |
| 4685 | 4688 | ||
| @@ -4693,7 +4696,9 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) | |||
| 4693 | mutex_lock(&cgroup_mutex); | 4696 | mutex_lock(&cgroup_mutex); |
| 4694 | mutex_lock(&cgroup_root_mutex); | 4697 | mutex_lock(&cgroup_root_mutex); |
| 4695 | 4698 | ||
| 4696 | offline_css(cgroup_css(cgroup_dummy_top, ss)); | 4699 | css = cgroup_css(cgroup_dummy_top, ss); |
| 4700 | if (css) | ||
| 4701 | offline_css(css); | ||
| 4697 | 4702 | ||
| 4698 | /* deassign the subsys_id */ | 4703 | /* deassign the subsys_id */ |
| 4699 | cgroup_subsys[ss->subsys_id] = NULL; | 4704 | cgroup_subsys[ss->subsys_id] = NULL; |
| @@ -4720,7 +4725,8 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) | |||
| 4720 | * need to free before marking as null because ss->css_free needs | 4725 | * need to free before marking as null because ss->css_free needs |
| 4721 | * the cgrp->subsys pointer to find their state. | 4726 | * the cgrp->subsys pointer to find their state. |
| 4722 | */ | 4727 | */ |
| 4723 | ss->css_free(cgroup_css(cgroup_dummy_top, ss)); | 4728 | if (css) |
| 4729 | ss->css_free(css); | ||
| 4724 | RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); | 4730 | RCU_INIT_POINTER(cgroup_dummy_top->subsys[ss->subsys_id], NULL); |
| 4725 | 4731 | ||
| 4726 | mutex_unlock(&cgroup_root_mutex); | 4732 | mutex_unlock(&cgroup_root_mutex); |
