All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/3] PTRACE_SEIZE && fork() fixes
@ 2011-07-08 17:13 Oleg Nesterov
  2011-07-08 17:13 ` [PATCH 1/3] ptrace_init_task: initialize child->jobctl explicitly Oleg Nesterov
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Oleg Nesterov @ 2011-07-08 17:13 UTC (permalink / raw)
  To: Tejun Heo, Linus Torvalds
  Cc: vda.linux, jan.kratochvil, pedro, indan, bdonlan, linux-kernel

On 06/01, Oleg Nesterov wrote:
>
> Just to remind, tracehook_report_clone() shouldn't send SIGSTOP if
> the auto-attached tracee is PT_SEIZED.

I think it is the time to do this, everything else looks consistent.

The patches are simple but 3/3 needs the discussion and acks, this
API is new.

Oleg.


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

* [PATCH 1/3] ptrace_init_task: initialize child->jobctl explicitly
  2011-07-08 17:13 [RFC PATCH 0/3] PTRACE_SEIZE && fork() fixes Oleg Nesterov
@ 2011-07-08 17:13 ` Oleg Nesterov
  2011-07-13 10:25   ` Tejun Heo
  2011-07-08 17:13 ` [PATCH 2/3] ptrace: mv send-SIGSTOP from do_fork() to ptrace_init_task() Oleg Nesterov
  2011-07-08 17:14 ` [RFC PATCH 3/3] ptrace: dont send SIGSTOP on auto-attach if PT_SEIZED Oleg Nesterov
  2 siblings, 1 reply; 6+ messages in thread
From: Oleg Nesterov @ 2011-07-08 17:13 UTC (permalink / raw)
  To: Tejun Heo, Linus Torvalds
  Cc: vda.linux, jan.kratochvil, pedro, indan, bdonlan, linux-kernel

new_child->jobctl is not initialized during the fork, it is copied
from parent->jobctl. Currently this is harmless, the forking task
is running and copy_process() can't succeed if signal_pending() is
true, so only JOBCTL_STOP_DEQUEUED can be copied. Still this is a
bit fragile, it would be more clean to set ->jobctl = 0 explicitly.

Also, check ->ptrace != 0 instead of PT_PTRACED, move the
CONFIG_HAVE_HW_BREAKPOINT code up.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 include/linux/ptrace.h |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

--- ptrace/include/linux/ptrace.h~3_init_jobctl	2011-07-07 18:34:44.000000000 +0200
+++ ptrace/include/linux/ptrace.h	2011-07-08 17:15:20.000000000 +0200
@@ -217,16 +217,17 @@ static inline void ptrace_init_task(stru
 {
 	INIT_LIST_HEAD(&child->ptrace_entry);
 	INIT_LIST_HEAD(&child->ptraced);
-	child->parent = child->real_parent;
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+	atomic_set(&child->ptrace_bp_refcnt, 1);
+#endif
+	child->jobctl = 0;
 	child->ptrace = 0;
-	if (unlikely(ptrace) && (current->ptrace & PT_PTRACED)) {
+	child->parent = child->real_parent;
+
+	if (unlikely(ptrace) && current->ptrace) {
 		child->ptrace = current->ptrace;
 		__ptrace_link(child, current->parent);
 	}
-
-#ifdef CONFIG_HAVE_HW_BREAKPOINT
-	atomic_set(&child->ptrace_bp_refcnt, 1);
-#endif
 }
 
 /**


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

* [PATCH 2/3] ptrace: mv send-SIGSTOP from do_fork() to ptrace_init_task()
  2011-07-08 17:13 [RFC PATCH 0/3] PTRACE_SEIZE && fork() fixes Oleg Nesterov
  2011-07-08 17:13 ` [PATCH 1/3] ptrace_init_task: initialize child->jobctl explicitly Oleg Nesterov
@ 2011-07-08 17:13 ` Oleg Nesterov
  2011-07-08 17:14 ` [RFC PATCH 3/3] ptrace: dont send SIGSTOP on auto-attach if PT_SEIZED Oleg Nesterov
  2 siblings, 0 replies; 6+ messages in thread
From: Oleg Nesterov @ 2011-07-08 17:13 UTC (permalink / raw)
  To: Tejun Heo, Linus Torvalds
  Cc: vda.linux, jan.kratochvil, pedro, indan, bdonlan, linux-kernel

If the new child is traced, do_fork() adds the pending SIGSTOP.
It assumes that either it is traced because of auto-attach or the
tracer attached later, in both cases sigaddset/set_thread_flag is
correct even if SIGSTOP is already pending.

Now that we have PTRACE_SEIZE this is no longer right in the latter
case. If the tracer does PTRACE_SEIZE after copy_process() makes the
child visible the queued SIGSTOP is wrong.

