---
id: CVE-2026-89791
title: |-
  In the Linux kernel, the following vulnerability has been resolved:

  perf: Fix use-after-free when perf mmap() revival races with the last munmap()

  perf_mmap_close() drops rb->mmap_count *without* holding
  event->mmap_mutex (the refcount…
summary: |-
  In the Linux kernel, the following vulnerability has been resolved:

  perf: Fix use-after-free when perf mmap() revival races with the last munmap()

  perf_mmap_close() drops rb->mmap_count *without* holding
  event->mmap_mutex (the refcount…
severity: high
cvss: 7.8
cvssVector: 'CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H'
vendor: Linux
product: Linux
affected:
  - >-
    Linux >= 59741451b49ce9964a9758c19d6f7df2a1255c75 <
    929cb3b9dc818dd9fa89d510d4ff2b255e42badd
  - >-
    Linux >= 59741451b49ce9964a9758c19d6f7df2a1255c75 <
    0c739f54f1c77f3a4643160cd2e031b6c2f2aab6
  - >-
    Linux >= 59741451b49ce9964a9758c19d6f7df2a1255c75 <
    58a8108bc73de0740d5b88150465d6690ea5f85f
  - Linux 6.18
published: '2026-09-16'
updated: '2026-09-16'
sourceUpdated: '2026-09-16T15:18:09.253'
source: NVD
sourceUrl: 'https://nvd.nist.gov/vuln/detail/CVE-2026-89791'
references:
  - url: 'https://git.kernel.org/stable/c/0c739f54f1c77f3a4643160cd2e031b6c2f2aab6'
    label: 416baaa9-dc9f-4396-8d5f-8c081fb06d67
  - url: 'https://git.kernel.org/stable/c/58a8108bc73de0740d5b88150465d6690ea5f85f'
    label: 416baaa9-dc9f-4396-8d5f-8c081fb06d67
  - url: 'https://git.kernel.org/stable/c/929cb3b9dc818dd9fa89d510d4ff2b255e42badd'
    label: 416baaa9-dc9f-4396-8d5f-8c081fb06d67
tags:
  - nvd
  - cve.org
ingestedAt: '2026-09-16T08:52:29.592Z'
epss: 0.0016
epssPercentile: 0.04509
---

## Overview

In the Linux kernel, the following vulnerability has been resolved:

perf: Fix use-after-free when perf mmap() revival races with the last munmap()

perf_mmap_close() drops rb->mmap_count *without* holding
event->mmap_mutex (the refcount_dec_and_test() right before the
refcount_dec_and_mutex_lock() of event->mmap_count). A concurrent
perf_mmap_rb() can slot its entire "revival" path into that window
(perf_mmap holds event->mmap_mutex for its whole duration, including
rb_alloc):

  munmap side (perf_mmap_close)          mmap side (perf_mmap_rb)
  -----------------------------------    --------------------------------
  rb->mmap_count 1 -> 0   (no lock)      (holds event->mmap_mutex)
                                         inc_not_zero(rb->mmap_count) fails
                                         ring_buffer_attach(event, NULL)
                                         rb_alloc() + attach new rb
                                         refcount_set(&event->mmap_count, 1)
  lock; event->mmap_count 1 -> 0
  ring_buffer_attach(event, NULL)
  ring_buffer_put() -> frees the *new* rb

The revival's refcount_set(&event->mmap_count, 1) is an invisible
1 -> 1 write: the close frees the just-revived buffer although the
other process still has it mapped -- a page-level use-after-free
allowing local privilege escalation to root by any unprivileged user
(default kernel.perf_event_paranoid=2).

Swap the order of the two counter updates: event->mmap_count is
dropped first via refcount_dec_and_mutex_lock(), so its 1 -> 0
transition and the ring_buffer_attach() stay serialized with
perf_mmap(). rb->mmap_count == 0 then implies every event using the
buffer is detached already, so the result of the rb->mmap_count drop
can gate the remaining teardown directly and detach_rest is no longer
needed.

An earlier fix for this race from Kyle Zeng and David Lee takes
event->mmap_mutex around both counter updates [0]; here the not-last
close stays lockless.

## Remediation

Refer to the linked advisories for vendor-supplied fixes and affected version ranges.
