## https://sploitus.com/exploit?id=8FF551F8-DFC3-5F10-95CB-6ECABBDF76C7

**Abraxas Labs** Β· [abraxaslabs.tech](https://abraxaslabs.tech) Β· [github.com/abraxas](https://github.com/abraxas) Β· [@abraxas_null](https://x.com/abraxas_null)
# CVE-2025-38502
**Linux kernel BPF cgroup local storage out-of-bounds access via tail calls**
| | |
|---|---|
| **CVE** | [CVE-2025-38502](https://vulners.com/cve/CVE-2025-38502) |
| **CWE** | [CWE-125](https://cwe.mitre.org/data/definitions/125.html) β Out-of-bounds Read |
| **Vendor** | Linux kernel |
| **Component** | `kernel/bpf/core.c`, `include/linux/bpf.h` (cgroup local storage + tail calls) |
| **Impact** | Local kernel memory corruption; privilege escalation is in scope on unpatched kernels |
| **Attack vector** | Local (`AV:L`) |
| **Privileges** | Low (`PR:L`) β a process that can load BPF programs of type `CGROUP_SKB` (or equivalent cgroup-attached programs) |
| **User interaction** | None |
| **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` |
| **Public** | 16 August 2025 |
| **Upstream fix** | `abad3d0` in **6.17-rc1**; backported to 6.16.1, 6.12.46, 6.6.105, 6.1.151, 5.15.192 |
> **Research / educational use only.** Do not run, deploy, or use material in this repository against any host unless you have explicit written permission from both the party hosting this repository and the owner of the target systems. Found in the wild.
The source filename `CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c` truncates the identifier. The published record is **CVE-2025-38502**. There is no Linux CVE `CVE-2025-3850`.
---
## Contents
- [Summary](#summary)
- [Impact](#impact)
- [Root cause](#root-cause)
- [Affected kernel versions](#affected-kernel-versions)
- [Distribution status](#distribution-status)
- [Preconditions](#preconditions)
- [The fix](#the-fix)
- [Checking a running system](#checking-a-running-system)
- [Mitigation](#mitigation)
- [Repository layout](#repository-layout)
- [References](#references)
- [Contact](#contact)
- [Disclaimer](#disclaimer)
---
## Summary
Lonial reported that **cgroup BPF local storage can be accessed out of bounds across a tail call**.
The eBPF verifier type-checks each program in isolation. At runtime, `bpf_get_local_storage()` does **not** look up the currently executing program's map. It reads the cgroup-storage pointer out of `current->bpf_ctx` β `bpf_cg_run_ctx` β `prog_item->cgroup_storage[]`. That slot is filled from the **originally attached** program, not from the program that was tail-called into.
If program A (small `BPF_MAP_TYPE_CGROUP_STORAGE` value size) tail-calls program B (large value size), B's `bpf_get_local_storage()` still returns A's smaller buffer. Accesses the verifier allowed against B's map then walk off the end of A's allocation.
The defect was introduced in Linux **5.9** by `7d9c342` (*bpf: Make cgroup storages shared between programs on the same cgroup*). It was fixed by extending `bpf_map_owner` with a `storage_cookie[]` so tail-call combinations are only accepted when the callee uses the **same** cgroup-storage maps as the caller, or uses none.
---
## Impact
This is a **local kernel heap out-of-bounds access**. Severity scoring varies by vendor because they disagree on whether the primitive is βread-only DoSβ or full memory corruption:
| Source | Score | Integrity | Notes |
|---|---|---|---|
| kernel.org CNA / cve.org | **7.8 HIGH** | High | `C:H/I:H/A:H` β treats the bug as full local impact |
| NVD | **7.1 HIGH** | None | `C:H/I:N/A:H` β confidentiality + availability |
| Ubuntu | Medium (7.1) | β | [USN-7909](https://ubuntu.com/security/CVE-2025-38502) |
| Red Hat | **4.0 LOW** | None | `C:N/I:N/A:L` β rated as limited availability |
| Amazon Linux | **4.0** Medium | None | same vector as Red Hat |
| SUSE | **6.1** Moderate | None | some SLE 15 streams marked WONTFIX |
What that means in practice:
- **Confidentiality.** An OOB read of the neighbouring kmalloc object can leak kernel pointers (KASLR slide), heap cookies, and adjacent structure contents.
- **Integrity.** The same mismatch is a sized write relative to the *callee's* map, against the *caller's* smaller buffer. Adjacent heap objects (for example a `struct bpf_array` sprayed into the same slab/order) can be corrupted.
- **Availability.** A mistargeted write is a straightforward kernel oops / panic.
- **Privilege.** On an unpatched kernel where BPF cgroup programs can be loaded, this class of heap OOB has been used as a **local privilege escalation** primitive (overwrite `map->ops`, hijack a helper, `commit_creds` / namespace switch). That is why this tree labels the issue LPE. Red Hat's lower score reflects their product-specific assessment, not the absence of the bug.
The bug does **not** require a network-facing service. It is local. It does **not** require a TTY, a setuid helper, or user interaction.
---
## Root cause
### Verifier vs runtime
Two cgroup BPF programs, each with its own `BPF_MAP_TYPE_CGROUP_STORAGE` (shared flavor, `BPF_CGROUP_STORAGE_SHARED`):
| Program | Role | Storage value size |
|---|---|---|
| A | attached / tail-call caller | small (e.g. fits a given kmalloc order) |
| B | tail-call target | large (verifier allows accesses up to this size) |
The verifier checks A against A's map and B against B's map. Both pass.
At run time the helper does:
```c
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` is the array entry for the **program that started the cgroup run**, not the program currently executing after `bpf_tail_call`. B therefore operates on A's storage object.
### Why the sizes matter
`bpf_cgroup_storage_alloc()` sizes the backing buffer from the map's `value_size`. A's buffer is too small for B's verified accesses. The result is a classic **type-confusion of map identity across a control-transfer** β the same family of bugs as other BPF βhelper sees a different map than the verifier didβ issues.
### Shared storage on a cgroup
Commit `7d9c342` made cgroup storages **shared between programs attached to the same cgroup**. That sharing is what makes the run-context slot a single pointer rather than a per-program lookup, and is why kernels before 5.9 are not affected.
### Adjacent objects
`BPF_PROG_TEST_RUN` on a `BPF_PROG_TYPE_CGROUP_SKB` program allocates cgroup storage for the duration of the test. That allocation sits on the kernel heap next to whatever else was recently freed in the same size class β including `struct bpf_array` maps whose `value_size` was chosen to land in the same kmalloc order. An OOB from the storage buffer can therefore reach `bpf_map` fields (`ops`, RCU list, value[]) of a neighbouring array map.
That heap-layout detail is why a βmere OOB readβ advisory and an LPE write-up can describe the same CVE.
---
## Affected kernel versions
**Introduced:** Linux **5.9** (`7d9c3427894fe70d1347b4820476bf37736d2ff0`)
**Unaffected:** all kernels **before 5.9**
| Series | Affected | First fixed |
|---|---|---|
| 5.9 β 5.15 | 5.9 through **5.15.191** | **5.15.192** (`c1c74584β¦`) |
| 5.16 β 6.1 | 5.16 through **6.1.150** | **6.1.151** (`66da7ceeβ¦`) |
| 6.2 β 6.6 | 6.2 through **6.6.104** | **6.6.105** (`7acfa07cβ¦`) |
| 6.7 β 6.12 | 6.7 through **6.12.45** | **6.12.46** (`41688d1fβ¦`) |
| 6.13 β 6.16 | 6.13 through **6.16.0** | **6.16.1** (`19341d5cβ¦`) |
| mainline | until the fix landed | **6.17-rc1** (`abad3d0bβ¦`) |
One-liner:
```
/* CVE-2025-38502: affected 5.9β5.15.191, 5.16β6.1.150, 6.2β6.6.104, 6.7β6.12.45, 6.13β6.16.0; fixed in 5.15.192, 6.1.151, 6.6.105, 6.12.46, 6.16.1, 6.17-rc1 */
```
**Still open in some stables:** Debian's kernel tracker listed **5.10** upstream-stable / bullseye 5.10 as `needed`. Do not assume every 5.10.y is patched.
**Distro ABI numbers lie.** Ubuntu `5.15.0-163` is a patched 5.15 even though `5.15.0` looks older than upstream `5.15.192`. Compare the **package** changelog / USN / DSA / ALAS / RHSA, not `uname -r` against the table above.
---
## Distribution status
Any distribution that shipped a kernel in the ranges above was in scope until it backported `abad3d0` (or the matching stable commit). This is generic BPF code, not a distro-specific patch.
### Typically affected until patched
| Distro | Releases / kernels that were in range |
|---|---|
| **Ubuntu** | 22.04 LTS (5.15), 24.04 LTS (6.8), 25.04 (EOL still **needed**). 20.04 **HWE 5.15**. |
| **Debian** | 11 bullseye (5.10), 12 bookworm (6.1), 13 trixie (6.12) |
| **RHEL 9 / 10**, Rocky, Alma, Fedora | RHEL 9 β 5.14; RHEL 10 β 6.12; Fedora rolling 5.9β6.16 |
| **SUSE / openSUSE** | SLE Micro 5.3/5.4; some SLE 15 streams **WONTFIX** |
| **Amazon Linux 2023** | default kernel and `kernel6.12` |
| **Amazon Linux 2 extras** | 5.10 extra (**no fix planned**) and 5.15 extra |
| **Arch, Gentoo, Tumbleweed** | rolling kernels between 5.9 and the 6.16.1 / 6.17-rc1 fix |
### Not affected (GA kernel older than 5.9)
- Ubuntu 20.04 **GA** (5.4), 18.04, 16.04
- RHEL 8 **default** (4.18)
- Amazon Linux 1; Amazon Linux 2 **core** / 5.4 extra
### Known patched package versions (examples)
| Distro | Fixed package (indicative) | Advisory |
|---|---|---|
| Ubuntu 22.04 | `linux` **5.15.0-163.173** | [USN-7909](https://ubuntu.com/security/CVE-2025-38502) |
| Ubuntu 24.04 | `linux` **6.8.0-106.106** | same |
| Debian 12 | `linux` **6.1.153-1** | DSA-6009-1 |
| Debian 13 | `linux` **6.12.48-1** | DSA-6008-1 |
| Debian 11 (6.1 backport) | `linux-6.1` **6.1.153-1~deb11u1** | DLA-4328-1 |
| Amazon Linux 2023 | kernel / kernel6.12, 2025-09-29 | ALAS2023-2025-1210 / 1208 |
| Amazon Linux 2 5.15 extra | 2025-09-29 | ALAS2KERNEL-5.15-2025-091 |
Ubuntu 26.04 / 25.10 are listed **not affected** (they branched after the fix). Ubuntu 25.04 reached EOL still **needed**.
---
## Preconditions
A host can match an affected version and still not be reachable. Useful checks:
| Condition | Why it matters |
|---|---|
| `CONFIG_BPF_SYSCALL=y` | `bpf(2)` must exist |
| `CONFIG_CGROUP_BPF=y` | cgroup-attached programs and cgroup local storage |
| `kernel.unprivileged_bpf_disabled` | `0` allows unprivileged program load; `1`/`2` require `CAP_BPF` / `CAP_PERFMON` / `CAP_SYS_ADMIN` |
| Lockdown / LSM / seccomp | may block `BPF_PROG_LOAD` or `BPF_PROG_TEST_RUN` |
| `BPF_PROG_TYPE_CGROUP_SKB` (or other cgroup program types that carry local storage) | the run context that holds `cgroup_storage[]` |
`unprivileged_bpf_disabled=1` is **not** a complete fix β a user with BPF capability can still hit the bug β but it removes the unprivileged path.
---
## The fix
Upstream commit **`abad3d0bad72a52137e0c350c59542d75ae4f513`** (*bpf: Fix oob access in cgroup local storage*, Daniel Borkmann).
`struct bpf_map_owner` gains a `storage_cookie[]` array. On tail-call target update, the kernel now:
1. **If the callee uses `bpf_get_local_storage()`** β require the callee's cgroup-storage maps to be **exactly** the caller's maps (same cookies).
2. **If the callee uses no cgroup local storage** β allow the tail-call combination.
Mismatching value sizes can no longer be composed behind the verifier's back. Each program is still verified alone; the new check is on the **edge** between them.
Do not cherry-pick the commit onto an arbitrary tree without the surrounding BPF owner/cookie helpers. Use the stable backport for your series.
---
## Checking a running system
```bash
uname -r
# Compare against the table above, then against your distro advisory β
# Ubuntu/Debian ABI numbers are not upstream stable numbers.
grep -E 'CONFIG_BPF_SYSCALL|CONFIG_CGROUP_BPF' \
/boot/config-$(uname -r) /proc/config.gz 2>/dev/null
sysctl kernel.unprivileged_bpf_disabled
# 0 = unprivileged bpf allowed (widest exposure)
# 1 = disabled after first privileged use, or fully disabled depending on kernel
# 2 = disabled (admin can re-enable)
```
Confirm the package, not just the version string:
```bash
# Debian / Ubuntu
apt changelog linux-image-$(uname -r) 2>/dev/null | grep -i 38502
# RHEL family
rpm -q --changelog kernel | grep -i 38502
```
A kernel **β₯ 6.17**, or a stable listed in the βfirst fixedβ column, or a distro package from the advisory table, is the actual close-out.
---
## Mitigation
1. **Patch.** Install the distro kernel that contains `abad3d0` / the stable equivalent. This is the only complete fix.
2. **Until you can patch:**
- Set `kernel.unprivileged_bpf_disabled=1` (or `2`) to drop unprivileged loaders.
- Restrict `CAP_BPF`, `CAP_PERFMON`, and `CAP_SYS_ADMIN` on untrusted users and containers.
- In user namespaces / unprivileged containers, disable BPF (`seccomp`, LSM, or dropping those caps in the runtime).
3. **Do not** treat βwe don't attach cgroup SKB programs ourselvesβ as safety. `BPF_PROG_TEST_RUN` is enough to exercise the allocation path; a local attacker supplies the programs.
---
## Repository layout
```
CVE-2025-38502/
βββ README.md
βββ banner.png
βββ CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c
βββ ebpf_lpe.h
```
| File | What it is |
|---|---|
| `banner.png` | README banner (Abraxas Labs / CVE-2025-38502) |
| `CVE-2025-3850-Linux-LPE-Abaraxas-Labs.c` | Research source recovered in the wild (filename truncates the CVE id) |
| `ebpf_lpe.h` | Shared BPF instruction constructors, map helpers, and kernel-offset macros used by that source |
This directory documents the vulnerability and holds the corresponding research tree. It is **not** a drop-in exploit kit: kernel gadget symbols (`ARRAY_MAP_OPS_OFF`, `COMMIT_CREDS`, β¦) are compile-time inputs for a **specific** `vmlinux`, and running the program against a live kernel is out of scope for this README.
---
## References
**CVE / NVD**
- [CVE-2025-38502](https://vulners.com/cve/CVE-2025-38502)
- [NVD](https://nvd.nist.gov/vuln/detail/CVE-2025-38502)
- [GitHub Advisory GHSA-x96j-4m6x-jcvx](https://github.com/advisories/GHSA-x96j-4m6x-jcvx)
**Upstream**
- Introduced: [`7d9c342`](https://git.kernel.org/linus/7d9c3427894fe70d1347b4820476bf37736d2ff0) β *bpf: Make cgroup storages shared between programs on the same cgroup*
- Fixed: [`abad3d0`](https://git.kernel.org/linus/abad3d0bad72a52137e0c350c59542d75ae4f513) β *bpf: Fix oob access in cgroup local storage*
- [linux-cve-announce](https://lists.openwall.net/linux-cve-announce/2025/08/16/2)
**Stable backports**
- 6.16.1 [`19341d5c`](https://git.kernel.org/stable/c/19341d5c59e8c7e8528e40f8663e99d67810473c)
- 6.12.46 [`41688d1f`](https://git.kernel.org/stable/c/41688d1fc5d163a6c2c0e95c0419e2cb31a44648)
- 6.6.105 [`7acfa07c`](https://git.kernel.org/stable/c/7acfa07c585e3d7a64654d38f0a5c762877d0b9b)
- 6.1.151 [`66da7cee`](https://git.kernel.org/stable/c/66da7cee78590259b400e51a70622ccd41da7bb2)
- 5.15.192 [`c1c74584`](https://git.kernel.org/stable/c/c1c74584b9b4043c52e41fec415226e582d266a3)
**Distros**
- [Ubuntu CVE page](https://ubuntu.com/security/CVE-2025-38502)
- [Debian security tracker](https://security-tracker.debian.org/tracker/CVE-2025-38502)
- [Debian kernel-sec](https://kernel-team.pages.debian.net/kernel-sec/CVE-2025-38502.html)
- [Red Hat](https://access.redhat.com/security/cve/cve-2025-38502)
- [Amazon Linux ALAS](https://explore.alas.aws.amazon.com/CVE-2025-38502.html)
- [SUSE](https://www.suse.com/security/cve/CVE-2025-38502.html)
---
## Contact
**Abraxas Labs** β research / authorized testing only
| | |
|---|---|
| Website | [https://abraxaslabs.tech](https://abraxaslabs.tech) |
| GitHub | [https://github.com/abraxas](https://github.com/abraxas) |
| X | [@abraxas_null](https://x.com/abraxas_null) |
---
## Disclaimer
This repository is for **research and education**.
Do not compile, run, deploy, or otherwise use the code here against any system unless you have **explicit written authorization** from both the party hosting this repository and the owner of the target. Unauthorized access to computer systems is a crime.
The authors and Abraxas Labs provide this material **as-is**, with no warranty that it is complete, correct, or safe to execute. Kernel exploitation research can panic a machine, corrupt filesystems, and lose data. You assume that risk.
Found in the wild.