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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.