utrace_finish_stop() is needed to avoid the races with SIGKILL which wakes up UTRACED task, and thus it should be called every time after the STOPPED/TRACED/UTRACED returns from schedule(), remember that TASK_UTRACED can be added while the task is STOPPED/UTRACED.
- change do_signal_state() to call this helper right after schedule(), otherwise this logic is broken by the upstream changes
- now that utrace doesn't control TASK_TRACED bit, ptrace_stop() must call this helper too.
Signed-off-by: Oleg Nesterov oleg@redhat.com --- include/linux/utrace.h | 11 +++++++++++ kernel/signal.c | 5 +++++ kernel/utrace.c | 2 +- 3 files changed, 17 insertions(+), 1 deletions(-)
diff --git a/include/linux/utrace.h b/include/linux/utrace.h index cf13839..0279c74 100644 --- a/include/linux/utrace.h +++ b/include/linux/utrace.h @@ -719,4 +719,15 @@ static inline void utrace_exit_notify(struct task_struct *task, utrace_report_death(task, group_dead, signal); }
+/** + * utrace_end_stop - report about return from STOPPED/TRACED + * + * This is called by do_signal_stop() and ptrace_stop after wakeup. + */ +static inline void utrace_end_stop(void) +{ + if (task_utrace_flags(current)) + utrace_finish_stop(); +} + #endif /* linux/utrace.h */ diff --git a/kernel/signal.c b/kernel/signal.c index 0dc6abb..a625309 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1895,6 +1895,8 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) read_unlock(&tasklist_lock); }
+ utrace_end_stop(); + /* * While in TASK_TRACED, we were considered "frozen enough". * Now that we woke up, it's crucial if we're supposed to be @@ -2059,6 +2061,9 @@ static bool do_signal_stop(int signr)
/* Now we don't run again until woken by SIGCONT or SIGKILL */ schedule(); + + utrace_end_stop(); + return true; } else { /* diff --git a/kernel/utrace.c b/kernel/utrace.c index 2097103..d41b982 100644 --- a/kernel/utrace.c +++ b/kernel/utrace.c @@ -741,7 +741,7 @@ static bool utrace_reset(struct task_struct *task, struct utrace *utrace) void utrace_finish_stop(void) { /* - * If we were task_is_traced() and then SIGKILL'ed, make + * If we were task_is_utraced() and then SIGKILL'ed, make * sure we do nothing until the tracer drops utrace->lock. */ if (unlikely(__fatal_signal_pending(current))) {