aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLi Zefan <lizefan@huawei.com>2013-03-04 21:57:03 -0500
committerTejun Heo <tj@kernel.org>2013-03-05 12:33:25 -0500
commit7d8e0bf56a66bab08d2f316dd87e56c08cecb899 (patch)
treebe35c2daec953f0c98241c16311879dd45bc4859
parentf50daa704f36a6544a902c52b6cf37b0493dfc5d (diff)
cgroup: avoid accessing modular cgroup subsys structure without locking
subsys[i] is set to NULL in cgroup_unload_subsys() at modular unload, and that's protected by cgroup_mutex, and then the memory *subsys[i] resides will be freed. So this is unsafe without any locking: if (!ss || ss->module) ... v2: - add a comment for enum cgroup_subsys_id - simplify the comment in cgroup_exit() Signed-off-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--include/linux/cgroup.h17
-rw-r--r--kernel/cgroup.c28
2 files changed, 28 insertions, 17 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 75c6ec1ba1ba..5f76829dd75e 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -44,14 +44,25 @@ extern void cgroup_unload_subsys(struct cgroup_subsys *ss);
44 44
45extern const struct file_operations proc_cgroup_operations; 45extern const struct file_operations proc_cgroup_operations;
46 46
47/* Define the enumeration of all builtin cgroup subsystems */ 47/*
48 * Define the enumeration of all cgroup subsystems.
49 *
50 * We define ids for builtin subsystems and then modular ones.
51 */
48#define SUBSYS(_x) _x ## _subsys_id, 52#define SUBSYS(_x) _x ## _subsys_id,
49#define IS_SUBSYS_ENABLED(option) IS_ENABLED(option)
50enum cgroup_subsys_id { 53enum cgroup_subsys_id {
54#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
55#include <linux/cgroup_subsys.h>
56#undef IS_SUBSYS_ENABLED
57 CGROUP_BUILTIN_SUBSYS_COUNT,
58
59 __CGROUP_SUBSYS_TEMP_PLACEHOLDER = CGROUP_BUILTIN_SUBSYS_COUNT - 1,
60
61#define IS_SUBSYS_ENABLED(option) IS_MODULE(option)
51#include <linux/cgroup_subsys.h> 62#include <linux/cgroup_subsys.h>
63#undef IS_SUBSYS_ENABLED
52 CGROUP_SUBSYS_COUNT, 64 CGROUP_SUBSYS_COUNT,
53}; 65};
54#undef IS_SUBSYS_ENABLED
55#undef SUBSYS 66#undef SUBSYS
56 67
57/* Per-subsystem/per-cgroup state maintained by the system. */ 68/* Per-subsystem/per-cgroup state maintained by the system. */
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 9df799d5d31c..7a6c4c72ca55 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4940,17 +4940,17 @@ void cgroup_post_fork(struct task_struct *child)
4940 * and addition to css_set. 4940 * and addition to css_set.
4941 */ 4941 */
4942 if (need_forkexit_callback) { 4942 if (need_forkexit_callback) {
4943 for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { 4943 /*
4944 * fork/exit callbacks are supported only for builtin
4945 * subsystems, and the builtin section of the subsys
4946 * array is immutable, so we don't need to lock the
4947 * subsys array here. On the other hand, modular section
4948 * of the array can be freed at module unload, so we
4949 * can't touch that.
4950 */
4951 for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
4944 struct cgroup_subsys *ss = subsys[i]; 4952 struct cgroup_subsys *ss = subsys[i];
4945 4953
4946 /*
4947 * fork/exit callbacks are supported only for
4948 * builtin subsystems and we don't need further
4949 * synchronization as they never go away.
4950 */
4951 if (!ss || ss->module)
4952 continue;
4953
4954 if (ss->fork) 4954 if (ss->fork)
4955 ss->fork(child); 4955 ss->fork(child);
4956 } 4956 }
@@ -5015,13 +5015,13 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks)
5015 tsk->cgroups = &init_css_set; 5015 tsk->cgroups = &init_css_set;
5016 5016
5017 if (run_callbacks && need_forkexit_callback) { 5017 if (run_callbacks && need_forkexit_callback) {
5018 for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { 5018 /*
5019 * fork/exit callbacks are supported only for builtin
5020 * subsystems, see cgroup_post_fork() for details.
5021 */
5022 for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) {
5019 struct cgroup_subsys *ss = subsys[i]; 5023 struct cgroup_subsys *ss = subsys[i];
5020 5024
5021 /* modular subsystems can't use callbacks */
5022 if (!ss || ss->module)
5023 continue;
5024
5025 if (ss->exit) { 5025 if (ss->exit) {
5026 struct cgroup *old_cgrp = 5026 struct cgroup *old_cgrp =
5027 rcu_dereference_raw(cg->subsys[i])->cgroup; 5027 rcu_dereference_raw(cg->subsys[i])->cgroup;