
Repositório de pesquisa para CVE-2025-38502, um acesso fora dos limites ao armazenamento local do cgroup BPF do kernel Linux via tail calls, permitindo escalonamento local de privilégios.

Abraxas Labs · abraxaslabs.tech · github.com/abraxas · @abraxas_null
Acesso fora dos limites ao armazenamento local de cgroup do BPF do kernel Linux via tail calls
| CVE | CVE-2025-38502 |
| CWE | CWE-125 — Leitura fora dos limites |
| Fornecedor | Linux kernel |
| Componente | kernel/bpf/core.c, include/linux/bpf.h (armazenamento local de cgroup + tail calls) |
| Impacto | Corrupção de memória local do kernel; escalonamento de privilégios está no escopo em kernels não corrigidos |
| Vetor de ataque | Local (AV:L) |
| Privilégios | Baixo (PR:L) — um processo capaz de carregar programas BPF do tipo CGROUP_SKB (ou programas equivalentes anexados a cgroup) |
| Interação do usuário | Nenhuma |
| 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 |
| Correção upstream | abad3d0 em 6.17-rc1; backport para 6.16.1, 6.12.46, 6.6.105, 6.1.151, 5.15.192 |
Apenas para pesquisa / uso educacional. Não execute, implante ou use o material deste repositório contra qualquer host, a menos que você tenha permissão explícita por escrito tanto da parte que hospeda este repositório quanto do proprietário dos sistemas-alvo. Encontrado em ambiente real.
O nome do arquivo de origem CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c trunca o identificador. O registro publicado é CVE-2025-38502. Não existe CVE do Linux CVE-2025-3850.
Lonial relatou que o armazenamento local de cgroup do BPF pode ser acessado fora dos limites através de uma tail call.
O verificador do eBPF faz a checagem de tipos de cada programa isoladamente. Em tempo de execução, bpf_get_local_storage() não consulta o mapa do programa atualmente em execução. Ele lê o ponteiro do armazenamento de cgroup de current->bpf_ctx → bpf_cg_run_ctx → prog_item->cgroup_storage[]. Esse slot é preenchido a partir do programa originalmente anexado, não do programa para o qual foi feita a tail call.
Se o programa A (com tamanho de valor pequeno em BPF_MAP_TYPE_CGROUP_STORAGE) faz uma tail call para o programa B (com tamanho de valor grande), o bpf_get_local_storage() de B ainda retorna o buffer menor de A. Os acessos que o verificador permitiu em relação ao mapa de B então ultrapassam o fim da alocação de A.
O defeito foi introduzido no Linux 5.9 por 7d9c342 (bpf: Make cgroup storages shared between programs on the same cgroup). Foi corrigido estendendo bpf_map_owner com um storage_cookie[], de modo que combinações de tail call só são aceitas quando o chamado usa os mesmos mapas de armazenamento de cgroup que o chamador, ou não usa nenhum.
Este é um acesso fora dos limites no heap do kernel local. A pontuação de severidade varia por fornecedor porque eles discordam sobre se a primitiva é “DoS somente leitura” ou corrupção total de memória:
| Fonte | Pontuação | Integridade | Notas |
|---|---|---|---|
| kernel.org CNA / cve.org | 7.8 ALTO | Alta | C:H/I:H/A:H — trata o bug como impacto local total |
| NVD | 7.1 ALTO | Nenhuma | C:H/I:N/A:H — confidencialidade + disponibilidade |
| Ubuntu | Médio (7.1) | — | USN-7909 |
| Red Hat | 4.0 BAIXO | Nenhuma | C:N/I:N/A:L — avaliado como disponibilidade limitada |
| Amazon Linux | 4.0 Médio | Nenhuma | mesmo vetor do Red Hat |
| SUSE | 6.1 Moderado | Nenhuma | alguns fluxos do SLE 15 marcados como WONTFIX |
O que isso significa na prática:
struct bpf_array pulverizado na mesma slab/ordem) podem ser corrompidos.map->ops, sequestrar um helper, commit_creds / troca de namespace). É por isso que esta árvore rotula o problema como LPE. A pontuação mais baixa do Red Hat reflete sua avaliação específica de produto, não a ausência do bug.O bug não exige um serviço exposto à rede. É local. Não exige um TTY, um helper setuid ou interação do usuário.
Dois programas BPF de cgroup, cada um com seu próprio BPF_MAP_TYPE_CGROUP_STORAGE (variante compartilhada, BPF_CGROUP_STORAGE_SHARED):
| Programa | Papel | Tamanho do valor de armazenamento |
|---|---|---|
| A | anexado / chamador da tail call | pequeno (por exemplo, cabe em uma dada ordem de kmalloc) |
| B | alvo da tail call | grande (o verificador permite acessos até esse tamanho) |
O verificador checa A em relação ao mapa de A e B em relação ao mapa de B. Ambos passam.
Em tempo de execução, o helper faz:
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 é a entrada do array para o programa que iniciou a execução do cgroup, não o programa atualmente em execução após bpf_tail_call. Portanto, B opera sobre o objeto de armazenamento de A.
bpf_cgroup_storage_alloc() dimensiona o buffer de suporte a partir do value_size do mapa. O buffer de A é pequeno demais para os acessos verificados de B. O resultado é uma clássica confusão de tipo da identidade do mapa através de uma transferência de controle — a mesma família de bugs de outros problemas de BPF em que “o helper vê um mapa diferente do que o verificador viu”.
O commit 7d9c342 tornou os armazenamentos de cgroup compartilhados entre programas anexados ao mesmo cgroup. Esse compartilhamento é o que faz o slot do contexto de execução ser um único ponteiro em vez de uma consulta por programa, e é por isso que kernels anteriores ao 5.9 não são afetados.