
Repositorio de investigación para CVE-2025-38502, un acceso fuera de límites en el almacenamiento local del cgroup BPF del kernel de Linux mediante tail calls que permite la escalada de privilegios local.

Abraxas Labs · abraxaslabs.tech · github.com/abraxas · @abraxas_null
Acceso fuera de límites al almacenamiento local de cgroup de BPF del kernel de Linux mediante tail calls
| CVE | CVE-2025-38502 |
| CWE | CWE-125 — Lectura fuera de límites |
| Fabricante | Linux kernel |
| Componente | kernel/bpf/core.c, include/linux/bpf.h (almacenamiento local de cgroup + tail calls) |
| Impacto | Corrupción de memoria del kernel local; la escalada de privilegios está dentro del alcance en kernels sin parchear |
| Vector de ataque | Local (AV:L) |
| Privilegios | Bajos (PR:L) — un proceso que puede cargar programas BPF de tipo CGROUP_SKB (o programas equivalentes adjuntos a cgroup) |
| Interacción del usuario | Ninguna |
| CVSS 3.1 (kernel.org CNA) | 7.8 ALTO — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| CVSS 3.1 (NVD) | 7.1 ALTO — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H |
| Público | 16 de agosto de 2025 |
| Corrección upstream | abad3d0 en 6.17-rc1; retroportado a 6.16.1, 6.12.46, 6.6.105, 6.1.151, 5.15.192 |
Solo para investigación / uso educativo. No ejecute, despliegue ni utilice el material de este repositorio contra ningún host a menos que tenga permiso escrito explícito tanto de la parte que aloja este repositorio como del propietario de los sistemas objetivo. Encontrado en estado salvaje.
El nombre del archivo fuente CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c trunca el identificador. El registro publicado es CVE-2025-38502. No existe un CVE de Linux CVE-2025-3850.
Lonial informó que el almacenamiento local de BPF de cgroup puede ser accedido fuera de límites a través de una tail call.
El verificador de eBPF comprueba los tipos de cada programa de forma aislada. En tiempo de ejecución, bpf_get_local_storage() no busca el mapa del programa que se está ejecutando actualmente. Lee el puntero del almacenamiento de cgroup desde current->bpf_ctx → bpf_cg_run_ctx → prog_item->cgroup_storage[]. Esa ranura se rellena desde el programa originalmente adjunto, no desde el programa al que se hizo la tail call.
Si el programa A (tamaño de valor pequeño de BPF_MAP_TYPE_CGROUP_STORAGE) hace una tail call al programa B (tamaño de valor grande), el bpf_get_local_storage() de B sigue devolviendo el búfer más pequeño de A. Los accesos que el verificador permitió contra el mapa de B entonces se salen del final de la asignación de A.
El defecto se introdujo en Linux 5.9 mediante 7d9c342 (bpf: Make cgroup storages shared between programs on the same cgroup). Se corrigió extendiendo bpf_map_owner con un storage_cookie[] para que las combinaciones de tail call solo se acepten cuando el destinatario usa los mismos mapas de almacenamiento de cgroup que el llamador, o no usa ninguno.
Este es un acceso fuera de límites al heap del kernel local. La puntuación de severidad varía según el proveedor porque no coinciden en si la primitiva es un "DoS de solo lectura" o una corrupción de memoria completa:
| Fuente | Puntuación | Integridad | Notas |
|---|---|---|---|
| kernel.org CNA / cve.org | 7.8 ALTO | Alta | C:H/I:H/A:H — trata el fallo como impacto local completo |
| NVD | 7.1 ALTO | Ninguna | C:H/I:N/A:H — confidencialidad + disponibilidad |
| Ubuntu | Medio (7.1) | — | USN-7909 |
| Red Hat | 4.0 BAJO | Ninguna | C:N/I:N/A:L — calificado como disponibilidad limitada |
| Amazon Linux | 4.0 Medio | Ninguna | mismo vector que Red Hat |
| SUSE | 6.1 Moderado | Ninguna | algunos flujos de SLE 15 marcados como WONTFIX |
Qué significa esto en la práctica:
struct bpf_array rociado en el mismo slab/orden) pueden corromperse.map->ops, secuestrar un helper, commit_creds / cambio de namespace). Por eso este árbol etiqueta el problema como LPE. La puntuación más baja de Red Hat refleja su evaluación específica del producto, no la ausencia del fallo.El fallo no requiere un servicio expuesto a la red. Es local. No requiere una TTY, un helper setuid ni interacción del usuario.
Dos programas BPF de cgroup, cada uno con su propio BPF_MAP_TYPE_CGROUP_STORAGE (variante compartida, BPF_CGROUP_STORAGE_SHARED):
| Programa | Rol | Tamaño del valor de almacenamiento |
|---|---|---|
| A | adjunto / llamador de tail call | pequeño (p. ej., cabe en un orden de kmalloc dado) |
| B | objetivo de tail call | grande (el verificador permite accesos hasta este tamaño) |
El verificador comprueba A contra el mapa de A y B contra el mapa de B. Ambos pasan.
En tiempo de ejecución el helper hace:
ctx = container_of(current->bpf_ctx, struct bpf_cg_run_ctx, run_ctx);
storage = ctx->prog_item->cgroup_storage[stype];
if (stype == BPF_CGROUP_STORAGE_SHARED)
ptr = &READ_ONCE(storage->buf)->data[0];
else
ptr = this_cpu_ptr(storage->percpu_buf);
prog_item es la entrada del array para el programa que inició la ejecución del cgroup, no el programa que se está ejecutando actualmente tras bpf_tail_call. Por lo tanto, B opera sobre el objeto de almacenamiento de A.
bpf_cgroup_storage_alloc() dimensiona el búfer de respaldo a partir del value_size del mapa. El búfer de A es demasiado pequeño para los accesos verificados de B. El resultado es una clásica confusión de tipos de la identidad del mapa a través de una transferencia de control — la misma familia de fallos que otros problemas de BPF en los que "el helper ve un mapa diferente al que vio el verificador".
El commit 7d9c342 hizo que los almacenamientos de cgroup fueran compartidos entre programas adjuntos al mismo cgroup. Esa compartición es lo que hace que la ranura del contexto de ejecución sea un único puntero en lugar de una búsqueda por programa, y es por lo que los kernels anteriores a 5.9 no se ven afectados.