kernel/events/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Since commit 4f6fc7821283 ("perf: Fix sample vs do_exit()") has moved
perf_event_exit_task() call from after exit_task_work() to before
exit_task_work(), task_work_add() from perf_event_exit_task() now returns
0 than -ESRCH, despite perf_event_exit_task_context() updates ctx->task
to TASK_TOMBSTONE. As a result, event->ctx->task == current assumption
no longer holds.
Reported-by: syzbot <syzbot+2fe61cb2a86066be6985@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=2fe61cb2a86066be6985
Fixes: 4f6fc7821283 ("perf: Fix sample vs do_exit()")
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
#syz test
kernel/events/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 7281230044d0..489f42defe3c 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7208,7 +7208,8 @@ static void perf_sigtrap(struct perf_event *event)
* ctx->task or current has changed in the meantime. This can be the
* case on architectures that do not implement arch_irq_work_raise().
*/
- if (WARN_ON_ONCE(event->ctx->task != current))
+ if (WARN_ON_ONCE(event->ctx->task != current &&
+ event->ctx->task != TASK_TOMBSTONE))
return;
/*
--
2.50.0
On Sat, Jul 05, 2025 at 11:43:37PM +0900, Tetsuo Handa wrote: > Since commit 4f6fc7821283 ("perf: Fix sample vs do_exit()") has moved > perf_event_exit_task() call from after exit_task_work() to before > exit_task_work(), > task_work_add() from perf_event_exit_task() now returns There is no task_work_add() in perf_event_exit_task(). > 0 than -ESRCH, despite perf_event_exit_task_context() updates ctx->task > to TASK_TOMBSTONE. As a result, event->ctx->task == current assumption > no longer holds. This changelog is confusing to the point that I've no idea what it is trying to tell me. Did you mean to say something like: Because exit_task_work() now runs after perf_event_exit_task(), it is possible for an already queued perf_pending_task()->perf_sigtrap() to observe a dead task context. > Reported-by: syzbot <syzbot+2fe61cb2a86066be6985@syzkaller.appspotmail.com> > Closes: https://syzkaller.appspot.com/bug?extid=2fe61cb2a86066be6985 > Fixes: 4f6fc7821283 ("perf: Fix sample vs do_exit()") > Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> > --- > #syz test > > kernel/events/core.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/kernel/events/core.c b/kernel/events/core.c > index 7281230044d0..489f42defe3c 100644 > --- a/kernel/events/core.c > +++ b/kernel/events/core.c > @@ -7208,7 +7208,8 @@ static void perf_sigtrap(struct perf_event *event) > * ctx->task or current has changed in the meantime. This can be the > * case on architectures that do not implement arch_irq_work_raise(). > */ > - if (WARN_ON_ONCE(event->ctx->task != current)) > + if (WARN_ON_ONCE(event->ctx->task != current && > + event->ctx->task != TASK_TOMBSTONE)) > return; > Also, isn't it better to simply swap the early exit tests in that function like so: diff --git a/kernel/events/core.c b/kernel/events/core.c index 0db36b2b2448..22fdf0c187cd 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7203,6 +7203,13 @@ void perf_event_wakeup(struct perf_event *event) static void perf_sigtrap(struct perf_event *event) { + /* + * Both perf_pending_task() and perf_pending_irq() can race with the + * task exiting. + */ + if (current->flags & PF_EXITING) + return; + /* * We'd expect this to only occur if the irq_work is delayed and either * ctx->task or current has changed in the meantime. This can be the @@ -7211,13 +7218,6 @@ static void perf_sigtrap(struct perf_event *event) if (WARN_ON_ONCE(event->ctx->task != current)) return; - /* - * Both perf_pending_task() and perf_pending_irq() can race with the - * task exiting. - */ - if (current->flags & PF_EXITING) - return; - send_sig_perf((void __user *)event->pending_addr, event->orig_type, event->attr.sig_data); }
On 2025/07/09 18:44, Peter Zijlstra wrote: > On Sat, Jul 05, 2025 at 11:43:37PM +0900, Tetsuo Handa wrote: >> Since commit 4f6fc7821283 ("perf: Fix sample vs do_exit()") has moved >> perf_event_exit_task() call from after exit_task_work() to before >> exit_task_work(), > >> task_work_add() from perf_event_exit_task() now returns > > There is no task_work_add() in perf_event_exit_task(). Since the function which triggers BUG_ON() is perf_sigtrap(), I guessed that the location that queued the task work is task_work_add() in __perf_event_overflow(). But since testing again with --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -10324,6 +10324,7 @@ static int __perf_event_overflow(struct perf_event *event, if (!event->pending_work && !task_work_add(current, &event->pending_task, notify_mode)) { + BUG_ON(event->ctx && event->ctx->task == TASK_TOMBSTONE); event->pending_work = pending_id; local_inc(&event->ctx->nr_no_switch_fast); WARN_ON_ONCE(!atomic_long_inc_not_zero(&event->refcount)); did not trigger, it seems that __perf_event_overflow() is not called from perf_event_exit_task() path. > Did you mean to say something like: > > Because exit_task_work() now runs after perf_event_exit_task(), it is > possible for an already queued perf_pending_task()->perf_sigtrap() to > observe a dead task context. Yes. > Also, isn't it better to simply swap the early exit tests in that > function like so: Yes, that will be OK if you prefer it ( https://lkml.kernel.org/r/ed888189-dad4-47e1-bfc8-4f2213eda32d@I-love.SAKURA.ne.jp ).
Since exit_task_work() runs after perf_event_exit_task_context() updated
ctx->task to TASK_TOMBSTONE, perf_sigtrap() from perf_pending_task() might
observe event->ctx->task == TASK_TOMBSTONE.
Swap the early exit tests in order not to hit WARN_ON_ONCE().
Reported-by: syzbot <syzbot+2fe61cb2a86066be6985@syzkaller.appspotmail.com>
Closes: https://syzkaller.appspot.com/bug?extid=2fe61cb2a86066be6985
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
kernel/events/core.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 0db36b2b2448..22fdf0c187cd 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7204,18 +7204,18 @@ void perf_event_wakeup(struct perf_event *event)
static void perf_sigtrap(struct perf_event *event)
{
/*
- * We'd expect this to only occur if the irq_work is delayed and either
- * ctx->task or current has changed in the meantime. This can be the
- * case on architectures that do not implement arch_irq_work_raise().
+ * Both perf_pending_task() and perf_pending_irq() can race with the
+ * task exiting.
*/
- if (WARN_ON_ONCE(event->ctx->task != current))
+ if (current->flags & PF_EXITING)
return;
/*
- * Both perf_pending_task() and perf_pending_irq() can race with the
- * task exiting.
+ * We'd expect this to only occur if the irq_work is delayed and either
+ * ctx->task or current has changed in the meantime. This can be the
+ * case on architectures that do not implement arch_irq_work_raise().
*/
- if (current->flags & PF_EXITING)
+ if (WARN_ON_ONCE(event->ctx->task != current))
return;
send_sig_perf((void __user *)event->pending_addr,
--
2.47.1
The following commit has been merged into the perf/urgent branch of tip:
Commit-ID: 3da6bb419750f3ad834786d6ba7c9d5d062c770b
Gitweb: https://git.kernel.org/tip/3da6bb419750f3ad834786d6ba7c9d5d062c770b
Author: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
AuthorDate: Wed, 09 Jul 2025 20:27:52 +09:00
Committer: Peter Zijlstra <peterz@infradead.org>
CommitterDate: Wed, 09 Jul 2025 13:40:17 +02:00
perf/core: Fix WARN in perf_sigtrap()
Since exit_task_work() runs after perf_event_exit_task_context() updated
ctx->task to TASK_TOMBSTONE, perf_sigtrap() from perf_pending_task() might
observe event->ctx->task == TASK_TOMBSTONE.
Swap the early exit tests in order not to hit WARN_ON_ONCE().
Closes: https://syzkaller.appspot.com/bug?extid=2fe61cb2a86066be6985
Reported-by: syzbot <syzbot+2fe61cb2a86066be6985@syzkaller.appspotmail.com>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lkml.kernel.org/r/b1c224bd-97f9-462c-a3e3-125d5e19c983@I-love.SAKURA.ne.jp
---
kernel/events/core.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 0db36b2..22fdf0c 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -7204,18 +7204,18 @@ void perf_event_wakeup(struct perf_event *event)
static void perf_sigtrap(struct perf_event *event)
{
/*
- * We'd expect this to only occur if the irq_work is delayed and either
- * ctx->task or current has changed in the meantime. This can be the
- * case on architectures that do not implement arch_irq_work_raise().
+ * Both perf_pending_task() and perf_pending_irq() can race with the
+ * task exiting.
*/
- if (WARN_ON_ONCE(event->ctx->task != current))
+ if (current->flags & PF_EXITING)
return;
/*
- * Both perf_pending_task() and perf_pending_irq() can race with the
- * task exiting.
+ * We'd expect this to only occur if the irq_work is delayed and either
+ * ctx->task or current has changed in the meantime. This can be the
+ * case on architectures that do not implement arch_irq_work_raise().
*/
- if (current->flags & PF_EXITING)
+ if (WARN_ON_ONCE(event->ctx->task != current))
return;
send_sig_perf((void __user *)event->pending_addr,
Hello, syzbot has tested the proposed patch and the reproducer did not trigger any issue: Reported-by: syzbot+2fe61cb2a86066be6985@syzkaller.appspotmail.com Tested-by: syzbot+2fe61cb2a86066be6985@syzkaller.appspotmail.com Tested on: commit: a79a588f Merge tag 'pm-6.16-rc5' of git://git.kernel.o.. git tree: upstream console output: https://syzkaller.appspot.com/x/log.txt?x=13691c8c580000 kernel config: https://syzkaller.appspot.com/x/.config?x=a6dba31fc9bb876c dashboard link: https://syzkaller.appspot.com/bug?extid=2fe61cb2a86066be6985 compiler: Debian clang version 20.1.7 (++20250616065708+6146a88f6049-1~exp1~20250616065826.132), Debian LLD 20.1.7 patch: https://syzkaller.appspot.com/x/patch.diff?x=157a2582580000 Note: testing is done by a robot and is best-effort only.
© 2016 - 2025 Red Hat, Inc.