aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-03-23 05:37:01 -0400
committerTejun Heo <tj@kernel.org>2011-03-23 05:37:01 -0400
commit62bcf9d992ecc19ea4f37ff57ee0b3333e3e843e (patch)
treea02286c9afffcda9361e0422370b78fe953df7de
parent75b95953a56969a990e6ce154b260be83818fe71 (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>
-rw-r--r--kernel/signal.c18
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(&current->sighand->siglock); 1899 spin_unlock_irq(&current->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)
2182out: 2190out:
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}