diff options
author | Peter Zijlstra <peterz@infradead.org> | 2011-01-19 06:26:11 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-01-19 06:51:32 -0500 |
commit | 068c5cc5ac7414a8e9eb7856b4bf3cc4d4744267 (patch) | |
tree | 28a017e342dddd3ffe8e3dd3499a395aee39b796 /kernel | |
parent | d7d8294415f0ce4254827d4a2a5ee88b00be52a8 (diff) |
sched, cgroup: Use exit hook to avoid use-after-free crash
By not notifying the controller of the on-exit move back to
init_css_set, we fail to move the task out of the previous
cgroup's cfs_rq. This leads to an opportunity for a
cgroup-destroy to come in and free the cgroup (there are no
active tasks left in it after all) to which the not-quite dead
task is still enqueued.
Reported-by: Miklos Vajna <vmiklos@frugalware.org>
Fixed-by: Mike Galbraith <efault@gmx.de>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: <stable@kernel.org>
Cc: Mike Galbraith <efault@gmx.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
LKML-Reference: <1293206353.29444.205.camel@laptop>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched.c | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 0a169a85eb3e..fa5272a0932c 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -606,6 +606,9 @@ static inline struct task_group *task_group(struct task_struct *p) | |||
606 | struct task_group *tg; | 606 | struct task_group *tg; |
607 | struct cgroup_subsys_state *css; | 607 | struct cgroup_subsys_state *css; |
608 | 608 | ||
609 | if (p->flags & PF_EXITING) | ||
610 | return &root_task_group; | ||
611 | |||
609 | css = task_subsys_state_check(p, cpu_cgroup_subsys_id, | 612 | css = task_subsys_state_check(p, cpu_cgroup_subsys_id, |
610 | lockdep_is_held(&task_rq(p)->lock)); | 613 | lockdep_is_held(&task_rq(p)->lock)); |
611 | tg = container_of(css, struct task_group, css); | 614 | tg = container_of(css, struct task_group, css); |
@@ -8880,6 +8883,20 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, | |||
8880 | } | 8883 | } |
8881 | } | 8884 | } |
8882 | 8885 | ||
8886 | static void | ||
8887 | cpu_cgroup_exit(struct cgroup_subsys *ss, struct task_struct *task) | ||
8888 | { | ||
8889 | /* | ||
8890 | * cgroup_exit() is called in the copy_process() failure path. | ||
8891 | * Ignore this case since the task hasn't ran yet, this avoids | ||
8892 | * trying to poke a half freed task state from generic code. | ||
8893 | */ | ||
8894 | if (!(task->flags & PF_EXITING)) | ||
8895 | return; | ||
8896 | |||
8897 | sched_move_task(task); | ||
8898 | } | ||
8899 | |||
8883 | #ifdef CONFIG_FAIR_GROUP_SCHED | 8900 | #ifdef CONFIG_FAIR_GROUP_SCHED |
8884 | static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype, | 8901 | static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype, |
8885 | u64 shareval) | 8902 | u64 shareval) |
@@ -8952,6 +8969,7 @@ struct cgroup_subsys cpu_cgroup_subsys = { | |||
8952 | .destroy = cpu_cgroup_destroy, | 8969 | .destroy = cpu_cgroup_destroy, |
8953 | .can_attach = cpu_cgroup_can_attach, | 8970 | .can_attach = cpu_cgroup_can_attach, |
8954 | .attach = cpu_cgroup_attach, | 8971 | .attach = cpu_cgroup_attach, |
8972 | .exit = cpu_cgroup_exit, | ||
8955 | .populate = cpu_cgroup_populate, | 8973 | .populate = cpu_cgroup_populate, |
8956 | .subsys_id = cpu_cgroup_subsys_id, | 8974 | .subsys_id = cpu_cgroup_subsys_id, |
8957 | .early_init = 1, | 8975 | .early_init = 1, |