aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-09-05 06:05:56 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-09-10 21:57:47 -0400
commit7d94143291e4e625e2bc3b1ebdc7143ee7a9a2f1 (patch)
treec4f8a974a33dd6ac1feacf18f217ee326c8af5eb
parent897ee77bfba12b83752027427a41009961458ee6 (diff)
Fix spurious syscall tracing after PTRACE_DETACH + PTRACE_ATTACH
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 <roland@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/i386/kernel/ptrace.c1
-rw-r--r--arch/ia64/kernel/ptrace.c1
-rw-r--r--arch/m68k/kernel/ptrace.c1
-rw-r--r--kernel/ptrace.c1
4 files changed, 1 insertions, 3 deletions
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 0c8f00e69c4d..7c1b92522e95 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)
274void ptrace_disable(struct task_struct *child) 274void ptrace_disable(struct task_struct *child)
275{ 275{
276 clear_singlestep(child); 276 clear_singlestep(child);
277 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
278 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); 277 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
279} 278}
280 279
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 122444a97897..2e96f17b2f3b 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)
1577 1577
1578 case PTRACE_DETACH: 1578 case PTRACE_DETACH:
1579 /* detach a process that was attached. */ 1579 /* detach a process that was attached. */
1580 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
1581 ret = ptrace_detach(child, data); 1580 ret = ptrace_detach(child, data);
1582 goto out_tsk; 1581 goto out_tsk;
1583 1582
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index 2cf0690b7882..e792d3cba4c7 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)
116void ptrace_disable(struct task_struct *child) 116void ptrace_disable(struct task_struct *child)
117{ 117{
118 singlestep_disable(child); 118 singlestep_disable(child);
119 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
120} 119}
121 120
122long arch_ptrace(struct task_struct *child, long request, long addr, long data) 121long arch_ptrace(struct task_struct *child, long request, long addr, long data)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 82a558b655da..3eca7a55f2ee 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -233,6 +233,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
233 233
234 /* Architecture-specific hardware disable .. */ 234 /* Architecture-specific hardware disable .. */
235 ptrace_disable(child); 235 ptrace_disable(child);
236 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
236 237
237 write_lock_irq(&tasklist_lock); 238 write_lock_irq(&tasklist_lock);
238 /* protect against de_thread()->release_task() */ 239 /* protect against de_thread()->release_task() */