From 2b774b5bbffabae7ac6be98a98e9641fb3c0bbb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 21 Oct 2026 10:18:22 +0200 Subject: [PATCH 1/3] alpha: add simd_enabled argument to perf_reg_validate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Align the alpha function with the generic function signature. The alpha function was added in commit 9280e99d87dd ("alpha: add HAVE_PERF_REGS and HAVE_PERF_USER_STACK_DUMP support") while the generic function signature was changed in commit a2c64c74c029 ("perf: Enhance perf_reg_validate() with simd_enabled argument"). After both commits landed in Linus' tree the signatures now differ, resulting in a build error: arch/alpha/kernel/perf_regs.c:46:5: error: conflicting types for 'perf_reg_validate'; have 'int(u64)' {aka 'int(long long unsigned int)'} 46 | int perf_reg_validate(u64 mask) | ^~~~~~~~~~~~~~~~~ In file included from include/linux/perf_event.h:50, from arch/alpha/kernel/perf_regs.c:4: include/linux/perf_regs.h:13:5: note: previous declaration of 'perf_reg_validate' with type 'int(u64, bool)' {aka 'int(long long unsigned int, _Bool)'} 13 | int perf_reg_validate(u64 mask, bool simd_enabled); | ^~~~~~~~~~~~~~~~~ Add the missing argument. Fixes: 742f62b63904 ("Merge tag 'alpha-for-v7.4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/lindholm/alpha") Signed-off-by: Thomas Weißschuh Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Magnus Lindholm Tested-by: Magnus Lindholm Link: https://patch.msgid.link/20261021-alpha-perf_reg_validate-v1-1-a8e8cc23ea7a@linutronix.de --- arch/alpha/kernel/perf_regs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/alpha/kernel/perf_regs.c b/arch/alpha/kernel/perf_regs.c index 33ea2e831ba0..c5a55bfa15a5 100644 --- a/arch/alpha/kernel/perf_regs.c +++ b/arch/alpha/kernel/perf_regs.c @@ -43,7 +43,7 @@ u64 perf_reg_value(struct pt_regs *regs, int idx) return *(unsigned long *)((void *)regs + pt_regs_offset[idx]); } -int perf_reg_validate(u64 mask) +int perf_reg_validate(u64 mask, bool simd_enabled) { if (!mask || mask & REG_RESERVED) return -EINVAL; From 64ea0e8226ed98d14e0231af1beae10c3d5c043a Mon Sep 17 00:00:00 2001 From: Lee Jia Jie Date: Thu, 22 Oct 2026 20:58:48 +0800 Subject: [PATCH 2/3] perf: Fix UAF in attach_task_ctx_data() struct perf_ctx_data is RCU protected. In attach_task_ctx_data(), the cmpxchg retry loop runs without holding rcu_read_lock(). If task->perf_ctx_data already holds a pointer (call it `cd1`), then try_cmpxchg(&task->perf_ctx_data, &old, cd) fails and loads old = cd1. A concurrent thread running detach_task_ctx_data() could free cd1 leading to UAF and further memory corruption when cd1 is reclaimed by another thread. CPU 0: attach_task_ctx_data() CPU 1: detach_task_ctx_data() ----------------------------- ----------------------------- try_cmpxchg(&task->perf_ctx_data, &old, cd2) -> fails; loads old = cd1 refcount_dec_and_test(&cd1->refcount) try_cmpxchg(&task->perf_ctx_data, &cd1, NULL) perf_free_ctx_data_rcu(cd1) [ RCU grace period -> kfree(cd1) ] refcount_inc_not_zero(&old->refcount) -> UAF on freed cd1 Fix this by taking rcu_read_lock across the race window. Fixes: 506e64e710ff ("perf: attach/detach PMU specific data") Signed-off-by: Lee Jia Jie Signed-off-by: Peter Zijlstra (Intel) --- kernel/events/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index a9ee91151b2d..e248f34f7b66 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5434,6 +5434,9 @@ attach_task_ctx_data(struct task_struct *task, struct kmem_cache *ctx_cache, return -ENOMEM; for (;;) { + /* Protect @old until inc_not_zero(&old->refcount) */ + guard(rcu)(); + if (try_cmpxchg(&task->perf_ctx_data, &old, cd)) { if (old) perf_free_ctx_data_rcu(old); From d095321349222961813333277881b3c74f10b17b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 14 Oct 2026 14:45:51 +0200 Subject: [PATCH 3/3] perf: Fix perf_remove_from_context() event scheduling Q8 noted that it is possible to get into an inconsistent state when using perf_remove_from_context() on a group leader event. Specifically, when the leader gets scheduled out, we should (when not destroying the grouping) schedule out the complete group, similar to __perf_event_disable(). Reported-by: Q8 Tested-by: Q8 Signed-off-by: Peter Zijlstra (Intel) --- kernel/events/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index e248f34f7b66..f36a3bbaa33c 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2590,6 +2590,7 @@ __perf_remove_from_context(struct perf_event *event, enum perf_event_state state = PERF_EVENT_STATE_OFF; unsigned long flags = (unsigned long)info; + perf_pmu_disable(pmu_ctx->pmu); ctx_time_update(cpuctx, ctx); /* @@ -2603,6 +2604,13 @@ __perf_remove_from_context(struct perf_event *event, if (flags & DETACH_DEAD) state = PERF_EVENT_STATE_DEAD; + /* + * When disabling a group leader, the whole group becomes ineligible + * to run, so schedule out the full group. + */ + if (!(flags & DETACH_GROUP) && event == event->group_leader) + group_sched_out(event, ctx); + __event_disable(event, ctx, state); if (flags & DETACH_GROUP) @@ -2632,6 +2640,7 @@ __perf_remove_from_context(struct perf_event *event, cpuctx->task_ctx = NULL; } } + perf_pmu_enable(pmu_ctx->pmu); } /*