1. ptrace_set_syscall_trace(true)->set_tsk_thread_flag(TIF_SYSCALL_TRACE)
can race with utrace_control()->utrace_reset() path which can miss
PT_SYSCALL_TRACE and clear TIF_SYSCALL_TRACE after it was already set.
2. ptrace_set_syscall_trace(false) clears TIF_SYSCALL_TRACE and this is
not utrace-friendly, it can need this flag.
Change ptrace_set_syscall_trace() to take task_utrace_lock(), this is
enough to fix the 1st problem. Check task_utrace_flags() before clearing
TIF_SYSCALL_TRACE, this fixes 2.
Signed-off-by: Oleg Nesterov <oleg(a)redhat.com>
---
kernel/ptrace.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 1ac03eb..739183a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -24,6 +24,7 @@
#include <linux/regset.h>
#include <linux/hw_breakpoint.h>
#include <linux/cn_proc.h>
+#include <linux/utrace.h>
void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
{
@@ -40,13 +41,16 @@ void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
static void ptrace_set_syscall_trace(struct task_struct *p, bool on)
{
+ task_utrace_lock(p);
if (on) {
p->ptrace |= PT_SYSCALL_TRACE;
set_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
} else {
p->ptrace &= ~PT_SYSCALL_TRACE;
- clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
+ if (!(task_utrace_flags(p) & UTRACE_EVENT_SYSCALL))
+ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE);
}
+ task_utrace_unlock(p);
}
static int ptrace_trapping_sleep_fn(void *flags)
--
1.5.5.1