CVE-2026-98507

Estado: RecibidaSin puntuar—
Gravedad—Sin puntuar
Probabilidad de explotación0.20 %mayor que el 9 % de las CVE
Explotación activaNono figura en el catálogo de CISA
Exploit públicoNo conocidosin código público localizado

En el kernel de Linux, se ha resuelto la siguiente vulnerabilidad:

mm/rmap: corregir la barrera de memoria que falta entre la inicialización de anon_vma y la publicación de vma->anon_vma

En un servidor arm64, observamos que una tarea que intenta obtener el bloqueo de anon_vma activa hungtask.

Tras analizar el vmcore, comprobamos que anon_vma->root->rwsem.count vale -1. Hay otro anon_vma cuyo anon_vma->root->rwsem.count vale 1, y anon_vma->root->rwsem.owner indica que el bloqueo está retenido, pero la pila de la tarea muestra que la tarea no retiene el bloqueo de anon_vma.

Tras añadir más información de depuración, descubrimos que __anon_vma_prepare() reutiliza anon_vma y provoca un UAF de anon_vma->root debido a la falta de una barrera de memoria, lo que lleva a bloquear y desbloquear dos anon_vma->root distintos; por tanto, un anon_vma nunca se desbloquea y otro anon_vma ya no puede bloquearse.

Leer descripción completaMostrar menos

Esta condición de carrera requiere dos VMA adyacentes que no se fusionan, pero que son compatibles con anon_vma (por ejemplo, difieren en VMA_ACCESS_FLAGS, que pueden cambiar mediante mprotect()). Dos hilos provocan un fallo en cada VMA de forma concurrente, y ambos llaman a __anon_vma_prepare() manteniendo solo mmap_lock en modo de lectura.

El hilo A provoca un fallo de página y llama a __anon_vma_prepare() para preparar anon_vma para la VMA que provoca el fallo. __anon_vma_prepare() reserva e inicializa un nuevo anon_vma y, a continuación, lo publica en la VMA mediante una escritura simple. anon_vma_prepare() solo requiere que mmap_lock se mantenga en modo de lectura, por lo que dos hilos pueden provocar fallos en VMA adyacentes al mismo tiempo. Mientras el hilo A publica un nuevo anon_vma, el hilo B podría encontrar dicho anon_vma mediante find_mergeable_anon_vma() y bloquear entonces anon_vma->root->rwsem.

La escritura en anon_vma->root en anon_vma_alloc() y la escritura en vma->anon_vma pueden reordenarse. anon_vma_lock_write() y spin_lock() solo proporcionan semántica de adquisición (acquire), que no impide que las escrituras anteriores se reordenen después de ellas. La semántica de liberación (release) de los correspondientes spin_unlock() y anon_vma_unlock_write() llega demasiado tarde: la escritura en vma->anon_vma ya se ha publicado antes de que surtan efecto. En consecuencia, el hilo B puede observar el siguiente orden:

La caché de anon_vma utiliza SLAB_TYPESAFE_BY_RCU, por lo que un anon_vma recién asignado puede reutilizar memoria de otro liberado previamente. El constructor (anon_vma_ctor) no restablece anon_vma->root, y __put_anon_vma() tampoco lo borra, de modo que el valor antiguo de root persiste hasta que anon_vma_alloc() lo sobrescribe. Si esa escritura no v ---truncado---

Detalles técnicos trazas, registros y código del informe original
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

    HILO A                               HILO B
__anon_vma_prepare                __anon_vma_prepare
 find_mergeable_anon_vma() -> NULL
 anon_vma = anon_vma_alloc();
   anon_vma->root = anon_vma;
 // las dos escrituras pueden reordenarse
 vma->anon_vma = anon_vma;
                                   // encuentra el anon_vma de A
                                   anon_vma = find_mergeable_anon_vma(vma);
                                   anon_vma_lock_write(anon_vma);
                                     // puede seguir viendo la raíz antigua
                                     down_write(&anon_vma->root->rwsem);
                                   anon_vma_unlock_write(anon_vma);
                                     // ve la nueva raíz y nunca desbloquea la antigua
                                     up_write(&anon_vma->root->rwsem);

    vma->anon_vma = anon_vma;
    anon_vma->root = anon_vma;

Traducción automática del texto original de NVD (en inglés).

CVSS

NVD no ha asignado puntuación CVSS a esta CVE (habitual desde el cambio de política de abril de 2026).

Probabilidad de explotación (EPSS)