We could check PT_SEIZED bit and change ptrace_attach() to set both
PT_PTRACED and PT_SEIZED bits simultaneously but see the next patch,
we need to know whether this child was auto-attached or not anyway.

So this patch simply moves this code to ptrace_init_task(), this
way we can never race with ptrace_attach().

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 include/linux/ptrace.h |    3 +++
 kernel/fork.c          |   12 ------------
 2 files changed, 3 insertions(+), 12 deletions(-)

--- ptrace/include/linux/ptrace.h~4_send_stop_from_ptrace_init	2011-07-08 17:24:46.000000000 +0200
+++ ptrace/include/linux/ptrace.h	2011-07-08 18:32:05.000000000 +0200
@@ -227,6 +227,9 @@ static inline void ptrace_init_task(stru
 	if (unlikely(ptrace) && current->ptrace) {
 		child->ptrace = current->ptrace;
 		__ptrace_link(child, current->parent);
+
+		sigaddset(&child->pending.signal, SIGSTOP);
+		set_tsk_thread_flag(child, TIF_SIGPENDING);
 	}
 }
 
--- ptrace/kernel/fork.c~4_send_stop_from_ptrace_init	2011-07-08 17:24:46.000000000 +0200
+++ ptrace/kernel/fork.c	2011-07-08 17:25:25.000000000 +0200
@@ -37,7 +37,6 @@
 #include <linux/swap.h>
 #include <linux/syscalls.h>
 #include <linux/jiffies.h>
-#include <linux/tracehook.h>
 #include <linux/futex.h>
 #include <linux/compat.h>
 #include <linux/kthread.h>
