
Dépôt de recherche pour CVE-2025-38502, une vulnérabilité de type accès hors limites dans le stockage local du cgroup BPF du noyau Linux via des tail calls permettant une élévation de privilèges locale.

Abraxas Labs · abraxaslabs.tech · github.com/abraxas · @abraxas_null
Accès hors limites au stockage local de cgroup BPF du noyau Linux via des tail calls
| CVE | CVE-2025-38502 |
| CWE | CWE-125 — Lecture hors limites |
| Éditeur | Noyau Linux |
| Composant | kernel/bpf/core.c, include/linux/bpf.h (stockage local de cgroup + tail calls) |
| Impact | Corruption de mémoire du noyau locale ; l'élévation de privilèges est dans le périmètre sur les noyaux non corrigés |
| Vecteur d'attaque | Local (AV:L) |
| Privilèges | Faibles (PR:L) — un processus capable de charger des programmes BPF de type CGROUP_SKB (ou des programmes équivalents attachés à un cgroup) |
| Interaction utilisateur | Aucune |
| CVSS 3.1 (kernel.org CNA) | 7.8 ÉLEVÉ — 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 ÉLEVÉ — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H |
| Public | 16 août 2025 |
| Correctif amont | abad3d0 dans 6.17-rc1 ; rétroporté vers 6.16.1, 6.12.46, 6.6.105, 6.1.151, 5.15.192 |
Usage recherche / éducatif uniquement. N'exécutez, ne déployez et n'utilisez le contenu de ce dépôt contre aucun hôte sans autorisation écrite explicite de la part à la fois de la partie hébergeant ce dépôt et du propriétaire des systèmes cibles. Trouvé dans la nature.
Le nom de fichier source CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c tronque l'identifiant. L'enregistrement publié est CVE-2025-38502. Il n'existe pas de CVE Linux CVE-2025-3850.
Lonial a signalé que le stockage local de cgroup BPF peut être accédé hors limites à travers un tail call.
Le vérificateur eBPF effectue la vérification de type de chaque programme isolément. À l'exécution, bpf_get_local_storage() ne recherche pas la map du programme en cours d'exécution. Il lit le pointeur de stockage de cgroup depuis current->bpf_ctx → bpf_cg_run_ctx → prog_item->cgroup_storage[]. Cet emplacement est rempli à partir du programme initialement attaché, et non du programme vers lequel un tail call a été effectué.
Si le programme A (petite taille de valeur BPF_MAP_TYPE_CGROUP_STORAGE) effectue un tail call vers le programme B (grande taille de valeur), le bpf_get_local_storage() de B renvoie toujours le plus petit tampon de A. Les accès que le vérificateur a autorisés par rapport à la map de B dépassent alors la fin de l'allocation de A.
Le défaut a été introduit dans Linux 5.9 par 7d9c342 (bpf: Make cgroup storages shared between programs on the same cgroup). Il a été corrigé en étendant bpf_map_owner avec un storage_cookie[] afin que les combinaisons de tail calls ne soient acceptées que lorsque le programme appelé utilise les mêmes maps de stockage de cgroup que l'appelant, ou n'en utilise aucune.
Il s'agit d'un accès hors limites au tas du noyau local. Le score de gravité varie selon l'éditeur car ils ne sont pas d'accord sur le fait que la primitive soit un « DoS en lecture seule » ou une corruption mémoire complète :
| Source | Score | Intégrité | Notes |
|---|---|---|---|
| kernel.org CNA / cve.org | 7.8 ÉLEVÉ | Élevée | C:H/I:H/A:H — traite le bug comme un impact local complet |
| NVD | 7.1 ÉLEVÉ | Aucune | C:H/I:N/A:H — confidentialité + disponibilité |
| Ubuntu | Moyen (7.1) | — | USN-7909 |
| Red Hat | 4.0 FAIBLE | Aucune | C:N/I:N/A:L — évalué comme disponibilité limitée |
| Amazon Linux | 4.0 Moyen | Aucune | même vecteur que Red Hat |
| SUSE | 6.1 Modéré | Aucune | certains flux SLE 15 marqués WONTFIX |
Ce que cela signifie en pratique :
struct bpf_array pulvérisé dans le même slab/ordre) peuvent être corrompus.map->ops, détournement d'un helper, commit_creds / changement d'espace de noms). C'est pourquoi cette arborescence étiquette le problème comme LPE. Le score plus faible de Red Hat reflète leur évaluation spécifique au produit, et non l'absence du bug.Le bug ne nécessite pas de service exposé au réseau. Il est local. Il ne nécessite pas de TTY, d'helper setuid, ni d'interaction utilisateur.
Deux programmes BPF de cgroup, chacun avec son propre BPF_MAP_TYPE_CGROUP_STORAGE (variante partagée, BPF_CGROUP_STORAGE_SHARED) :
| Programme | Rôle | Taille de valeur du stockage |
|---|---|---|
| A | attaché / appelant du tail call | petite (par ex. tient dans un ordre kmalloc donné) |
| B | cible du tail call | grande (le vérificateur autorise les accès jusqu'à cette taille) |
Le vérificateur vérifie A par rapport à la map de A et B par rapport à la map de B. Les deux passent.
À l'exécution, le helper fait :
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 est l'entrée de tableau du programme qui a démarré l'exécution du cgroup, et non du programme en cours d'exécution après bpf_tail_call. B opère donc sur l'objet de stockage de A.
bpf_cgroup_storage_alloc() dimensionne le tampon sous-jacent à partir du value_size de la map. Le tampon de A est trop petit pour les accès vérifiés de B. Le résultat est une confusion de type de l'identité de la map à travers un transfert de contrôle — la même famille de bugs que les autres problèmes BPF où « le helper voit une map différente de celle vue par le vérificateur ».
Le commit 7d9c342 a rendu les stockages de cgroup partagés entre les programmes attachés au même cgroup. Ce partage est ce qui fait de l'emplacement du contexte d'exécution un pointeur unique plutôt qu'une recherche par programme, et c'est pourquoi les noyaux antérieurs à 5.9 ne sont pas affectés.