From: sashiko-bot@kernel.org
To: "Daehyeon Ko" <4ncienth@gmail.com>
Cc: linux-perf-users@vger.kernel.org
Subject: Re: [PATCH v2] perf/core: Close owner-list publication race with remove-on-exec
Date: Sat, 17 Oct 2026 15:25:28 +0000 [thread overview]
Message-ID: <sashiko-outbox-175581@kernel.org> (raw)
In-Reply-To: <20261017150747.1119197-1-4ncienth@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] perf/core: unpinning ctx before owner_entry link allows fork/swap exec race
--
commit 32e21b1610ca28e8fe922d31bdbd5f0a4a31607c
Author: Daehyeon Ko <4ncienth@gmail.com>
perf/core: Close owner-list publication race with remove-on-exec
This commit keeps the target task's exec_update_lock held in perf_event_open()
until event->owner_entry is added to current->perf_event_list, preventing a
concurrent target exec from running perf_remove_from_owner() on an unlinked
owner_entry.
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 7846d70be57f6..2fdd8d71dcd55 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -14246,15 +14246,15 @@ SYSCALL_DEFINE5(perf_event_open,
>
> mutex_unlock(&ctx->mutex);
>
> + mutex_lock(¤t->perf_event_mutex);
> + list_add_tail(&event->owner_entry, ¤t->perf_event_list);
> + mutex_unlock(¤t->perf_event_mutex);
> +
> if (task) {
> up_read(&task->signal->exec_update_lock);
> put_task_struct(task);
> }
>
> - mutex_lock(¤t->perf_event_mutex);
> - list_add_tail(&event->owner_entry, ¤t->perf_event_list);
> - mutex_unlock(¤t->perf_event_mutex);
> -
> /*
> * File reference in group guarantees that group_leader has been
> * kept alive until we place the new event on the sibling_list.
[Severity: Critical]
Can the same owner_entry race still happen if the target task forks and the
child execs before list_add_tail() runs?
In SYSCALL_DEFINE5(perf_event_open) in kernel/events/core.c, ctx is unpinned
and ctx->mutex is unlocked before event->owner_entry is linked onto
current->perf_event_list:
event->owner = current;
perf_install_in_context(ctx, event, event->cpu);
perf_unpin_context(ctx);
mutex_unlock(&ctx->mutex);
mutex_lock(¤t->perf_event_mutex);
list_add_tail(&event->owner_entry, ¤t->perf_event_list);
mutex_unlock(¤t->perf_event_mutex);
Holding task->signal->exec_update_lock only blocks execve() on task's own
signal_struct. It does not prevent task from calling fork(), which runs
copy_process() -> perf_event_init_task() -> perf_event_init_context() without
taking task->signal->exec_update_lock and allocates a new signal_struct with a
separate unlocked exec_update_lock for the child.
When an event is opened with attr.remove_on_exec = 1 and attr.inherit = 1,
perf_event_init_context() acquires ctx->mutex, inherits the event into
child_ctx, and marks child_ctx as a clone of ctx. Because perf_unpin_context()
already dropped ctx->pin_count to 0, context_equiv() allows the context swap
optimization:
kernel/events/core.c:context_equiv() {
/* Pinning disables the swap optimization */
if (ctx1->pin_count || ctx2->pin_count)
return 0;
}
When switching from task to the newly forked child,
perf_event_context_sched_out() can then swap the unpinned original ctx onto the
child task:
kernel/events/core.c:perf_event_context_sched_out() {
WRITE_ONCE(ctx->task, next);
WRITE_ONCE(next_ctx->task, task);
perf_ctx_sched_task_cb(ctx, task, false);
perf_ctx_enable(ctx, 0);
RCU_INIT_POINTER(task->perf_event_ctxp, next_ctx);
RCU_INIT_POINTER(next->perf_event_ctxp, ctx);
}
At that point, the original ctx containing the parent event (with
event->owner == current and event->owner_entry still {NULL, NULL}) belongs to
the child process. If the child immediately calls execve() under its own
child->signal->exec_update_lock, begin_new_exec() -> perf_event_exec() ->
perf_event_remove_on_exec() iterates the swapped ctx->event_list:
kernel/events/core.c:perf_event_remove_on_exec() {
list_for_each_entry_safe(event, next, &ctx->event_list, event_entry) {
if (!event->attr.remove_on_exec)
continue;
if (!is_kernel_event(event))
perf_remove_from_owner(event);
}
Wouldn't this allow perf_remove_from_owner(event) to run before the opener
executes list_add_tail(&event->owner_entry, ¤t->perf_event_list), hitting
the same list_del_init() corruption or use-after-free on
current->perf_event_list?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261017150747.1119197-1-4ncienth@gmail.com?part=1
prev parent reply other threads:[~2026-10-17 15:25 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-15 12:34 [PATCH] perf/core: Close owner-list publication race with remove-on-exec Daehyeon Ko
2026-10-15 12:45 ` sashiko-bot
2026-10-16 8:45 ` Peter Zijlstra
2026-10-17 15:07 ` [PATCH v2] " Daehyeon Ko
2026-10-17 15:25 ` sashiko-bot [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-175581@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=4ncienth@gmail.com \
--cc=linux-perf-users@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox