diff options
author | Tejun Heo <tj@kernel.org> | 2011-03-23 05:37:01 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-03-23 05:37:01 -0400 |
commit | 62bcf9d992ecc19ea4f37ff57ee0b3333e3e843e (patch) | |
tree | a02286c9afffcda9361e0422370b78fe953df7de /kernel | |
parent | 75b95953a56969a990e6ce154b260be83818fe71 (diff) |
job control: Job control stop notifications should always go to the real parent
The stopped notifications in do_signal_stop() and exit_signals() are
always for the completion of job control. The one in do_signal_stop()
may be delivered to the ptracer if PTRACE_ATTACH races with
notification and the one in exit_signals() if task exits while
ptraced.
In both cases, the notifications are meaningless and confusing to the
ptracer as it never accesses the group stop state while the real
parent would miss notifications for the events it is watching.
Make sure these notifications always go to the real parent by calling
do_notify_parent_cld_stop() with %false @for_ptrace.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/signal.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 69d60540a680..9f10b246fd46 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -1898,10 +1898,18 @@ retry: | |||
1898 | __set_current_state(TASK_STOPPED); | 1898 | __set_current_state(TASK_STOPPED); |
1899 | spin_unlock_irq(¤t->sighand->siglock); | 1899 | spin_unlock_irq(¤t->sighand->siglock); |
1900 | 1900 | ||
1901 | /* | ||
1902 | * Notify the parent of the group stop completion. Because | ||
1903 | * we're not holding either the siglock or tasklist_lock | ||
1904 | * here, ptracer may attach inbetween; however, this is for | ||
1905 | * group stop and should always be delivered to the real | ||
1906 | * parent of the group leader. The new ptracer will get | ||
1907 | * its notification when this task transitions into | ||
1908 | * TASK_TRACED. | ||
1909 | */ | ||
1901 | if (notify) { | 1910 | if (notify) { |
1902 | read_lock(&tasklist_lock); | 1911 | read_lock(&tasklist_lock); |
1903 | do_notify_parent_cldstop(current, task_ptrace(current), | 1912 | do_notify_parent_cldstop(current, false, notify); |
1904 | notify); | ||
1905 | read_unlock(&tasklist_lock); | 1913 | read_unlock(&tasklist_lock); |
1906 | } | 1914 | } |
1907 | 1915 | ||
@@ -2182,9 +2190,13 @@ void exit_signals(struct task_struct *tsk) | |||
2182 | out: | 2190 | out: |
2183 | spin_unlock_irq(&tsk->sighand->siglock); | 2191 | spin_unlock_irq(&tsk->sighand->siglock); |
2184 | 2192 | ||
2193 | /* | ||
2194 | * If group stop has completed, deliver the notification. This | ||
2195 | * should always go to the real parent of the group leader. | ||
2196 | */ | ||
2185 | if (unlikely(group_stop)) { | 2197 | if (unlikely(group_stop)) { |
2186 | read_lock(&tasklist_lock); | 2198 | read_lock(&tasklist_lock); |
2187 | do_notify_parent_cldstop(tsk, task_ptrace(tsk), group_stop); | 2199 | do_notify_parent_cldstop(tsk, false, group_stop); |
2188 | read_unlock(&tasklist_lock); | 2200 | read_unlock(&tasklist_lock); |
2189 | } | 2201 | } |
2190 | } | 2202 | } |