stable.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] ptrace fixes for 3.2
@ 2012-01-04 16:28 Oleg Nesterov
  2012-01-04 16:29 ` [PATCH 1/2] ptrace: partially fix the do_wait(WEXITED) vs EXIT_DEAD->EXIT_ZOMBIE race Oleg Nesterov
  2012-01-04 16:29 ` [PATCH 2/2] ptrace: ensure JOBCTL_STOP_SIGMASK is not zero after detach Oleg Nesterov
  0 siblings, 2 replies; 3+ messages in thread
From: Oleg Nesterov @ 2012-01-04 16:28 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Denys Vlasenko, Lukasz Michalik, Dmitry V. Levin, Tejun Heo,
	linux-kernel, stable

Hello.

2 simple fixes for 3.2. Both changes are temporary hacks, hopefully
we will properly fix the problems in the next devel cycle.

Oleg.


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] ptrace: partially fix the do_wait(WEXITED) vs EXIT_DEAD->EXIT_ZOMBIE race
  2012-01-04 16:28 [PATCH 0/2] ptrace fixes for 3.2 Oleg Nesterov
@ 2012-01-04 16:29 ` Oleg Nesterov
  2012-01-04 16:29 ` [PATCH 2/2] ptrace: ensure JOBCTL_STOP_SIGMASK is not zero after detach Oleg Nesterov
  1 sibling, 0 replies; 3+ messages in thread
From: Oleg Nesterov @ 2012-01-04 16:29 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Denys Vlasenko, Lukasz Michalik, Dmitry V. Levin, Tejun Heo,
	linux-kernel, stable

Test-case:

	int main(void)
	{
		int pid, status;

		pid = fork();
		if (!pid) {
			for (;;) {
				if (!fork())
					return 0;
				if (waitpid(-1, &status, 0) < 0) {
					printf("ERR!! wait: %m\n");
					return 0;
				}
			}
		}

		assert(ptrace(PTRACE_ATTACH, pid, 0,0) == 0);
		assert(waitpid(-1, NULL, 0) == pid);

		assert(ptrace(PTRACE_SETOPTIONS, pid, 0,
					PTRACE_O_TRACEFORK) == 0);

		do {
			ptrace(PTRACE_CONT, pid, 0, 0);
			pid = waitpid(-1, NULL, 0);
		} while (pid > 0);

		return 1;
	}

It fails because ->real_parent sees its child in EXIT_DEAD state
while the tracer is going to change the state back to EXIT_ZOMBIE
in wait_task_zombie().

The offending commit is 823b018e which moved the EXIT_DEAD check,
but in fact we should not blame it. The original code was not
correct as well because it didn't take ptrace_reparented() into
account and because we can't really trust ->ptrace.

This patch adds the additional check to close this particular
race but it doesn't solve the whole problem. We simply can't
rely on ->ptrace in this case, it can be cleared if the tracer
is multithreaded by the exiting ->parent.

I think we should kill EXIT_DEAD altogether, we should always
remove the soon-to-be-reaped child from ->children or at least
we should never do the DEAD->ZOMBIE transition. But this is too
complex for 3.2.

Reported-and-tested-by: Denys Vlasenko <vda.linux@googlemail.com>
Tested-by: Lukasz Michalik <lmi@ift.uni.wroc.pl>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: <stable@kernel.org>		[3.0+]
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 kernel/exit.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/kernel/exit.c b/kernel/exit.c
index d0b7d98..e6e01b9 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1540,8 +1540,15 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
 	}
 
 	/* dead body doesn't have much to contribute */
-	if (p->exit_state == EXIT_DEAD)
+	if (unlikely(p->exit_state == EXIT_DEAD)) {
+		/*
+		 * But do not ignore this task until the tracer does
+		 * wait_task_zombie()->do_notify_parent().
+		 */
+		if (likely(!ptrace) && unlikely(ptrace_reparented(p)))
+			wo->notask_error = 0;
 		return 0;
+	}
 
 	/* slay zombie? */
 	if (p->exit_state == EXIT_ZOMBIE) {
-- 
1.5.5.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] ptrace: ensure JOBCTL_STOP_SIGMASK is not zero after detach
  2012-01-04 16:28 [PATCH 0/2] ptrace fixes for 3.2 Oleg Nesterov
  2012-01-04 16:29 ` [PATCH 1/2] ptrace: partially fix the do_wait(WEXITED) vs EXIT_DEAD->EXIT_ZOMBIE race Oleg Nesterov
@ 2012-01-04 16:29 ` Oleg Nesterov
  1 sibling, 0 replies; 3+ messages in thread
From: Oleg Nesterov @ 2012-01-04 16:29 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Denys Vlasenko, Lukasz Michalik, Dmitry V. Levin, Tejun Heo,
	linux-kernel, stable

This is the temporary simple fix for 3.2, we need more changes in this
area.

1. do_signal_stop() assumes that the running untraced thread in the
   stopped thread group is not possible. This was our goal but it is
   not yet achieved: a stopped-but-resumed tracee can clone the running
   thread which can initiate another group-stop.

   Remove WARN_ON_ONCE(!current->ptrace).

2. A new thread always starts with ->jobctl = 0. If it is auto-attached
   and this group is stopped, __ptrace_unlink() sets JOBCTL_STOP_PENDING
   but JOBCTL_STOP_SIGMASK part is zero, this triggers WANR_ON(!signr)
   in do_jobctl_trap() if another debugger attaches.

   Change __ptrace_unlink() to set the artificial SIGSTOP for report.

   Alternatively we could change ptrace_init_task() to copy signr from
   current, but this means we can copy it for no reason and hide the
   possible similar problems.

Acked-by: Tejun Heo <tj@kernel.org>
Cc: <stable@kernel.org>		[3.1]
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 kernel/ptrace.c |   13 ++++++++++++-
 kernel/signal.c |    2 --
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 24d0447..78ab24a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -96,9 +96,20 @@ void __ptrace_unlink(struct task_struct *child)
 	 */
 	if (!(child->flags & PF_EXITING) &&
 	    (child->signal->flags & SIGNAL_STOP_STOPPED ||
-	     child->signal->group_stop_count))
+	     child->signal->group_stop_count)) {
 		child->jobctl |= JOBCTL_STOP_PENDING;
 
+		/*
+		 * This is only possible if this thread was cloned by the
+		 * traced task running in the stopped group, set the signal
+		 * for the future reports.
+		 * FIXME: we should change ptrace_init_task() to handle this
+		 * case.
+		 */
+		if (!(child->jobctl & JOBCTL_STOP_SIGMASK))
+			child->jobctl |= SIGSTOP;
+	}
+
 	/*
 	 * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick
 	 * @child in the butt.  Note that @resume should be used iff @child
diff --git a/kernel/signal.c b/kernel/signal.c
index b3f78d0..2065515 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1994,8 +1994,6 @@ static bool do_signal_stop(int signr)
 		 */
 		if (!(sig->flags & SIGNAL_STOP_STOPPED))
 			sig->group_exit_code = signr;
-		else
-			WARN_ON_ONCE(!current->ptrace);
 
 		sig->group_stop_count = 0;
 
-- 
1.5.5.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-01-04 16:29 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-01-04 16:28 [PATCH 0/2] ptrace fixes for 3.2 Oleg Nesterov
2012-01-04 16:29 ` [PATCH 1/2] ptrace: partially fix the do_wait(WEXITED) vs EXIT_DEAD->EXIT_ZOMBIE race Oleg Nesterov
2012-01-04 16:29 ` [PATCH 2/2] ptrace: ensure JOBCTL_STOP_SIGMASK is not zero after detach Oleg Nesterov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).