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 0825a01..209ea2d 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -23,6 +23,7 @@
#include <linux/uaccess.h>
#include <linux/regset.h>
#include <linux/hw_breakpoint.h>
+#include <linux/utrace.h>
static void ptrace_signal_wake_up(struct task_struct *p, int quiescent)
{
@@ -39,13 +40,16 @@ static 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);
}
/*
--
1.5.5.1
Show replies by thread