Re: [PATCH] perf: Fix deadlock in perf_mmap()

From: Ian Rogers

Date: Mon Mar 09 2026 - 15:00:22 EST


On Mon, Mar 9, 2026 at 1:26 AM Qing Wang <wangqing7171@xxxxxxxxx> wrote:
>
> There is a possible deadlock in perf_mmap() if mmap_range() fails then
> perf_mmap_close() is called while holding event->mmap_mutex. Since
> perf_mmap_close() also acquire the same mutex, this result in self-deadlock.
>
> Fix this by moving the cleanup(perf_mmap_close()) outside the scope of
> scoped_guard(mutex, &event->mmap_mutex).
>
> Fixes: 77de62ad3de3 ("perf/core: Fix refcount bug and potential UAF in perf_mmap")
> Reported-by: syzbot+196a82fd904572696b3c@xxxxxxxxxxxxxxxxxxxxxxxxx
> Closes: https://syzkaller.appspot.com/bug?extid=196a82fd904572696b3c
> Signed-off-by: Qing Wang <wangqing7171@xxxxxxxxx>

Hi Qing, thank you for looking into this. I proposed a similar fix:
https://lore.kernel.org/lkml/CAP-5=fW-wHEv=TCULwk_HVOhWHdqRd8AZoESZsU_vnhLjghUBQ@xxxxxxxxxxxxxx/
but Haocheng noted it reintroduced the race condition the original fix
was targeting. Haocheng has a larger fix in:
https://lore.kernel.org/lkml/20260306093616.84299-1-yuhaocheng035@xxxxxxxxx/
that should handle both the original race condition and the deadlock.
I wonder that fix may be made smaller by passing a parameter like
"holds_event_mmap_mutex" to perf_mmap_close, something like:
```
static void __perf_mmap_close(struct vm_area_struct *vma, struct
perf_event *event, bool holds_event_mmap_lock)
{
... // code from original perf_mmap_close
if ((!holds_event_mmap_lock &&
!refcount_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex))
||
(holds_event_mmap_lock && !refcount_dec_and_test(&event->mmap_count)))
...

static void perf_mmap_close(struct vm_area_struct *vma)
{
struct perf_event *event = vma->vm_file->private_data;
__perf_mmap_close(vma, event, /*holds_event_mmap_lock=*/false);
}

static void perf_mmap_close_locked(struct vm_area_struct *vma, struct
perf_event *event)
{
__perf_mmap_close(vma, event, /*holds_event_mmap_lock=*/true);
}
```

Thanks,
Ian

> ---
> kernel/events/core.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 1f5699b339ec..e5ce03ce926d 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -7485,9 +7485,12 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
> */
> ret = map_range(event->rb, vma);
> if (ret)
> - perf_mmap_close(vma);
> + goto out_close;
> }
> + return 0;
>
> +out_close:
> + perf_mmap_close(vma);
> return ret;
> }
>
> --
> 2.34.1
>