@@ -1522,17 +1521,6 @@ long do_fork(unsigned long clone_flags,
 		audit_finish_fork(p);
 
 		/*
-		 * Child is ready but hasn't started running yet.  Queue
-		 * SIGSTOP if it's gonna be ptraced - it doesn't matter who
-		 * attached/attaching to this task, the pending SIGSTOP is
-		 * right in any case.
-		 */
-		if (unlikely(p->ptrace)) {
-			sigaddset(&p->pending.signal, SIGSTOP);
-			set_tsk_thread_flag(p, TIF_SIGPENDING);
-		}
-
-		/*
 		 * We set PF_STARTING at creation in case tracing wants to
 		 * use this to distinguish a fully live task from one that
 		 * hasn't finished SIGSTOP raising yet.  Now we clear it


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

* [RFC PATCH 3/3] ptrace: dont send SIGSTOP on auto-attach if PT_SEIZED
  2011-07-08 17:13 [RFC PATCH 0/3] PTRACE_SEIZE && fork() fixes Oleg Nesterov
  2011-07-08 17:13 ` [PATCH 1/3] ptrace_init_task: initialize child->jobctl explicitly Oleg Nesterov
  2011-07-08 17:13 ` [PATCH 2/3] ptrace: mv send-SIGSTOP from do_fork() to ptrace_init_task() Oleg Nesterov
@ 2011-07-08 17:14 ` Oleg Nesterov
  2011-07-13 12:10   ` Tejun Heo
  2 siblings, 1 reply; 6+ messages in thread
From: Oleg Nesterov @ 2011-07-08 17:14 UTC (permalink / raw)
  To: Tejun Heo, Linus Torvalds
  Cc: vda.linux, jan.kratochvil, pedro, indan, bdonlan, linux-kernel

The fake SIGSTOP during attach has numerous problems. PTRACE_SEIZE
is already fine, but we have basically the same problems is SIGSTOP
is sent on auto-attach, the tracer can't know if this signal signal
should be cancelled or not.

Change ptrace_event() to set JOBCTL_TRAP_STOP if the new child is
PT_SEIZED, this triggers the PTRACE_EVENT_STOP report.

Thereafter a PT_SEIZED task can never report the bogus SIGSTOP.

Test-case:

	#define PTRACE_SEIZE		0x4206
	#define PTRACE_SEIZE_DEVEL	0x80000000
	#define PTRACE_EVENT_STOP	7
	#define WEVENT(s)		((s & 0xFF0000) >> 16)

	int main(void)
	{
		int child, grand_child, status;
		long message;

		child = fork();
		if (!child) {
			kill(getpid(), SIGSTOP);
			fork();
			assert(0);
			return 0x23;
		}

		assert(ptrace(PTRACE_SEIZE, child, 0,PTRACE_SEIZE_DEVEL) == 0);
		assert(wait(&status) == child);
		assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);

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

		assert(ptrace(PTRACE_CONT, child, 0,0) == 0);
		assert(waitpid(child, &status, 0) == child);
		assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP);
		assert(WEVENT(status) == PTRACE_EVENT_FORK);

		assert(ptrace(PTRACE_GETEVENTMSG, child, 0, &message) == 0);
		grand_child = message;

		assert(waitpid(grand_child, &status, 0) == grand_child);
		assert(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP);
		assert(WEVENT(status) == PTRACE_EVENT_STOP);

		kill(child, SIGKILL);
		kill(grand_child, SIGKILL);
		return 0;
	}

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---

 include/linux/ptrace.h |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

--- ptrace/include/linux/ptrace.h~5_clone_no_stop_if_seized	2011-07-08 18:32:05.000000000 +0200
+++ ptrace/include/linux/ptrace.h	2011-07-08 18:32:53.000000000 +0200
@@ -228,7 +228,11 @@ static inline void ptrace_init_task(stru
 		child->ptrace = current->ptrace;
 		__ptrace_link(child, current->parent);
 
-		sigaddset(&child->pending.signal, SIGSTOP);
+		if (child->ptrace & PT_SEIZED)
+			task_set_jobctl_pending(child, JOBCTL_TRAP_STOP);
+		else
+			sigaddset(&child->pending.signal, SIGSTOP);
+
 		set_tsk_thread_flag(child, TIF_SIGPENDING);
 	}
 }


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

* Re: [PATCH 1/3] ptrace_init_task: initialize child->jobctl explicitly
  2011-07-08 17:13 ` [PATCH 1/3] ptrace_init_task: initialize child->jobctl explicitly Oleg Nesterov
@ 2011-07-13 10:25   ` Tejun Heo
  0 siblings, 0 replies; 6+ messages in thread
From: Tejun Heo @ 2011-07-13 10:25 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Linus Torvalds, vda.linux, jan.kratochvil, pedro, indan, bdonlan,
	linux-kernel

On Fri, Jul 08, 2011 at 07:13:39PM +0200, Oleg Nesterov wrote:
> new_child->jobctl is not initialized during the fork, it is copied
> from parent->jobctl. Currently this is harmless, the forking task
> is running and copy_process() can't succeed if signal_pending() is
> true, so only JOBCTL_STOP_DEQUEUED can be copied. Still this is a
> bit fragile, it would be more clean to set ->jobctl = 0 explicitly.
> 
> Also, check ->ptrace != 0 instead of PT_PTRACED, move the
> CONFIG_HAVE_HW_BREAKPOINT code up.
> 
> Signed-off-by: Oleg Nesterov <oleg@redhat.com>

Acked-by: Tejun Heo <tj@kernel.org>

Thanks.

-- 
tejun

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

* Re: [RFC PATCH 3/3] ptrace: dont send SIGSTOP on auto-attach if PT_SEIZED
  2011-07-08 17:14 ` [RFC PATCH 3/3] ptrace: dont send SIGSTOP on auto-attach if PT_SEIZED Oleg Nesterov
@ 2011-07-13 12:10   ` Tejun Heo
  0 siblings, 0 replies; 6+ messages in thread
From: Tejun Heo @ 2011-07-13 12:10 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Linus Torvalds, vda.linux, jan.kratochvil, pedro, indan, bdonlan,
	linux-kernel

Hello,

On Fri, Jul 08, 2011 at 07:14:17PM +0200, Oleg Nesterov wrote:
> The fake SIGSTOP during attach has numerous problems. PTRACE_SEIZE
> is already fine, but we have basically the same problems is SIGSTOP
> is sent on auto-attach, the tracer can't know if this signal signal
> should be cancelled or not.
> 
> Change ptrace_event() to set JOBCTL_TRAP_STOP if the new child is
> PT_SEIZED, this triggers the PTRACE_EVENT_STOP report.
> 
> Thereafter a PT_SEIZED task can never report the bogus SIGSTOP.
> 
> Test-case:
...
> Signed-off-by: Oleg Nesterov <oleg@redhat.com>

Looks good to me.  For 2 and 3,

 Acked-by: Tejun Heo <tj@kernel.org>

So, yeah, with this change, we're almost there.

Thanks.

-- 
tejun

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

end of thread, other threads:[~2011-07-13 12:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-08 17:13 [RFC PATCH 0/3] PTRACE_SEIZE && fork() fixes Oleg Nesterov
2011-07-08 17:13 ` [PATCH 1/3] ptrace_init_task: initialize child->jobctl explicitly Oleg Nesterov
2011-07-13 10:25   ` Tejun Heo
2011-07-08 17:13 ` [PATCH 2/3] ptrace: mv send-SIGSTOP from do_fork() to ptrace_init_task() Oleg Nesterov
2011-07-08 17:14 ` [RFC PATCH 3/3] ptrace: dont send SIGSTOP on auto-attach if PT_SEIZED Oleg Nesterov
2011-07-13 12:10   ` Tejun Heo

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.