mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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: 506e64e710 ("perf: attach/detach PMU specific data")
Signed-off-by: Lee Jia Jie <mkofdwu@gmail.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
This commit is contained in:
parent
2b774b5bbf
commit
64ea0e8226
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user