
Forschungs-Repository für CVE-2025-38502, einen Out-of-Bounds-Zugriff auf den lokalen Speicher der Linux-Kernel-BPF-Cgroup über Tail Calls, der lokale Rechteausweitung ermöglicht.

Abraxas Labs · abraxaslabs.tech · github.com/abraxas · @abraxas_null
Linux-Kernel-BPF-Cgroup-Local-Storage-Out-of-Bounds-Zugriff über Tail Calls
| CVE | CVE-2025-38502 |
| CWE | CWE-125 — Out-of-bounds Read |
| Hersteller | Linux-Kernel |
| Komponente | kernel/bpf/core.c, include/linux/bpf.h (Cgroup Local Storage + Tail Calls) |
| Auswirkung | Lokale Kernel-Speicherbeschädigung; Privilegieneskalation ist auf ungepatchten Kerneln im Rahmen des Möglichen |
| Angriffsvektor | Lokal (AV:L) |
| Privilegien | Niedrig (PR:L) — ein Prozess, der BPF-Programme vom Typ CGROUP_SKB (oder äquivalente cgroup-attached Programme) laden kann |
| Benutzerinteraktion | Keine |
| CVSS 3.1 (kernel.org CNA) | 7.8 HIGH — 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 HIGH — CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H |
| Veröffentlicht | 16. August 2025 |
| Upstream-Fix | abad3d0 in 6.17-rc1; zurückportiert nach 6.16.1, 6.12.46, 6.6.105, 6.1.151, 5.15.192 |
Nur für Forschung / Bildungszwecke. Führen Sie Material in diesem Repository nicht aus, setzen Sie es nicht ein und verwenden Sie es nicht gegen einen Host, es sei denn, Sie haben die ausdrückliche schriftliche Genehmigung sowohl der Partei, die dieses Repository hostet, als auch des Eigentümers der Zielsysteme. In freier Wildbahn gefunden.
Der Quelldateiname CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c schneidet den Bezeichner ab. Der veröffentlichte Eintrag ist CVE-2025-38502. Es gibt kein Linux-CVE CVE-2025-3850.
Lonial meldete, dass Cgroup-BPF-Local-Storage über einen Tail Call hinweg außerhalb der Grenzen zugegriffen werden kann.
Der eBPF-Verifier prüft jedes Programm isoliert auf Typen. Zur Laufzeit sucht bpf_get_local_storage() nicht die Map des aktuell ausgeführten Programms. Es liest den Cgroup-Storage-Zeiger aus current->bpf_ctx → bpf_cg_run_ctx → prog_item->cgroup_storage[]. Dieser Slot wird vom ursprünglich angehängten Programm befüllt, nicht von dem Programm, in das per Tail Call gesprungen wurde.
Wenn Programm A (kleine BPF_MAP_TYPE_CGROUP_STORAGE-Wertgröße) per Tail Call in Programm B (große Wertgröße) springt, liefert bpf_get_local_storage() von B weiterhin den kleineren Puffer von A. Zugriffe, die der Verifier gegen B's Map erlaubt hat, laufen dann über das Ende von A's Allokation hinaus.
Der Defekt wurde in Linux 5.9 durch 7d9c342 (bpf: Make cgroup storages shared between programs on the same cgroup) eingeführt. Behoben wurde er durch Erweiterung von bpf_map_owner um ein storage_cookie[], sodass Tail-Call-Kombinationen nur akzeptiert werden, wenn der Callee dieselben Cgroup-Storage-Maps wie der Caller verwendet oder gar keine.
Dies ist ein lokaler Kernel-Heap-Out-of-Bounds-Zugriff. Die Schweregradbewertung variiert je nach Hersteller, weil sie sich uneinig darüber sind, ob das Primitiv ein „Read-only-DoS“ oder vollständige Speicherbeschädigung ist:
| Quelle | Score | Integrität | Anmerkungen |
|---|---|---|---|
| kernel.org CNA / cve.org | 7.8 HIGH | Hoch | C:H/I:H/A:H — behandelt den Bug als vollständige lokale Auswirkung |
| NVD | 7.1 HIGH | Keine | C:H/I:N/A:H — Vertraulichkeit + Verfügbarkeit |
| Ubuntu | Mittel (7.1) | — | USN-7909 |
| Red Hat | 4.0 LOW | Keine | C:N/I:N/A:L — als eingeschränkte Verfügbarkeit bewertet |
| Amazon Linux | 4.0 Mittel | Keine | gleicher Vektor wie Red Hat |
| SUSE | 6.1 Moderate | Keine | einige SLE-15-Streams als WONTFIX markiert |
Was das in der Praxis bedeutet:
struct bpf_array) können beschädigt werden.map->ops, Hijacking eines Helpers, commit_creds / Namespace-Wechsel). Deshalb bezeichnet dieser Tree das Problem als LPE. Red Hats niedrigerer Score spiegelt deren produktspezifische Bewertung wider, nicht die Abwesenheit des Bugs.Der Bug erfordert keinen netzwerkseitig erreichbaren Dienst. Er ist lokal. Er erfordert kein TTY, keinen setuid-Helper und keine Benutzerinteraktion.
Zwei Cgroup-BPF-Programme, jedes mit eigenem BPF_MAP_TYPE_CGROUP_STORAGE (Shared-Flavor, BPF_CGROUP_STORAGE_SHARED):
| Programm | Rolle | Storage-Wertgröße |
|---|---|---|
| A | angehängt / Tail-Call-Caller | klein (z. B. passt in eine gegebene kmalloc-Order) |
| B | Tail-Call-Ziel | groß (Verifier erlaubt Zugriffe bis zu dieser Größe) |
Der Verifier prüft A gegen A's Map und B gegen B's Map. Beide bestehen.
Zur Laufzeit macht der Helper Folgendes:
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 ist der Array-Eintrag für das Programm, das den Cgroup-Run gestartet hat, nicht für das Programm, das nach bpf_tail_call aktuell ausgeführt wird. B arbeitet daher auf A's Storage-Objekt.
bpf_cgroup_storage_alloc() dimensioniert den zugrunde liegenden Puffer anhand der value_size der Map. A's Puffer ist zu klein für B's verifizierte Zugriffe. Das Ergebnis ist eine klassische Typverwechslung der Map-Identität über einen Kontrolltransfer hinweg — dieselbe Bug-Familie wie andere BPF-Probleme, bei denen „der Helper eine andere Map sieht als der Verifier“.
Commit 7d9c342 machte Cgroup-Storages zwischen Programmen, die an dieselbe Cgroup angehängt sind, geteilt. Diese Teilung ist der Grund, warum der Run-Context-Slot ein einzelner Zeiger ist statt eines Lookups pro Programm, und warum Kernel vor 5.9 nicht betroffen sind.