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(a)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))) {
--
1.5.5.1