From: Oleg Nesterov <oleg@redhat.com>
To: Tejun Heo <tj@kernel.org>
Cc: roland@redhat.com, linux-kernel@vger.kernel.org,
torvalds@linux-foundation.org, akpm@linux-foundation.org,
rjw@sisk.pl, jan.kratochvil@redhat.com
Subject: Re: [PATCH 10/16] ptrace: clean transitions between TASK_STOPPED and TRACED
Date: Mon, 20 Dec 2010 16:00:37 +0100 [thread overview]
Message-ID: <20101220150037.GE11583@redhat.com> (raw)
In-Reply-To: <1291654624-6230-11-git-send-email-tj@kernel.org>
On 12/06, Tejun Heo wrote:
>
> @@ -93,6 +99,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)
> * we are sure that this is our traced child and that can only
> * be changed by us so it's not changing right after this.
> */
> +relock:
> read_lock(&tasklist_lock);
> if ((child->ptrace & PT_PTRACED) && child->parent == current) {
> ret = 0;
> @@ -101,10 +108,30 @@ int ptrace_check_attach(struct task_struct *child, int kill)
> * does ptrace_unlink() before __exit_signal().
> */
> spin_lock_irq(&child->sighand->siglock);
> - if (task_is_stopped(child))
> - child->state = TASK_TRACED;
> - else if (!task_is_traced(child) && !kill)
> + if (!task_is_traced(child) && !kill) {
> + /*
> + * If GROUP_STOP_TRAPPING is set, it is known that
> + * the tracee will enter either TRACED or the bit
> + * will be cleared in definite amount of (userland)
> + * time. Wait while the bit is set.
> + *
> + * This hides PTRACE_ATTACH initiated transition
> + * from STOPPED to TRACED from userland.
> + */
> + if (child->group_stop & GROUP_STOP_TRAPPING) {
> + const int bit = ilog2(GROUP_STOP_TRAPPING);
> + DEFINE_WAIT_BIT(wait, &child->group_stop, bit);
Unused "wait_bit_queue wait"
> +
> + spin_unlock_irq(&child->sighand->siglock);
> + read_unlock(&tasklist_lock);
> +
> + wait_on_bit(&child->group_stop, bit,
Hmm. we could probably use ->wait_chldexit/__wake_up_parent instead,
although I am not sure this would be more clean...
> + ptrace_wait_trap,
> + TASK_UNINTERRUPTIBLE);
I am nervous ;) To me, TASK_KILLABLE makes more sense, and it is
safer if we have a bug.
> + goto relock;
We already set ret = 0. "relock" should set -ESRCH.
> + }
> ret = -ESRCH;
> + }
Probably this deserves a minor cleanup,
relock:
ret = -ESRCH;
read_lock(&tasklist_lock);
if (task_is_traced() || kill) {
ret = 0;
} else {
...
OK. So, ptrace_attach() asks a stopped tracee to s/STOPPED/TRACED/.
If it is not stopped, it should call ptrace_stop() eventually.
This doesn't work if ptrace_attach() races with clone(CLONE_STOPPED).
ptrace_check_attach() can return the wrong ESRCH after that. Perhaps
it is time to kill the CLONE_STOPPED code in do_fork().
> @@ -204,6 +231,26 @@ int ptrace_attach(struct task_struct *task)
> __ptrace_link(task, current);
> send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
>
> + spin_lock(&task->sighand->siglock);
> +
> + /*
> + * If the task is already STOPPED, set GROUP_STOP_PENDING and
> + * TRAPPING, and kick it so that it transits to TRACED. TRAPPING
> + * will be cleared if the child completes the transition or any
> + * event which clears the group stop states happens. The bit is
> + * waited by ptrace_check_attach() to hide the transition from
> + * userland.
> + *
> + * The following is safe as both transitions in and out of STOPPED
> + * are protected by siglock.
> + */
> + if (task_is_stopped(task)) {
> + task->group_stop |= GROUP_STOP_PENDING | GROUP_STOP_TRAPPING;
> + signal_wake_up(task, 1);
> + }
> +
> + spin_unlock(&task->sighand->siglock);
Well. I do not know whether this matters, but "hide the transition from
userland" is not 100% correct. I mean, this change is still visible.
ptrace_check_attach()->wait_on_bit() logic fixes the previous example,
but:
1. the tracer knows that the tracee is stopped
2. the tracer does ptrace(ATTACH)
3. the tracer does do_wait()
In this case do_wait() can see the tracee in TASK_RUNNING state,
this breaks wait_task_stopped(ptrace => true).
Jan?
> @@ -1799,22 +1830,28 @@ static int do_signal_stop(int signr)
> */
> sig->group_exit_code = signr;
>
> - current->group_stop = gstop;
> + current->group_stop &= ~GROUP_STOP_SIGMASK;
> + current->group_stop |= signr | gstop;
> sig->group_stop_count = 1;
> - for (t = next_thread(current); t != current; t = next_thread(t))
> + for (t = next_thread(current); t != current;
> + t = next_thread(t)) {
> + t->group_stop &= ~GROUP_STOP_SIGMASK;
> /*
> * Setting state to TASK_STOPPED for a group
> * stop is always done with the siglock held,
> * so this check has no races.
> */
> if (!(t->flags & PF_EXITING) && !task_is_stopped(t)) {
> - t->group_stop = gstop;
> + t->group_stop |= signr | gstop;
> sig->group_stop_count++;
> signal_wake_up(t, 0);
> - } else
> + } else {
> task_clear_group_stop(t);
This looks racy. Suppose that "current" is ptraced, in this case
it can initiate the new group-stop even if SIGNAL_STOP_STOPPED
is set and we have another TASK_STOPPED thead T.
Suppose that another (or same) debugger ataches to this thread T,
wakes it up and sets GROUP_STOP_TRAPPING.
T resumes, calls ptrace_stop() in TASK_STOPPED, and temporary drops
->siglock.
Now, this task_clear_group_stop(T) confuses ptrace_check_attach(T).
I think ptrace_stop() should be called in TASK_RUNNING state.
This also makes sense because we may call arch_ptrace_stop().
> + t->group_stop |= signr;
Probably this doesn't really matter, but why do we need to
change the GROUP_STOP_SIGMASK part of t->group_stop? If it
is exiting, this is not needed. If it is already stopped, then
it already has the correct (previous) signr.
> + }
> + }
> }
> -
> +retry:
> current->exit_code = sig->group_exit_code;
> __set_current_state(TASK_STOPPED);
It is no longer needed to set ->exit_code here. The only reason
was s/STOPPED/TRACED/ change in ptrace_check_attach(). Now that
we rely on ptrace_stop() which sets ->exit_state, this can be
removed.
And,
> @@ -1842,7 +1879,18 @@ static int do_signal_stop(int signr)
>
> spin_lock_irq(¤t->sighand->siglock);
> } else
> - ptrace_stop(current->exit_code, CLD_STOPPED, 0, NULL);
> + ptrace_stop(current->group_stop & GROUP_STOP_SIGMASK,
> + CLD_STOPPED, 0, NULL);
Perhaps it would be more clean to clear ->exit_code here, in the
"else" branch.
Oleg.
next prev parent reply other threads:[~2010-12-20 15:07 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 [this message]
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 ` [PATCH 12/16] ptrace: make group stop notification reliable against ptrace Tejun Heo
2010-12-20 17:34 ` 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=20101220150037.GE11583@redhat.com \
--to=oleg@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=jan.kratochvil@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=rjw@sisk.pl \
--cc=roland@redhat.com \
--cc=tj@kernel.org \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.