There is a test case in https://bugzilla.redhat.com/show_bug.cgi?id=276861
to demonstrate this bug.
Thanks,
Roland
---
When PTRACE_SYSCALL was used and then PTRACE_DETACH is used, the
TIF_SYSCALL_TRACE flag is left set on the formerly-traced task.
This means that when a new tracer comes along and does
PTRACE_ATTACH, it's possible he gets a syscall tracing stop even
though he's never used PTRACE_SYSCALL. This happens if the task was
in the middle of a system call when the second PTRACE_ATTACH was
done. The symptom is an unexpected SIGTRAP when the tracer thinks
that only SIGSTOP should have been provoked by his ptrace calls so far.
A few machines already fixed this in ptrace_disable (i386, ia64, m68k).
But all other machines do not, and still have this bug. On x86_64, this
constitutes a regression in IA32 compatibility support.
Since all machines now use TIF_SYSCALL_TRACE for this, I put the
clearing of TIF_SYSCALL_TRACE in the generic ptrace_detach code rather
than adding it to every other machine's ptrace_disable.
Signed-off-by: Roland McGrath <[email protected]>
---
arch/i386/kernel/ptrace.c | 1 -
arch/ia64/kernel/ptrace.c | 1 -
arch/m68k/kernel/ptrace.c | 1 -
kernel/ptrace.c | 1 +
4 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 0c8f00e..7c1b925 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -274,7 +274,6 @@ static void clear_singlestep(struct task_struct *child)
void ptrace_disable(struct task_struct *child)
{
clear_singlestep(child);
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
}
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 122444a..2e96f17 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -1577,7 +1577,6 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
case PTRACE_DETACH:
/* detach a process that was attached. */
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
ret = ptrace_detach(child, data);
goto out_tsk;
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 2cf0690..e792d3c 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -116,7 +116,6 @@ static inline void singlestep_disable(struct task_struct *child)
void ptrace_disable(struct task_struct *child)
{
singlestep_disable(child);
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
}
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 82a558b..3eca7a5 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -233,6 +233,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
/* Architecture-specific hardware disable .. */
ptrace_disable(child);
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
write_lock_irq(&tasklist_lock);
/* protect against de_thread()->release_task() */