aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Davydov <vdavydov@parallels.com>2013-12-12 14:17:08 -0500
committerTejun Heo <tj@kernel.org>2013-12-13 15:46:49 -0500
commit10bf2f7e7db993273419ca9f51f5934e4cf71768 (patch)
tree3d6f820b4409859fc97e4dfc8a3c90d936d27b24
parent0be8669dd530f60cf3f59f084518570c1dfb47ee (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.c12
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);
4680void cgroup_unload_subsys(struct cgroup_subsys *ss) 4682void 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);