* [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.