CVE-2026-89791 (GCVE-0-2026-89791)
Vulnerability from cvelistv5
Published
2026-09-16 08:48
Modified
2026-10-19 08:52
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_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.
Impacted products
Vendor Product Version
Linux Linux Version: 59741451b49ce9964a9758c19d6f7df2a1255c75
Version: 59741451b49ce9964a9758c19d6f7df2a1255c75
Version: 59741451b49ce9964a9758c19d6f7df2a1255c75
Create a notification for this product.
Show details on NVD website


{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "kernel/events/core.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "929cb3b9dc818dd9fa89d510d4ff2b255e42badd",
              "status": "affected",
              "version": "59741451b49ce9964a9758c19d6f7df2a1255c75",
              "versionType": "git"
            },
            {
              "lessThan": "0c739f54f1c77f3a4643160cd2e031b6c2f2aab6",
              "status": "affected",
              "version": "59741451b49ce9964a9758c19d6f7df2a1255c75",
              "versionType": "git"
            },
            {
              "lessThan": "58a8108bc73de0740d5b88150465d6690ea5f85f",
              "status": "affected",
              "version": "59741451b49ce9964a9758c19d6f7df2a1255c75",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "kernel/events/core.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "6.18"
            },
            {
              "lessThan": "6.18",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.18.*",
              "status": "unaffected",
              "version": "6.18.52",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "7.2.*",
              "status": "unaffected",
              "version": "7.2.5",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "7.3",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.18.52",
                  "versionStartIncluding": "6.18",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.2.5",
                  "versionStartIncluding": "6.18",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.3",
                  "versionStartIncluding": "6.18",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nperf: Fix use-after-free when perf mmap() revival races with the last munmap()\n\nperf_mmap_close() drops rb-\u003emmap_count *without* holding\nevent-\u003emmap_mutex (the refcount_dec_and_test() right before the\nrefcount_dec_and_mutex_lock() of event-\u003emmap_count). A concurrent\nperf_mmap_rb() can slot its entire \"revival\" path into that window\n(perf_mmap holds event-\u003emmap_mutex for its whole duration, including\nrb_alloc):\n\n  munmap side (perf_mmap_close)          mmap side (perf_mmap_rb)\n  -----------------------------------    --------------------------------\n  rb-\u003emmap_count 1 -\u003e 0   (no lock)      (holds event-\u003emmap_mutex)\n                                         inc_not_zero(rb-\u003emmap_count) fails\n                                         ring_buffer_attach(event, NULL)\n                                         rb_alloc() + attach new rb\n                                         refcount_set(\u0026event-\u003emmap_count, 1)\n  lock; event-\u003emmap_count 1 -\u003e 0\n  ring_buffer_attach(event, NULL)\n  ring_buffer_put() -\u003e frees the *new* rb\n\nThe revival\u0027s refcount_set(\u0026event-\u003emmap_count, 1) is an invisible\n1 -\u003e 1 write: the close frees the just-revived buffer although the\nother process still has it mapped -- a page-level use-after-free\nallowing local privilege escalation to root by any unprivileged user\n(default kernel.perf_event_paranoid=2).\n\nSwap the order of the two counter updates: event-\u003emmap_count is\ndropped first via refcount_dec_and_mutex_lock(), so its 1 -\u003e 0\ntransition and the ring_buffer_attach() stay serialized with\nperf_mmap(). rb-\u003emmap_count == 0 then implies every event using the\nbuffer is detached already, so the result of the rb-\u003emmap_count drop\ncan gate the remaining teardown directly and detach_rest is no longer\nneeded.\n\nAn earlier fix for this race from Kyle Zeng and David Lee takes\nevent-\u003emmap_mutex around both counter updates [0]; here the not-last\nclose stays lockless."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "baseScore": 7.8,
            "baseSeverity": "HIGH",
            "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
            "version": "3.1"
          },
          "scenarios": [
            {
              "lang": "en",
              "value": "AV:L - The UAF is reached only via local syscalls: perf_event_open(2) then mmap(2)/munmap(2) on the resulting perf fd (perf_fops.mmap \u2192 perf_mmap \u2192 perf_mmap_rb racing perf_mmap_close). There is no network, adjacent-radio, or physical path into the ring-buffer revival race.\nAC:L - The attacker drives both sides from threads or processes sharing the fd: one munmap() runs perf_mmap_close() while a concurrent mmap() holds event-\u003emmap_mutex through rb_alloc() and map_range(). That is an attacker-controlled, freely retryable race, not an uninfluenced layout or victim-state condition.\nPR:L - Default kernel.perf_event_paranoid=2 still allows an unprivileged per-task software event with exclude_kernel set; perf_mmap() only calls the optional LSM security_perf_event_read hook and does not require CAP_PERFMON or CAP_SYS_ADMIN. The fix notes local privilege escalation by any unprivileged user.\nUI:N - The attacker opens the event and races mmap/munmap on that fd in their own process or a helper that inherited the fd. No victim action such as mounting a filesystem or opening a file is required.\nS:U - Impact is host-kernel page use-after-free of the perf ring buffer, i.e. standard local privilege escalation in the same OS security authority. It is not a KVM/Xen guest-to-host escape or IOMMU/DMA boundary bypass.\nC:H - perf_mmap_close() frees the revived ring-buffer pages (rb_free) while the concurrent mmap\u0027s VM_PFNMAP VMA still maps those PFNs. That page-level UAF lets the attacker reclaim the pages and read arbitrary kernel memory through the still-valid mapping.\nI:H - The same still-mapped PFNs remain writable on the user control page (perf_mmap_pfn_mkwrite), so reclaim/spray of the freed pages yields a kernel write primitive. The fix commit describes this as local privilege escalation to root, matching UAF integrity High.\nA:H - Use-after-free of the ring buffer while it remains mapped causes kernel oops or panic on reuse, and the reporters documented a panic reproducer. Any kernel UAF is availability High even without a completed privilege-escalation exploit."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-10-19T08:52:45.122Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/929cb3b9dc818dd9fa89d510d4ff2b255e42badd"
        },
        {
          "url": "https://git.kernel.org/stable/c/0c739f54f1c77f3a4643160cd2e031b6c2f2aab6"
        },
        {
          "url": "https://git.kernel.org/stable/c/58a8108bc73de0740d5b88150465d6690ea5f85f"
        }
      ],
      "title": "perf: Fix use-after-free when perf mmap() revival races with the last munmap()",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2026-89791",
    "datePublished": "2026-09-16T08:48:27.020Z",
    "dateReserved": "2026-09-11T19:38:34.766Z",
    "dateUpdated": "2026-10-19T08:52:45.122Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
  • Confirmed: The vulnerability is confirmed from an analyst perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
  • Patched: This vulnerability was successfully patched by the user reporting the sighting.
  • Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
  • Not confirmed: The user expresses doubt about the veracity of the vulnerability.
  • Not patched: This vulnerability was not successfully patched by the user reporting the sighting.


Loading…

Loading…