From: Tejun Heo <tj@kernel.org>
To: oleg@redhat.com, roland@redhat.com, linux-kernel@vger.kernel.org,
torvalds@linux-foundation.org, akpm@linux-foundation.org,
rjw@sisk.pl, jan.kratochvil@redhat.com
Cc: Tejun Heo <tj@kernel.org>
Subject: [PATCH 12/16] ptrace: make group stop notification reliable against ptrace
Date: Mon, 6 Dec 2010 17:57:00 +0100 [thread overview]
Message-ID: <1291654624-6230-13-git-send-email-tj@kernel.org> (raw)
In-Reply-To: <1291654624-6230-1-git-send-email-tj@kernel.org>
Group stop notifications are unreliable if one or more tasks of the
task group are being ptraced. If a ptraced task ends up finishing a
group stop, the notification is sent to the ptracer and the real
parent never gets notified.
This patch adds a new signal flag SIGNAL_NOTIFY_STOP which is set on
group stop completion and cleared on notification to the real parent
or together with other stopped flags on SIGCONT/KILL. This guarantees
that the real parent is notified correctly regardless of ptrace. If a
ptraced task is the last task to stop, the notification is postponed
till ptrace detach or canceled if SIGCONT/KILL is received inbetween.
Oleg spotted race against ptrace attach/detach in the initial
implementation. This is fixed by moving notification determiniation
into do_notify_parent_cldstop() and performing it while holding both
tasklist_lock and siglock.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
---
include/linux/sched.h | 2 +
kernel/signal.c | 65 +++++++++++++++++++++++++++++-------------------
2 files changed, 41 insertions(+), 26 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 7045c34..7a26e7d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -653,6 +653,8 @@ struct signal_struct {
#define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */
+#define SIGNAL_NOTIFY_STOP 0x00000100 /* notify parent of group stop */
+
/* If true, all threads except ->group_exit_task have pending SIGKILL */
static inline int signal_group_exit(const struct signal_struct *sig)
{
diff --git a/kernel/signal.c b/kernel/signal.c
index 7dfbba9..3196367 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -269,7 +269,7 @@ void task_clear_group_stop(struct task_struct *task)
* CONTEXT:
* Must be called with @task->sighand->siglock held.
*/
-static bool task_participate_group_stop(struct task_struct *task)
+static void task_participate_group_stop(struct task_struct *task)
{
struct signal_struct *sig = task->signal;
bool consume = task->group_stop & GROUP_STOP_CONSUME;
@@ -279,18 +279,15 @@ static bool task_participate_group_stop(struct task_struct *task)
task_clear_group_stop(task);
if (!consume)
- return false;
+ return;
task->group_stop &= ~GROUP_STOP_CONSUME;
if (!WARN_ON_ONCE(sig->group_stop_count == 0))
sig->group_stop_count--;
- if (!sig->group_stop_count) {
- sig->flags = SIGNAL_STOP_STOPPED;
- return true;
- }
- return false;
+ if (!sig->group_stop_count)
+ sig->flags = SIGNAL_STOP_STOPPED | SIGNAL_NOTIFY_STOP;
}
/*
@@ -1603,6 +1600,16 @@ int do_notify_parent(struct task_struct *tsk, int sig)
* @why: CLD_{CONTINUED|STOPPED|TRAPPED}
*
* Notifies the parent that @tsk has been continued or is about to stop.
+ * Depending on @why and other conditions, the notification might be
+ * skipped.
+ *
+ * CLD_STOPPED : If ptraced, always notify; otherwise, notify
+ * once if SIGNAL_NOTIFY_STOP is set.
+ *
+ * CLD_TRAPPED : Always notify.
+ *
+ * For notify once cases, the respective NOTIFY flag is consumed and
+ * cleared.
*
* The notify target changes depending on whether @tsk is being ptraced or
* not. If @tsk is being ptraced, it's always the ptracer; otherwise, it's
@@ -1632,9 +1639,26 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
switch (why) {
case CLD_CONTINUED:
+ notify = why;
+ break;
+
case CLD_STOPPED:
+ /*
+ * If ptraced, always notify; otherwise, notify once if
+ * NOTIFY_STOP is set.
+ */
+ if (task_ptrace(tsk))
+ notify = CLD_STOPPED;
+ else if (sig->flags & SIGNAL_NOTIFY_STOP) {
+ notify = CLD_STOPPED;
+ sig->flags &= ~SIGNAL_NOTIFY_STOP;
+ }
+ break;
+
case CLD_TRAPPED:
- notify = why;
+ /* TRAPPED is possible only while ptraced and always notified */
+ WARN_ON_ONCE(!task_ptrace(tsk));
+ notify = CLD_TRAPPED;
break;
}
@@ -1901,21 +1925,12 @@ retry:
__set_current_state(TASK_STOPPED);
if (likely(!task_ptrace(current))) {
- int notify = 0;
-
- /*
- * If there are no other threads in the group, or if there
- * is a group stop in progress and we are the last to stop,
- * report to the parent.
- */
- if (task_participate_group_stop(current))
- notify = CLD_STOPPED;
-
+ task_participate_group_stop(current);
spin_unlock_irq(¤t->sighand->siglock);
- if (notify) {
+ if (sig->flags & SIGNAL_NOTIFY_STOP) {
read_lock(&tasklist_lock);
- do_notify_parent_cldstop(current, notify);
+ do_notify_parent_cldstop(current, CLD_STOPPED);
read_unlock(&tasklist_lock);
}
@@ -2160,7 +2175,6 @@ relock:
void exit_signals(struct task_struct *tsk)
{
- int group_stop = 0;
struct task_struct *t;
if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) {
@@ -2185,15 +2199,14 @@ void exit_signals(struct task_struct *tsk)
if (!signal_pending(t) && !(t->flags & PF_EXITING))
recalc_sigpending_and_wake(t);
- if (unlikely(tsk->group_stop & GROUP_STOP_PENDING) &&
- task_participate_group_stop(tsk))
- group_stop = CLD_STOPPED;
+ if (unlikely(tsk->group_stop & GROUP_STOP_PENDING))
+ task_participate_group_stop(tsk);
out:
spin_unlock_irq(&tsk->sighand->siglock);
- if (unlikely(group_stop)) {
+ if (unlikely(tsk->signal->flags & SIGNAL_NOTIFY_STOP)) {
read_lock(&tasklist_lock);
- do_notify_parent_cldstop(tsk, group_stop);
+ do_notify_parent_cldstop(tsk, CLD_STOPPED);
read_unlock(&tasklist_lock);
}
}
--
1.7.1
next prev parent reply other threads:[~2010-12-06 16:58 UTC|newest]
Thread overview: 62+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-06 16:56 [PATCHSET] ptrace,signal: sane interaction between ptrace and job control signals, take#2 Tejun Heo
2010-12-06 16:56 ` [PATCH 01/16] signal: fix SIGCONT notification code Tejun Heo
2010-12-06 16:56 ` [PATCH 02/16] signal: fix CLD_CONTINUED notification target Tejun Heo
2010-12-20 14:58 ` Oleg Nesterov
2010-12-21 16:31 ` Tejun Heo
2010-12-06 16:56 ` [PATCH 03/16] signal: remove superflous try_to_freeze() loop in do_signal_stop() Tejun Heo
2010-12-20 14:59 ` Oleg Nesterov
2010-12-06 16:56 ` [PATCH 04/16] ptrace: kill tracehook_notify_jctl() Tejun Heo
2010-12-20 14:59 ` Oleg Nesterov
2010-12-21 17:00 ` Tejun Heo
2010-12-06 16:56 ` [PATCH 05/16] ptrace: add @why to ptrace_stop() Tejun Heo
2010-12-06 16:56 ` [PATCH 06/16] signal: fix premature completion of group stop when interfered by ptrace Tejun Heo
2010-12-20 15:00 ` Oleg Nesterov
2010-12-21 17:04 ` Tejun Heo
2010-12-06 16:56 ` [PATCH 07/16] signal: use GROUP_STOP_PENDING to stop once for a single group stop Tejun Heo
2010-12-06 16:56 ` [PATCH 08/16] ptrace: participate in group stop from ptrace_stop() iff the task is trapping for " Tejun Heo
2010-12-06 16:56 ` [PATCH 09/16] ptrace: make do_signal_stop() use ptrace_stop() if the task is being ptraced Tejun Heo
2010-12-23 12:26 ` Oleg Nesterov
2010-12-23 13:53 ` Tejun Heo
2010-12-23 16:06 ` Oleg Nesterov
2010-12-23 16:33 ` Tejun Heo
2011-01-17 22:09 ` Roland McGrath
2011-01-27 13:56 ` Tejun Heo
2011-01-28 20:30 ` Roland McGrath
2011-01-31 14:39 ` Tejun Heo
2010-12-06 16:56 ` [PATCH 10/16] ptrace: clean transitions between TASK_STOPPED and TRACED Tejun Heo
2010-12-20 15:00 ` Oleg Nesterov
2010-12-21 17:31 ` Tejun Heo
2010-12-21 17:32 ` Tejun Heo
2010-12-22 10:54 ` Tejun Heo
2010-12-22 11:39 ` Oleg Nesterov
2010-12-22 15:14 ` Tejun Heo
2010-12-22 16:00 ` Oleg Nesterov
2010-12-22 16:21 ` Tejun Heo
2010-12-06 16:56 ` [PATCH 11/16] signal: prepare for CLD_* notification changes Tejun Heo
2010-12-20 16:21 ` Oleg Nesterov
2010-12-20 16:23 ` Oleg Nesterov
2010-12-21 17:35 ` Tejun Heo
2010-12-06 16:57 ` Tejun Heo [this message]
2010-12-20 17:34 ` [PATCH 12/16] ptrace: make group stop notification reliable against ptrace Oleg Nesterov
2010-12-21 17:43 ` Tejun Heo
2010-12-22 11:54 ` Oleg Nesterov
2010-12-22 15:26 ` Tejun Heo
2010-12-22 16:02 ` Oleg Nesterov
2010-12-06 16:57 ` [PATCH 13/16] ptrace: reorganize __ptrace_unlink() and ptrace_untrace() Tejun Heo
2010-12-20 18:15 ` Oleg Nesterov
2010-12-21 17:54 ` Tejun Heo
2010-12-06 16:57 ` [PATCH 14/16] ptrace: make SIGCONT notification reliable against ptrace Tejun Heo
2010-12-20 19:43 ` Oleg Nesterov
2010-12-21 17:48 ` Tejun Heo
2010-12-22 12:16 ` Oleg Nesterov
2010-12-21 17:25 ` Oleg Nesterov
2010-12-22 10:35 ` Tejun Heo
2010-12-06 16:57 ` [PATCH 15/16] ptrace: make sure SIGNAL_NOTIFY_CONT is checked after ptrace_signal() Tejun Heo
2010-12-06 16:57 ` [PATCH 16/16] ptrace: remove the extra wake_up_process() from ptrace_detach() Tejun Heo
2010-12-07 0:10 ` Roland McGrath
2010-12-07 13:43 ` Tejun Heo
2010-12-21 17:54 ` Oleg Nesterov
2010-12-22 10:36 ` Tejun Heo
2010-12-14 17:36 ` [PATCHSET] ptrace,signal: sane interaction between ptrace and job control signals, take#2 Oleg Nesterov
2010-12-14 17:46 ` Tejun Heo
2010-12-22 15:20 ` Oleg Nesterov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1291654624-6230-13-git-send-email-tj@kernel.org \
--to=tj@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=jan.kratochvil@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=oleg@redhat.com \
--cc=rjw@sisk.pl \
--cc=roland@redhat.com \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome