Linux Kernel KFENCE Cross-Cache Free of SKB Head via bpf_prog_test_run_skb — CVE-2026-31429
by Antonius / w1sdom (Blue Dragon Security) · 2026-07-05
- Severity
- Medium
- CVE
- CVE-2026-31429
- Category
- binary
- Affected product
- Linux kernel — net/core/skbuff.c (skb_kfree_head()) via bpf_prog_test_run_skb
- Affected versions
- Linux >= 6.3 (introduced by bf9f1baa279f); fixed >= 6.12.82, >= 6.18.23, >= 6.19.13, >= 7.0 (commit 0f42e3f4fe2a)
- Disclosed
- 2026-07-05
- Patch status
- patched
Tags
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-04 |
| Author / Researcher | Antonius / w1sdom (Blue Dragon Security) |
| CVE / Advisory | CVE-2026-31429 |
| Category | binary |
| Severity | Medium |
| CVSS Score | Not specified in source |
| Status | PoC |
| Tags | linux-kernel, kfence, cross-cache, slab-corruption, ebpf, skb, cwe-763, use-after-free-adjacent |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Linux kernel — net/core/skbuff.c (skb_kfree_head()) via bpf_prog_test_run_skb |
| Versions Affected | Linux >= 6.3 (introduced by bf9f1baa279f); fixed >= 6.12.82, >= 6.18.23, >= 6.19.13, >= 7.0 (commit 0f42e3f4fe2a) |
| Language / Platform | C, Linux kernel (KFENCE-enabled builds) |
| Authentication Required | Local-only (ability to issue BPF_PROG_TEST_RUN, typically requires CAP_BPF/CAP_SYS_ADMIN-class privilege depending on unprivileged_bpf_disabled) |
| Network Access Required | No |
Summary
Linux’s skb_kfree_head() decides which slab cache to free an SKB’s head buffer back to based solely on whether end_offset equals SKB_SMALL_HEAD_HEADROOM, relying on the fact that SKB_SMALL_HEAD_CACHE_SIZE is a non-power-of-2 value that normally never collides with a generic kmalloc bucket size. When KFENCE intercepts the allocation (as can happen via bpf_test_init() in net/bpf/test_run.c calling kzalloc() with a size equal to SKB_SMALL_HEAD_CACHE_SIZE), kfence_ksize() returns the exact requested size rather than the rounded-up bucket size, causing the heuristic to falsely conclude the buffer belongs to skb_small_head_cache and freeing it to the wrong slab cache. This cross-cache free corrupts slab metadata and can be leveraged toward further memory-corruption primitives (the repository’s own README characterizes this as a proof-of-concept demonstrating the confusion, not a full working exploit).
Vulnerability Details
Root Cause
skb_kfree_head() uses end_offset == SKB_SMALL_HEAD_HEADROOM as a proxy for “this buffer came from skb_small_head_cache,” which is only valid under normal slab semantics where ksize() returns the bucket size. KFENCE’s kfence_ksize() returns the exact allocation size instead, so an allocation sized exactly SKB_SMALL_HEAD_CACHE_SIZE (704 bytes on x86_64) served from a kmalloc-1k region under KFENCE produces a false match, and the object is freed to the wrong kmem_cache.
Attack Vector
- Trigger
BPF_PROG_TEST_RUN(syscall 321,cmd=BPF_PROG_TEST_RUN) viabpf_prog_test_run_skb(). bpf_test_init()allocates the SKB head buffer withkzalloc(size, GFP_USER)wheresize == SKB_SMALL_HEAD_CACHE_SIZE(704 bytes on x86_64); on a KFENCE-instrumented kernel, KFENCE intercepts this allocation and serves it from guard-paged memory sized to the exact request.slab_build_skb()computesskb_end_offsetfromksize(data), which under KFENCE returns the exact 704-byte size instead of the 1024-byte bucket size, causingskb_end_offsetto equalSKB_SMALL_HEAD_HEADROOM(a false match).- On free,
skb_kfree_head()incorrectly routes the object tokmem_cache_free(skb_small_head_cache, ...)instead of generickfree(), corrupting the actual (kmalloc-1k) cache’s slab metadata — a cross-cache free.
Impact
Slab metadata corruption reachable from an unprivileged-adjacent syscall path when KFENCE is enabled; per the source repository this is documented as a proof-of-concept of the confusion (not a weaponized exploit), with potential security impacts including mitigation bypass, LSM disabling, kernel rootkit implantation, container breakout, and denial of service if further developed into a full exploit primitive.
Environment / Lab Setup
Target: Linux kernel >= 6.3, < fixed versions, built with CONFIG_KFENCE=y
Attacker: C toolchain (gcc/make) to build and run cve-2026-31429-poc-only.c; ability to invoke BPF_PROG_TEST_RUN
Proof of Concept
PoC Script
See
cve-2026-31429-poc-only.canddmesg.txt(crash/corruption evidence) in this folder.
| |
The PoC triggers BPF_PROG_TEST_RUN with a crafted SKB size matching SKB_SMALL_HEAD_CACHE_SIZE on a KFENCE-enabled kernel, causing the cross-cache free in skb_kfree_head(); dmesg.txt captures the resulting kernel slab-corruption warning/crash evidence from the researcher’s test run.
Detection & Indicators of Compromise
Signs of compromise:
- Kernel log warnings referencing
skb_small_head_cacheor slab-cache mismatches - Repeated
BPF_PROG_TEST_RUNinvocations with unusual/fixed-size SKB buffers from a single process - KFENCE/KASAN reports around
skb_kfree_headorslab_build_skb
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade to Linux >= 6.12.82, >= 6.18.23, >= 6.19.13, or >= 7.0 (mainline commit 0f42e3f4fe2a) |
| Interim mitigation | Restrict BPF_PROG_TEST_RUN access via unprivileged_bpf_disabled/CAP_BPF restrictions where KFENCE is enabled; disable KFENCE on the affected skb_small_head_cache path if not otherwise mitigated |
References
Notes
Mirrored from https://github.com/bluedragonsecurity/CVE-2026-31429-POC on 2026-07-05.
| |