diff options
author | Li Zefan <lizefan@huawei.com> | 2013-03-04 21:57:03 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-03-05 12:33:25 -0500 |
commit | 7d8e0bf56a66bab08d2f316dd87e56c08cecb899 (patch) | |
tree | be35c2daec953f0c98241c16311879dd45bc4859 /kernel/cgroup.c | |
parent | f50daa704f36a6544a902c52b6cf37b0493dfc5d (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>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 28 |
1 files changed, 14 insertions, 14 deletions
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; |