From: Greg Kroah-Hartman Date: Fri, 6 Nov 2020 11:23:53 +0000 (+0100) Subject: 5.9-stable patches X-Git-Tag: v4.4.242~49 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=09eb78a2b7316414f85866276a61f598ce10129f;p=thirdparty%2Fkernel%2Fstable-queue.git 5.9-stable patches added patches: ptrace-fix-task_join_group_stop-for-the-case-when-current-is-traced.patch --- diff --git a/queue-5.9/ptrace-fix-task_join_group_stop-for-the-case-when-current-is-traced.patch b/queue-5.9/ptrace-fix-task_join_group_stop-for-the-case-when-current-is-traced.patch new file mode 100644 index 00000000000..f8ac13a3c48 --- /dev/null +++ b/queue-5.9/ptrace-fix-task_join_group_stop-for-the-case-when-current-is-traced.patch @@ -0,0 +1,116 @@ +From 7b3c36fc4c231ca532120bbc0df67a12f09c1d96 Mon Sep 17 00:00:00 2001 +From: Oleg Nesterov +Date: Sun, 1 Nov 2020 17:07:44 -0800 +Subject: ptrace: fix task_join_group_stop() for the case when current is traced + +From: Oleg Nesterov + +commit 7b3c36fc4c231ca532120bbc0df67a12f09c1d96 upstream. + +This testcase + + #include + #include + #include + #include + #include + #include + #include + + void *tf(void *arg) + { + return NULL; + } + + int main(void) + { + int pid = fork(); + if (!pid) { + kill(getpid(), SIGSTOP); + + pthread_t th; + pthread_create(&th, NULL, tf, NULL); + + return 0; + } + + waitpid(pid, NULL, WSTOPPED); + + ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_TRACECLONE); + waitpid(pid, NULL, 0); + + ptrace(PTRACE_CONT, pid, 0,0); + waitpid(pid, NULL, 0); + + int status; + int thread = waitpid(-1, &status, 0); + assert(thread > 0 && thread != pid); + assert(status == 0x80137f); + + return 0; + } + +fails and triggers WARN_ON_ONCE(!signr) in do_jobctl_trap(). + +This is because task_join_group_stop() has 2 problems when current is traced: + + 1. We can't rely on the "JOBCTL_STOP_PENDING" check, a stopped tracee + can be woken up by debugger and it can clone another thread which + should join the group-stop. + + We need to check group_stop_count || SIGNAL_STOP_STOPPED. + + 2. If SIGNAL_STOP_STOPPED is already set, we should not increment + sig->group_stop_count and add JOBCTL_STOP_CONSUME. The new thread + should stop without another do_notify_parent_cldstop() report. + +To clarify, the problem is very old and we should blame +ptrace_init_task(). But now that we have task_join_group_stop() it makes +more sense to fix this helper to avoid the code duplication. + +Reported-by: syzbot+3485e3773f7da290eecc@syzkaller.appspotmail.com +Signed-off-by: Oleg Nesterov +Signed-off-by: Andrew Morton +Cc: Jens Axboe +Cc: Christian Brauner +Cc: "Eric W . Biederman" +Cc: Zhiqiang Liu +Cc: Tejun Heo +Cc: +Link: https://lkml.kernel.org/r/20201019134237.GA18810@redhat.com +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/signal.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +--- a/kernel/signal.c ++++ b/kernel/signal.c +@@ -391,16 +391,17 @@ static bool task_participate_group_stop( + + void task_join_group_stop(struct task_struct *task) + { ++ unsigned long mask = current->jobctl & JOBCTL_STOP_SIGMASK; ++ struct signal_struct *sig = current->signal; ++ ++ if (sig->group_stop_count) { ++ sig->group_stop_count++; ++ mask |= JOBCTL_STOP_CONSUME; ++ } else if (!(sig->flags & SIGNAL_STOP_STOPPED)) ++ return; ++ + /* Have the new thread join an on-going signal group stop */ +- unsigned long jobctl = current->jobctl; +- if (jobctl & JOBCTL_STOP_PENDING) { +- struct signal_struct *sig = current->signal; +- unsigned long signr = jobctl & JOBCTL_STOP_SIGMASK; +- unsigned long gstop = JOBCTL_STOP_PENDING | JOBCTL_STOP_CONSUME; +- if (task_set_jobctl_pending(task, signr | gstop)) { +- sig->group_stop_count++; +- } +- } ++ task_set_jobctl_pending(task, mask | JOBCTL_STOP_PENDING); + } + + /* diff --git a/queue-5.9/series b/queue-5.9/series index 6acbd212938..25cd30bd023 100644 --- a/queue-5.9/series +++ b/queue-5.9/series @@ -19,3 +19,4 @@ drm-i915-reject-90-270-degree-rotated-initial-fbs.patch drm-i915-restore-ilk-m-rps-support.patch drm-nouveau-kms-nv50-program-notifier-offset-before-requesting-disp-caps.patch drm-nouveau-device-fix-changing-endianess-code-to-work-on-older-gpus.patch +ptrace-fix-task_join_group_stop-for-the-case-when-current-is-traced.patch