CVE-2026-98507 (GCVE-0-2026-98507)
Vulnerability from cvelistv5
Published
2026-10-18 15:17
Modified
2026-10-24 14:09
Summary
In the Linux kernel, the following vulnerability has been resolved: mm/rmap: fix missing barrier between anon_vma init and vma->anon_vma publish On arm64 server, we find that a task trying to grab the anon_vma lock triggers hungtask. INFO: task main:2354726 blocked for more than 120 seconds. Tainted: G E 5.10.0-0021.aarch64 #1 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. task:main state:D stack: 0 pid:2354726 ppid:2350673 flags:0x00000a01 Call trace: __switch_to+0x7c/0xbc __schedule+0x3b4/0x8a0 schedule+0x50/0xe0 rwsem_down_write_slowpath+0x3cc/0x6cc down_write+0x60/0x260 __anon_vma_prepare+0x6c/0x210 do_anonymous_page+0x258/0x660 handle_pte_fault+0x188/0x214 __handle_mm_fault+0x1b0/0x380 handle_mm_fault+0xf4/0x284 do_page_fault+0x19c/0x494 do_translation_fault+0xcc/0xf8 do_mem_abort+0x48/0xac el0_da+0x44/0x80 el0_sync_handler+0x88/0xb4 el0_sync+0x160/0x180 After analyzing the vmcore, we found the anon_vma->root->rwsem.count is -1. There is another anon_vma whose anon_vma->root->rwsem.count is 1, the anon_vma->root->rwsem.owner shows the lock is held, but the stack of the task shows the task doesn't hold the anon_vma lock. After adding more debugging info, we found __anon_vma_prepare() reuses anon_vma and triggers the UAF of anon_vma->root due to missing memory barrier, leading to locking and unlocking two different anon_vma->root, thus leading to an anon_vma will never be unlocked, and another anon_vma couldn't be locked anymore. This race requires two adjacent VMAs that are not merged but are anon_vma-compatible (e.g., they differ in VMA_ACCESS_FLAGS that can be changed by mprotect()). Two threads fault on each VMA concurrently, both calling __anon_vma_prepare() with only mmap_lock held for reading. THREAD A THREAD B __anon_vma_prepare __anon_vma_prepare find_mergeable_anon_vma() -> NULL anon_vma = anon_vma_alloc(); anon_vma->root = anon_vma; // the two stores may be reordered vma->anon_vma = anon_vma; // finds A's anon_vma anon_vma = find_mergeable_anon_vma(vma); anon_vma_lock_write(anon_vma); // may still see the old root down_write(&anon_vma->root->rwsem); anon_vma_unlock_write(anon_vma); // see the new root, never unlock old up_write(&anon_vma->root->rwsem); thread A triggers page fault and calls __anon_vma_prepare() to prepare anon_vma for the faulting vma. __anon_vma_prepare() allocates and initializes a new anon_vma, and then publishes it to the vma with a plain store. anon_vma_prepare() only requires the mmap_lock to be held for reading, so two threads can fault on adjacent VMAs at the same time. While thread A publishes a new anon_vma, thread B could find the anon_vma via find_mergeable_anon_vma() and then locks anon_vma->root->rwsem. The store to anon_vma->root in anon_vma_alloc() and the store to vma->anon_vma can be reordered. The anon_vma_lock_write() and spin_lock() only provide acquire semantics, which do not prevent prior stores from being reordered after them. The release semantics of the corresponding spin_unlock() and anon_vma_unlock_write() come too late, the store to vma->anon_vma is already published before they take effect. As a result, thread B can observe the following order: vma->anon_vma = anon_vma; anon_vma->root = anon_vma; The anon_vma slab is SLAB_TYPESAFE_BY_RCU, so a newly allocated anon_vma may reuse memory from a previously freed one. The constructor (anon_vma_ctor) does not reset anon_vma->root, and __put_anon_vma() doesn't clear it either, so the old root value persists until anon_vma_alloc() overwrites it. If that store isn't v ---truncated---
Impacted products
Vendor Product Version
Linux Linux Version: 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1
Version: 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1
Version: 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1
Version: 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1
Version: 5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1
Create a notification for this product.
Show details on NVD website


