52 lines
1.8 KiB
Diff
52 lines
1.8 KiB
Diff
From 5948aaf64f81f217a25dcc2bf6c0779bca19566c Mon Sep 17 00:00:00 2001
|
|
From: Lee Jia Jie <jiajie.lee@starlabs.sg>
|
|
Date: Thu, 9 Jul 2026 21:56:19 +0800
|
|
Subject: [PATCH] perf/aux: Fix page UAF in map_range()
|
|
|
|
map_range() reads rb->aux_pages[], rb->aux_nr_pages and rb->aux_pgoff via
|
|
perf_mmap_to_page() while holding only event->mmap_mutex. Those fields are
|
|
serialized by rb->aux_mutex, and mmap_mutex is per event.
|
|
|
|
Thus, two events sharing one rb via PERF_EVENT_IOC_SET_OUTPUT can race
|
|
rb_alloc_aux() with map_range(), leading to a page-UAF scenario as follows:
|
|
|
|
CPU 0 CPU 1
|
|
===== =====
|
|
rb_alloc_aux() map_range()
|
|
[1]: allocate rb->aux_pages[0]
|
|
[2]: rb->aux_nr_pages++
|
|
[3]: perf_mmap_to_page()
|
|
returns rb->aux_pages[0]
|
|
[4]: map it as VM_PFNMAP
|
|
[5]: rb->aux_pgoff = 1
|
|
|
|
munmap the page
|
|
[6]: free rb->aux_pages[0]
|
|
|
|
Pages mapped as VM_PFNMAP have no refcount protection, so CPU 1 holds a
|
|
mapping to a freed physical frame.
|
|
|
|
Fix this by taking rb->aux_mutex across the page walk in map_range().
|
|
|
|
Fixes: b709eb872e19 ("perf: map pages in advance")
|
|
Signed-off-by: Lee Jia Jie <jiajie.lee@starlabs.sg>
|
|
Signed-off-by: Ingo Molnar <mingo@kernel.org>
|
|
Cc: stable@vger.kernel.org
|
|
Cc: Peter Zijlstra <peterz@infradead.org>
|
|
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Cc: Namhyung Kim <namhyung@kernel.org>
|
|
|
|
diff --git a/kernel/events/core.c b/kernel/events/core.c
|
|
index 43cee52..e2e7bb8 100644
|
|
--- a/kernel/events/core.c
|
|
+++ b/kernel/events/core.c
|
|
@@ -6896,6 +6896,8 @@ static int map_range(struct perf_buffer *rb, struct vm_area_struct *vma)
|
|
int err = 0;
|
|
unsigned long pagenum;
|
|
|
|
+ guard(mutex)(&rb->aux_mutex);
|
|
+
|
|
/*
|
|
* We map this as a VM_PFNMAP VMA.
|
|
*
|