Probabilidad de explotación en los próximos 30 días
0.20 %
Percentil entre todas las CVEs puntuadas
9
Fecha de la puntuación
20/10/2026

EPSS (Exploit Prediction Scoring System, de FIRST) estima la probabilidad de que una vulnerabilidad sea explotada en 30 días. Complementa a CVSS (impacto) y a CISA KEV (explotación confirmada).

Tecnologías afectadas (1)

⚠ Inferidas por IA a partir de la descripción — NVD aún no ha analizado esta CVE; no son CPE verificados.

Referencias

Mostrar las 4 referencias

JSON original (NVD)

Mostrar
{
  "id": "CVE-2026-98507",
  "cveTags": [],
  "metrics": {},
  "affected": [
    {
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
      "affectedData": [
        {
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "product": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "lessThan": "a500df43cde075f6ea4b8bae495d89f2c35b3e16",
              "versionType": "git"
            },
            {
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "lessThan": "4cef512a955e4008ae4436a4fc97726976df1fdf",
              "versionType": "git"
            },
            {
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "lessThan": "d348a715380bfcc6a611bdf722169d53fd01e735",
              "versionType": "git"
            },
            {
              "status": "affected",
              "version": "5c341ee1dfc8fe69d66b1c8b19e463c6d7201ae1",
              "lessThan": "b6ac0b3f6013c168f22cad97e79967accacb08e1",
              "versionType": "git"
            }
          ],
          "programFiles": [
            "mm/rmap.c",
            "mm/vma.c"
          ],
          "defaultStatus": "unaffected"
        },
        {
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "product": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "2.6.36"
            },
            {
              "status": "unaffected",
              "version": "0",
              "lessThan": "2.6.36",
              "versionType": "semver"
            },
            {
              "status": "unaffected",
              "version": "6.12.112",
              "versionType": "semver",
              "lessThanOrEqual": "6.12.*"
            },
            {
              "status": "unaffected",
              "version": "6.18.55",
              "versionType": "semver",
              "lessThanOrEqual": "6.18.*"
            },
            {
              "status": "unaffected",
              "version": "7.2.9",
              "versionType": "semver",
              "lessThanOrEqual": "7.2.*"
            },
            {
              "status": "unaffected",
              "version": "7.3",
              "versionType": "original_commit_for_fix",
              "lessThanOrEqual": "*"
            }
          ],
          "programFiles": [
            "mm/rmap.c",
            "mm/vma.c"
          ],
          "defaultStatus": "affected"
        }
      ]
    }
  ],
  "published": "2026-10-18T16:17:01.817",
  "references": [
    {
      "url": "https://git.kernel.org/stable/c/4cef512a955e4008ae4436a4fc97726976df1fdf",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    },
    {
      "url": "https://git.kernel.org/stable/c/a500df43cde075f6ea4b8bae495d89f2c35b3e16",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    },
    {
      "url": "https://git.kernel.org/stable/c/b6ac0b3f6013c168f22cad97e79967accacb08e1",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    },
    {
      "url": "https://git.kernel.org/stable/c/d348a715380bfcc6a611bdf722169d53fd01e735",
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    }
  ],
  "vulnStatus": "Received",
  "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->anon_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 > /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->root->rwsem.count is\n-1.  There is another anon_vma whose anon_vma->root->rwsem.count is 1, the\nanon_vma->root->rwsem.owner shows the lock is held, but the stack of the\ntask shows the task doesn't 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->root due to missing memory\nbarrier, leading to locking and unlocking two different anon_vma->root,\nthus leading to an anon_vma will never be unlocked, and another anon_vma\ncouldn't 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() -> NULL\n anon_vma = anon_vma_alloc();\n   anon_vma->root = anon_vma;\n // the two stores may be reordered\n vma->anon_vma = anon_vma;\n                                   // finds A's 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(&anon_vma->root->rwsem);\n                                   anon_vma_unlock_write(anon_vma);\n                                     // see the new root, never unlock old\n                                     up_write(&anon_vma->root->rwsem);\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->root->rwsem.\n\nThe store to anon_vma->root in anon_vma_alloc() and the store to\nvma->anon_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->anon_vma is already published before they take effect.  As a result,\nthread B can observe the following order:\n\n    vma->anon_vma = anon_vma;\n    anon_vma->root = 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->root, and __put_anon_vma()\ndoesn't clear it either, so the old root value persists until\nanon_vma_alloc() overwrites it.  If that store isn't v\n---truncated---"
    }
  ],
  "lastModified": "2026-10-19T10:19:04.000",
  "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
}