{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "mm/rmap.c",
            "mm/vma.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "465e222815c8839445d09028fa4c77e70f7f1c7d",
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "versionType": "git"
            },
            {
              "lessThan": "a500df43cde075f6ea4b8bae495d89f2c35b3e16",
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "versionType": "git"
            },
            {
              "lessThan": "4cef512a955e4008ae4436a4fc97726976df1fdf",
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "versionType": "git"
            },
            {
              "lessThan": "d348a715380bfcc6a611bdf722169d53fd01e735",
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "versionType": "git"
            },
            {
              "lessThan": "b6ac0b3f6013c168f22cad97e79967accacb08e1",
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "mm/rmap.c",
            "mm/vma.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "2.6.36"
            },
            {
              "lessThan": "2.6.36",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.6.*",
              "status": "unaffected",
              "version": "6.6.160",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.12.*",
              "status": "unaffected",
              "version": "6.12.112",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.18.*",
              "status": "unaffected",
              "version": "6.18.55",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "7.2.*",
              "status": "unaffected",
              "version": "7.2.9",
              "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.6.160",
                  "versionStartIncluding": "2.6.36",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.12.112",
                  "versionStartIncluding": "2.6.36",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.18.55",
                  "versionStartIncluding": "2.6.36",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.2.9",
                  "versionStartIncluding": "2.6.36",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.3",
                  "versionStartIncluding": "2.6.36",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nmm/rmap: fix missing barrier between anon_vma init and vma-\u003eanon_vma publish\n\nOn arm64 server, we find that a task trying to grab the anon_vma lock\ntriggers hungtask.\n\nINFO: task main:2354726 blocked for more than 120 seconds.\n      Tainted: G            E     5.10.0-0021.aarch64 #1\n\"echo 0 \u003e /proc/sys/kernel/hung_task_timeout_secs\" disables this message.\ntask:main            state:D stack:    0 pid:2354726 ppid:2350673 flags:0x00000a01\nCall trace:\n __switch_to+0x7c/0xbc\n __schedule+0x3b4/0x8a0\n schedule+0x50/0xe0\n rwsem_down_write_slowpath+0x3cc/0x6cc\n down_write+0x60/0x260\n __anon_vma_prepare+0x6c/0x210\n do_anonymous_page+0x258/0x660\n handle_pte_fault+0x188/0x214\n __handle_mm_fault+0x1b0/0x380\n handle_mm_fault+0xf4/0x284\n do_page_fault+0x19c/0x494\n do_translation_fault+0xcc/0xf8\n do_mem_abort+0x48/0xac\n el0_da+0x44/0x80\n el0_sync_handler+0x88/0xb4\n el0_sync+0x160/0x180\n\nAfter analyzing the vmcore, we found the anon_vma-\u003eroot-\u003erwsem.count is\n-1.  There is another anon_vma whose anon_vma-\u003eroot-\u003erwsem.count is 1, the\nanon_vma-\u003eroot-\u003erwsem.owner shows the lock is held, but the stack of the\ntask shows the task doesn\u0027t hold the anon_vma lock.\n\nAfter adding more debugging info, we found __anon_vma_prepare() reuses\nanon_vma and triggers the UAF of anon_vma-\u003eroot due to missing memory\nbarrier, leading to locking and unlocking two different anon_vma-\u003eroot,\nthus leading to an anon_vma will never be unlocked, and another anon_vma\ncouldn\u0027t be locked anymore.\n\nThis race requires two adjacent VMAs that are not merged but are\nanon_vma-compatible (e.g., they differ in VMA_ACCESS_FLAGS that can be\nchanged by mprotect()).  Two threads fault on each VMA concurrently, both\ncalling __anon_vma_prepare() with only mmap_lock held for reading.\n\n    THREAD A                             THREAD B\n__anon_vma_prepare                __anon_vma_prepare\n find_mergeable_anon_vma() -\u003e NULL\n anon_vma = anon_vma_alloc();\n   anon_vma-\u003eroot = anon_vma;\n // the two stores may be reordered\n vma-\u003eanon_vma = anon_vma;\n                                   // finds A\u0027s anon_vma\n                                   anon_vma = find_mergeable_anon_vma(vma);\n                                   anon_vma_lock_write(anon_vma);\n                                     // may still see the old root\n                                     down_write(\u0026anon_vma-\u003eroot-\u003erwsem);\n                                   anon_vma_unlock_write(anon_vma);\n                                     // see the new root, never unlock old\n                                     up_write(\u0026anon_vma-\u003eroot-\u003erwsem);\n\nthread A triggers page fault and calls __anon_vma_prepare() to prepare\nanon_vma for the faulting vma.  __anon_vma_prepare() allocates and\ninitializes a new anon_vma, and then publishes it to the vma with a plain\nstore.  anon_vma_prepare() only requires the mmap_lock to be held for\nreading, so two threads can fault on adjacent VMAs at the same time. \nWhile thread A publishes a new anon_vma, thread B could find the anon_vma\nvia find_mergeable_anon_vma() and then locks anon_vma-\u003eroot-\u003erwsem.\n\nThe store to anon_vma-\u003eroot in anon_vma_alloc() and the store to\nvma-\u003eanon_vma can be reordered.  The anon_vma_lock_write() and spin_lock()\nonly provide acquire semantics, which do not prevent prior stores from\nbeing reordered after them.  The release semantics of the corresponding\nspin_unlock() and anon_vma_unlock_write() come too late, the store to\nvma-\u003eanon_vma is already published before they take effect.  As a result,\nthread B can observe the following order:\n\n    vma-\u003eanon_vma = anon_vma;\n    anon_vma-\u003eroot = anon_vma;\n\nThe anon_vma slab is SLAB_TYPESAFE_BY_RCU, so a newly allocated anon_vma\nmay reuse memory from a previously freed one.  The constructor\n(anon_vma_ctor) does not reset anon_vma-\u003eroot, and __put_anon_vma()\ndoesn\u0027t clear it either, so the old root value persists until\nanon_vma_alloc() overwrites it.  If that store isn\u0027t v\n---truncated---"
        }
      ],
      "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 - A local memory fault reaches patched __anon_vma_prepare() via do_mem_abort() \u2192 do_page_fault() \u2192 handle_mm_fault() \u2192 __handle_mm_fault() \u2192 handle_pte_fault() \u2192 do_anonymous_page() \u2192 __vmf_anon_prepare(); no network data enters this path.\nAC:L - The attacker can use mprotect() to create adjacent unmerged VMAs differing in VMA_ACCESS_FLAGS, groom stale non-self roots through fork/exit, and concurrently fault both VMAs. They control both sides of the reusable_anon_vma() race and can retry the weak-memory window.\nPR:L - mmap(), mprotect(), fork()/clone(), and faults on the caller\u0027s own mappings require no capability; neither __vmf_anon_prepare() nor __anon_vma_prepare() performs a credential check. An ordinary unprivileged local process can reach the flaw.\nUI:N - The attacking process creates the VMA layout, grooms the anon_vma cache, and drives both concurrent faults itself; no action by another user is required.\nS:U - The stale root dereference and rwsem corruption occur in the host kernel\u0027s anon_vma memory-management state reached from the attacker\u0027s process; no VM, IOMMU, or other security-authority boundary is crossed.\nC:H - reusable_anon_vma() can return a newly allocated SLAB_TYPESAFE_BY_RCU object while its root still names a freed prior anon_vma, after which anon_vma_lock_write() dereferences the stale root-\u003erwsem. Same-cache grooming therefore provides a use-after-free read over recycled kernel object state.\nI:H - down_write() writes count and owner state through the freed or reallocated old root, while anon_vma_unlock_write() rereads the initialized root and up_write() corrupts that different semaphore, as demonstrated by counts 1 and -1. These are cross-object UAF writes into a groomable kernel slab.\nA:H - The mismatched down_write()/up_write() leaves the old anon_vma root permanently locked and underflows the new root\u0027s rwsem count, producing the reported uninterruptible hung task in __anon_vma_prepare(); repeated poisoned roots can block further faults and rmap operations."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-10-24T14:09:10.482Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/465e222815c8839445d09028fa4c77e70f7f1c7d"
        },
        {
          "url": "https://git.kernel.org/stable/c/a500df43cde075f6ea4b8bae495d89f2c35b3e16"
        },
        {
          "url": "https://git.kernel.org/stable/c/4cef512a955e4008ae4436a4fc97726976df1fdf"
        },
        {
          "url": "https://git.kernel.org/stable/c/d348a715380bfcc6a611bdf722169d53fd01e735"
        },
        {
          "url": "https://git.kernel.org/stable/c/b6ac0b3f6013c168f22cad97e79967accacb08e1"
        }
      ],
      "title": "mm/rmap: fix missing barrier between anon_vma init and vma-\u003eanon_vma publish",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2026-98507",
    "datePublished": "2026-10-18T15:17:13.767Z",
    "dateReserved": "2026-09-25T10:25:14.354Z",
    "dateUpdated": "2026-10-24T14:09:10.482Z",
    "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…