GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

CVE-2026-89791 (GCVE-0-2026-89791)

Vulnerability from cvelistv5 – Published: 2026-09-16 08:48 – Updated: 2026-09-16 14:38
VLAI
Title
perf: Fix use-after-free when perf mmap() revival races with the last munmap()
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 CPE status
Linux Linux Affected: 59741451b49ce9964a9758c19d6f7df2a1255c75 , < 929cb3b9dc818dd9fa89d510d4ff2b255e42badd (git)
Affected: 59741451b49ce9964a9758c19d6f7df2a1255c75 , < 0c739f54f1c77f3a4643160cd2e031b6c2f2aab6 (git)
Affected: 59741451b49ce9964a9758c19d6f7df2a1255c75 , < 58a8108bc73de0740d5b88150465d6690ea5f85f (git)
guessed Create a notification for this product.
Linux Linux Affected: 6.18
Unaffected: 0 , < 6.18 (semver)
Unaffected: 6.18.52 , ≤ 6.18.* (semver)
Unaffected: 7.2.5 , ≤ 7.2.* (semver)
Unaffected: 7.3-rc2 , ≤ * (original_commit_for_fix)
guessed 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-rc2",
              "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-rc2",
                  "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-09-16T14:38:40.190Z",
        "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-09-16T14:38:40.190Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-89791",
      "date": "2026-09-16",
      "epss": "0.00189",
      "percentile": "0.08736"
    },
    "nvd": "{\"cve\":{\"id\":\"CVE-2026-89791\",\"sourceIdentifier\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"published\":\"2026-09-16T09:17:09.930\",\"lastModified\":\"2026-09-16T15:18:09.253\",\"vulnStatus\":\"Received\",\"cveTags\":[],\"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.\"}],\"affected\":[{\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"affectedData\":[{\"vendor\":\"Linux\",\"product\":\"Linux\",\"defaultStatus\":\"unaffected\",\"programFiles\":[\"kernel/events/core.c\"],\"repo\":\"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\"versions\":[{\"version\":\"59741451b49ce9964a9758c19d6f7df2a1255c75\",\"lessThan\":\"929cb3b9dc818dd9fa89d510d4ff2b255e42badd\",\"versionType\":\"git\",\"status\":\"affected\"},{\"version\":\"59741451b49ce9964a9758c19d6f7df2a1255c75\",\"lessThan\":\"0c739f54f1c77f3a4643160cd2e031b6c2f2aab6\",\"versionType\":\"git\",\"status\":\"affected\"},{\"version\":\"59741451b49ce9964a9758c19d6f7df2a1255c75\",\"lessThan\":\"58a8108bc73de0740d5b88150465d6690ea5f85f\",\"versionType\":\"git\",\"status\":\"affected\"}]},{\"vendor\":\"Linux\",\"product\":\"Linux\",\"defaultStatus\":\"affected\",\"programFiles\":[\"kernel/events/core.c\"],\"repo\":\"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\"versions\":[{\"version\":\"6.18\",\"status\":\"affected\"},{\"version\":\"0\",\"lessThan\":\"6.18\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"6.18.52\",\"lessThanOrEqual\":\"6.18.*\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"7.2.5\",\"lessThanOrEqual\":\"7.2.*\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"7.3-rc2\",\"lessThanOrEqual\":\"*\",\"versionType\":\"original_commit_for_fix\",\"status\":\"unaffected\"}]}]}],\"metrics\":{\"cvssMetricV31\":[{\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"type\":\"Secondary\",\"cvssData\":{\"version\":\"3.1\",\"vectorString\":\"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H\",\"baseScore\":7.8,\"baseSeverity\":\"HIGH\",\"attackVector\":\"LOCAL\",\"attackComplexity\":\"LOW\",\"privilegesRequired\":\"LOW\",\"userInteraction\":\"NONE\",\"scope\":\"UNCHANGED\",\"confidentialityImpact\":\"HIGH\",\"integrityImpact\":\"HIGH\",\"availabilityImpact\":\"HIGH\"},\"exploitabilityScore\":1.8,\"impactScore\":5.9}]},\"references\":[{\"url\":\"https://git.kernel.org/stable/c/0c739f54f1c77f3a4643160cd2e031b6c2f2aab6\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/58a8108bc73de0740d5b88150465d6690ea5f85f\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/929cb3b9dc818dd9fa89d510d4ff2b255e42badd\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"}]}}",
    "suse_vex": {
      "aggregate_severity": "not set",
      "current_release_date": "2026-09-16T15:35:37Z",
      "cve": "CVE-2026-89791",
      "id": "CVE-2026-89791",
      "initial_release_date": "2026-09-16T15:35:37Z",
      "source": "SUSE CSAF VEX",
      "status": "interim",
      "title": "SUSE CVE CVE-2026-89791",
      "url": "https://ftp.suse.com/pub/projects/security/csaf-vex/cve-2026-89791.json",
      "version": "2"
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…