CVE-2026-98613: bpf: Bound ownership depth through local kptrs and graph roots
In the Linux kernel, the following vulnerability has been resolved:
bpf: Bound ownership depth through local kptrs and graph roots
Program-allocated objects can own other local objects through referenced kptrs. bpfobjfreefields() follows those pointers through bpfobjdropimpl() synchronously, before the object storage is freed through RCU. A self-referential local kptr type therefore permits arbitrarily deep object chains, and dropping the head can exhaust the kernel stack. Long acyclic type chains have the same problem.
btfcheckandfixupfields() still assumes referenced kptrs only point to kernel types and checks ownership through list and rbtree roots only. Its existing rule is sufficient for graph-only cycles: the target of each graph edge must contain a node, so every type in a cycle has both a root and a node. The rule rejects such a type owning another root, breaking every cycle. It also limits graph-only chains to three types, or two if the first type contains a node, and conservatively rejects longer acyclic chains. The missing local-kptr edges, rather than a missed graph-only cycle, are the bug introduced by support for bpfkptrxchg() into local kptrs.
Replace that restriction with one bounded ownership walk covering graph roots and local referenced kptrs. Run it after all BTF records have been fixed up, reject cycles and paths deeper than eight record-bearing types, and cache each type's suffix depth while checking it against the remaining budget. This also permits the longer acyclic graph-only layouts rejected by the old rule; update their existing BTF tests accordingly.
Keep the bound independent of MAXCALLFRAMES because recursive destruction can run below a BPF call chain. A plain local pointee without special-field metadata adds only a final non-recursing drop. Non-owning kptrs and kernel-BTF kptrs do not recurse through local records and remain outside the walk. Include local percpu-kptr edges too, although allocation of percpu objects with special fields is currently forbidden, so that relaxing that restriction cannot bypass the ownership bound.
btfcheckandfixupfields() continues to initialize graphroot.valuerec, including for separately allocated map records. The ownership relationships belong to immutable program BTF and only need validation at BTF load time.
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
ubuntu/linux-hwe-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42~24.04.1 - Upgrade
Upgrade
ubuntu/linux-riscv-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1~24.04.1 - Upgrade
Upgrade
ubuntu/linuxto a version that resolves this vulnerability.Fixed in 7.0.0-42.42 - Upgrade
Upgrade
ubuntu/linux-awsto a version that resolves this vulnerability.Fixed in 7.0.0-1016.17 - Upgrade
Upgrade
ubuntu/linux-gcpto a version that resolves this vulnerability.Fixed in 7.0.0-1016.18 - Upgrade
Upgrade
ubuntu/linux-ibmto a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oem-7.0to a version that resolves this vulnerability.Fixed in 7.0.0-1017.17 - Upgrade
Upgrade
ubuntu/linux-oracleto a version that resolves this vulnerability.Fixed in 7.0.0-1015.16 - Upgrade
Upgrade
ubuntu/linux-riscvto a version that resolves this vulnerability.Fixed in 7.0.0-42.42.1
Event History
Frequently Asked Questions
Which BPF object layouts are affected?
The issue affects program-allocated objects that own other local objects through referenced local kptrs. Self-referential local kptr types and sufficiently long acyclic ownership chains can trigger the problem.
What condition triggers the stack exhaustion?
Dropping the head object causes bpf_obj_free_fields() to synchronously follow owned local-kptr references through __bpf_obj_drop_impl(). An arbitrarily deep chain can therefore consume the kernel stack before the object storage is freed through RCU.
Are graph-root references alone the source of this issue?
No. The existing ownership checks were sufficient for graph-only cycles and conservatively limited graph-only chains. The missing validation concerned local-kptr ownership edges introduced with support for bpf_kptr_xchg() into local kptrs.