CVE-2025-38554 (GCVE-0-2025-38554)
Vulnerability from cvelistv5
Published
2025-08-19 17:02
Modified
2025-08-19 17:02
Severity ?
VLAI Severity ?
EPSS score ?
Summary
In the Linux kernel, the following vulnerability has been resolved:
mm: fix a UAF when vma->mm is freed after vma->vm_refcnt got dropped
By inducing delays in the right places, Jann Horn created a reproducer for
a hard to hit UAF issue that became possible after VMAs were allowed to be
recycled by adding SLAB_TYPESAFE_BY_RCU to their cache.
Race description is borrowed from Jann's discovery report:
lock_vma_under_rcu() looks up a VMA locklessly with mas_walk() under
rcu_read_lock(). At that point, the VMA may be concurrently freed, and it
can be recycled by another process. vma_start_read() then increments the
vma->vm_refcnt (if it is in an acceptable range), and if this succeeds,
vma_start_read() can return a recycled VMA.
In this scenario where the VMA has been recycled, lock_vma_under_rcu()
will then detect the mismatching ->vm_mm pointer and drop the VMA through
vma_end_read(), which calls vma_refcount_put(). vma_refcount_put() drops
the refcount and then calls rcuwait_wake_up() using a copy of vma->vm_mm.
This is wrong: It implicitly assumes that the caller is keeping the VMA's
mm alive, but in this scenario the caller has no relation to the VMA's mm,
so the rcuwait_wake_up() can cause UAF.
The diagram depicting the race:
T1 T2 T3
== == ==
lock_vma_under_rcu
mas_walk
<VMA gets removed from mm>
mmap
<the same VMA is reallocated>
vma_start_read
__refcount_inc_not_zero_limited_acquire
munmap
__vma_enter_locked
refcount_add_not_zero
vma_end_read
vma_refcount_put
__refcount_dec_and_test
rcuwait_wait_event
<finish operation>
rcuwait_wake_up [UAF]
Note that rcuwait_wait_event() in T3 does not block because refcount was
already dropped by T1. At this point T3 can exit and free the mm causing
UAF in T1.
To avoid this we move vma->vm_mm verification into vma_start_read() and
grab vma->vm_mm to stabilize it before vma_refcount_put() operation.
[surenb@google.com: v3]
References
Impacted products
{ "containers": { "cna": { "affected": [ { "defaultStatus": "unaffected", "product": "Linux", "programFiles": [ "include/linux/mmap_lock.h", "mm/mmap_lock.c" ], "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "vendor": "Linux", "versions": [ { "lessThan": "6e88fe54721dee17d3496bc998f0c7d243896348", "status": "affected", "version": "3104138517fc66aad21f4a2487bb572e9fc2e3ec", "versionType": "git" }, { "lessThan": "1bcd236a2536a451e385f8d6d2bb589689ec812f", "status": "affected", "version": "3104138517fc66aad21f4a2487bb572e9fc2e3ec", "versionType": "git" }, { "lessThan": "9bbffee67ffd16360179327b57f3b1245579ef08", "status": "affected", "version": "3104138517fc66aad21f4a2487bb572e9fc2e3ec", "versionType": "git" } ] }, { "defaultStatus": "affected", "product": "Linux", "programFiles": [ "include/linux/mmap_lock.h", "mm/mmap_lock.c" ], "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "vendor": "Linux", "versions": [ { "status": "affected", "version": "6.15" }, { "lessThan": "6.15", "status": "unaffected", "version": "0", "versionType": "semver" }, { "lessThanOrEqual": "6.15.*", "status": "unaffected", "version": "6.15.10", "versionType": "semver" }, { "lessThanOrEqual": "6.16.*", "status": "unaffected", "version": "6.16.1", "versionType": "semver" }, { "lessThanOrEqual": "*", "status": "unaffected", "version": "6.17-rc1", "versionType": "original_commit_for_fix" } ] } ], "cpeApplicability": [ { "nodes": [ { "cpeMatch": [ { "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionEndExcluding": "6.15.10", "versionStartIncluding": "6.15", "vulnerable": true }, { "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionEndExcluding": "6.16.1", "versionStartIncluding": "6.15", "vulnerable": true }, { "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionEndExcluding": "6.17-rc1", "versionStartIncluding": "6.15", "vulnerable": true } ], "negate": false, "operator": "OR" } ] } ], "descriptions": [ { "lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nmm: fix a UAF when vma-\u003emm is freed after vma-\u003evm_refcnt got dropped\n\nBy inducing delays in the right places, Jann Horn created a reproducer for\na hard to hit UAF issue that became possible after VMAs were allowed to be\nrecycled by adding SLAB_TYPESAFE_BY_RCU to their cache.\n\nRace description is borrowed from Jann\u0027s discovery report:\nlock_vma_under_rcu() looks up a VMA locklessly with mas_walk() under\nrcu_read_lock(). At that point, the VMA may be concurrently freed, and it\ncan be recycled by another process. vma_start_read() then increments the\nvma-\u003evm_refcnt (if it is in an acceptable range), and if this succeeds,\nvma_start_read() can return a recycled VMA.\n\nIn this scenario where the VMA has been recycled, lock_vma_under_rcu()\nwill then detect the mismatching -\u003evm_mm pointer and drop the VMA through\nvma_end_read(), which calls vma_refcount_put(). vma_refcount_put() drops\nthe refcount and then calls rcuwait_wake_up() using a copy of vma-\u003evm_mm. \nThis is wrong: It implicitly assumes that the caller is keeping the VMA\u0027s\nmm alive, but in this scenario the caller has no relation to the VMA\u0027s mm,\nso the rcuwait_wake_up() can cause UAF.\n\nThe diagram depicting the race:\nT1 T2 T3\n== == ==\nlock_vma_under_rcu\n mas_walk\n \u003cVMA gets removed from mm\u003e\n mmap\n \u003cthe same VMA is reallocated\u003e\n vma_start_read\n __refcount_inc_not_zero_limited_acquire\n munmap\n __vma_enter_locked\n refcount_add_not_zero\n vma_end_read\n vma_refcount_put\n __refcount_dec_and_test\n rcuwait_wait_event\n \u003cfinish operation\u003e\n rcuwait_wake_up [UAF]\n\nNote that rcuwait_wait_event() in T3 does not block because refcount was\nalready dropped by T1. At this point T3 can exit and free the mm causing\nUAF in T1.\n\nTo avoid this we move vma-\u003evm_mm verification into vma_start_read() and\ngrab vma-\u003evm_mm to stabilize it before vma_refcount_put() operation.\n\n[surenb@google.com: v3]" } ], "providerMetadata": { "dateUpdated": "2025-08-19T17:02:33.315Z", "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "shortName": "Linux" }, "references": [ { "url": "https://git.kernel.org/stable/c/6e88fe54721dee17d3496bc998f0c7d243896348" }, { "url": "https://git.kernel.org/stable/c/1bcd236a2536a451e385f8d6d2bb589689ec812f" }, { "url": "https://git.kernel.org/stable/c/9bbffee67ffd16360179327b57f3b1245579ef08" } ], "title": "mm: fix a UAF when vma-\u003emm is freed after vma-\u003evm_refcnt got dropped", "x_generator": { "engine": "bippy-1.2.0" } } }, "cveMetadata": { "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "assignerShortName": "Linux", "cveId": "CVE-2025-38554", "datePublished": "2025-08-19T17:02:33.315Z", "dateReserved": "2025-04-16T04:51:24.025Z", "dateUpdated": "2025-08-19T17:02:33.315Z", "state": "PUBLISHED" }, "dataType": "CVE_RECORD", "dataVersion": "5.1", "vulnerability-lookup:meta": { "nvd": "{\"cve\":{\"id\":\"CVE-2025-38554\",\"sourceIdentifier\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"published\":\"2025-08-19T17:15:31.510\",\"lastModified\":\"2025-08-20T14:40:17.713\",\"vulnStatus\":\"Awaiting Analysis\",\"cveTags\":[],\"descriptions\":[{\"lang\":\"en\",\"value\":\"In the Linux kernel, the following vulnerability has been resolved:\\n\\nmm: fix a UAF when vma-\u003emm is freed after vma-\u003evm_refcnt got dropped\\n\\nBy inducing delays in the right places, Jann Horn created a reproducer for\\na hard to hit UAF issue that became possible after VMAs were allowed to be\\nrecycled by adding SLAB_TYPESAFE_BY_RCU to their cache.\\n\\nRace description is borrowed from Jann\u0027s discovery report:\\nlock_vma_under_rcu() looks up a VMA locklessly with mas_walk() under\\nrcu_read_lock(). At that point, the VMA may be concurrently freed, and it\\ncan be recycled by another process. vma_start_read() then increments the\\nvma-\u003evm_refcnt (if it is in an acceptable range), and if this succeeds,\\nvma_start_read() can return a recycled VMA.\\n\\nIn this scenario where the VMA has been recycled, lock_vma_under_rcu()\\nwill then detect the mismatching -\u003evm_mm pointer and drop the VMA through\\nvma_end_read(), which calls vma_refcount_put(). vma_refcount_put() drops\\nthe refcount and then calls rcuwait_wake_up() using a copy of vma-\u003evm_mm. \\nThis is wrong: It implicitly assumes that the caller is keeping the VMA\u0027s\\nmm alive, but in this scenario the caller has no relation to the VMA\u0027s mm,\\nso the rcuwait_wake_up() can cause UAF.\\n\\nThe diagram depicting the race:\\nT1 T2 T3\\n== == ==\\nlock_vma_under_rcu\\n mas_walk\\n \u003cVMA gets removed from mm\u003e\\n mmap\\n \u003cthe same VMA is reallocated\u003e\\n vma_start_read\\n __refcount_inc_not_zero_limited_acquire\\n munmap\\n __vma_enter_locked\\n refcount_add_not_zero\\n vma_end_read\\n vma_refcount_put\\n __refcount_dec_and_test\\n rcuwait_wait_event\\n \u003cfinish operation\u003e\\n rcuwait_wake_up [UAF]\\n\\nNote that rcuwait_wait_event() in T3 does not block because refcount was\\nalready dropped by T1. At this point T3 can exit and free the mm causing\\nUAF in T1.\\n\\nTo avoid this we move vma-\u003evm_mm verification into vma_start_read() and\\ngrab vma-\u003evm_mm to stabilize it before vma_refcount_put() operation.\\n\\n[surenb@google.com: v3]\"},{\"lang\":\"es\",\"value\":\"En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad: mm: se corrige un UAF cuando vma-\u0026gt;mm se libera despu\u00e9s de que vma-\u0026gt;vm_refcnt se eliminara. Al inducir retrasos en los lugares adecuados, Jann Horn cre\u00f3 un reproductor para un problema de UAF dif\u00edcil de alcanzar que se hizo posible despu\u00e9s de que se permitiera reciclar los VMA agregando SLAB_TYPESAFE_BY_RCU a su cach\u00e9. La descripci\u00f3n de la ejecuci\u00f3n se tom\u00f3 prestada del informe de descubrimiento de Jann: lock_vma_under_rcu() busca un VMA sin bloqueo con mas_walk() bajo rcu_read_lock(). En ese punto, el VMA puede liberarse simult\u00e1neamente y puede reciclarse por otro proceso. vma_start_read() luego incrementa vma-\u0026gt;vm_refcnt (si est\u00e1 en un rango aceptable) y, si esto tiene \u00e9xito, vma_start_read() puede devolver un VMA reciclado. En este escenario, donde el VMA se ha reciclado, lock_vma_under_rcu() detectar\u00e1 el puntero -\u0026gt;vm_mm no coincidente y eliminar\u00e1 el VMA mediante vma_end_read(), que llama a vma_refcount_put(). vma_refcount_put() elimina el recuento de referencias y luego llama a rcuwait_wake_up() usando una copia de vma-\u0026gt;vm_mm. Esto es incorrecto: asume impl\u00edcitamente que quien llama mantiene activo el mm del VMA, pero en este escenario, quien llama no tiene relaci\u00f3n con el mm del VMA, por lo que rcuwait_wake_up() puede causar UAF. El diagrama que representa la ejecuci\u00f3n: T1 T2 T3 == == == lock_vma_under_rcu mas_walk mmap vma_start_read __refcount_inc_not_zero_limited_acquire munmap __vma_enter_locked refcount_add_not_zero vma_end_read vma_refcount_put __refcount_dec_and_test rcuwait_wait_event rcuwait_wake_up [UAF] Tenga en cuenta que rcuwait_wait_event() en T3 no se bloquea porque refcount ya fue descartado por T1. En este punto, T3 puede salir y liberar el mm que causa UAF en T1. Para evitar esto, movemos la verificaci\u00f3n vma-\u0026gt;vm_mm a vma_start_read() y tomamos vma-\u0026gt;vm_mm para estabilizarlo antes de la operaci\u00f3n vma_refcount_put(). [surenb@google.com: v3]\"}],\"metrics\":{},\"references\":[{\"url\":\"https://git.kernel.org/stable/c/1bcd236a2536a451e385f8d6d2bb589689ec812f\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/6e88fe54721dee17d3496bc998f0c7d243896348\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/9bbffee67ffd16360179327b57f3b1245579ef08\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"}]}}" } }
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.
- 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…