diff options
| author | Lee Jia Jie <mkofdwu@gmail.com> | 2026-10-22 20:58:48 +0800 |
|---|---|---|
| committer | Peter Zijlstra <peterz@infradead.org> | 2026-10-23 19:09:52 +0200 |
| commit | 64ea0e8226ed98d14e0231af1beae10c3d5c043a (patch) | |
| tree | 30b9ff888eba4d6c32748f0dc54374f4ae198543 /kernel | |
| parent | 2b774b5bbffabae7ac6be98a98e9641fb3c0bbb4 (diff) | |
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 <mkofdwu@gmail.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/events/core.c | 3 |
1 files changed, 3 insertions, 0 deletions
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); |
