CVE-2026-98643
NoneCVSS
—
EPSS
0.2%
Published
Oct 18, 2026
CISA due date
—
Cloudanix analysis
A bug in Linux kernel networking code could let certain low-level programs read and leak internal memory they should not access.
- Exploitation
- Local Privilege
- Attacker needs
- Low Privilege
- Complexity
- Moderate
- Impact
- Data Exposure
- Component
- OS kernel
- Class
- Information Disclosure
- Remediation
- Patch
- Effort
- Medium
- Patch risk
- Low
What it actually does
Out-of-bounds memory read in BPF sock_ops when accessing rtt_min on a request_sock instead of a full tcp_sock, disclosing adjacent kernel memory including pointers.
Why it matters to the business
Systems allowing untrusted BPF program loading face risk of kernel memory leaks that can reveal pointers and aid escalation to full kernel compromise.
How an attack unfolds
An attacker loads a sockops BPF program that reads skops->rtt_min on the BPF_SOCK_OPS_RWND_INIT path; when triggered during tcp_conn_request the unsafe cast reads past the request_sock structure, returning leaked kernel data to userspace.
How to fix it
Update the Linux kernel so that rtt_min is accessed only via SOCK_OPS_GET_FIELD which enforces the is_locked_tcp_sock check; rebuild and deploy the patched kernel across affected systems.
How to confirm the fix worked
Confirm the patched BPF helper contains the is_locked_tcp_sock guard before the rtt_min load; run sockops programs on request_sock paths and verify they now return zero instead of OOB data.
Typical attack path
- Obtain ability to load BPF programs via CAP_BPF or equivalent
- Attach malicious sockops program that directly reads rtt_min
- Trigger connection establishment to hit the tcp_conn_request path
- Extract leaked kernel memory from the BPF program return value or map
How to detect it
Inspect loaded BPF bytecode for direct loads of offset 2324 on sockops contexts without the is_locked_tcp_sock guard; review kernel logs for unusual sockops attachments and monitor for programs returning unexpected pointer values.
What your security team should do
- Restrict BPF loading privileges to the minimum necessary users and cgroups
- Apply the kernel fix immediately on any system that exposes BPF to workloads
- Audit existing sockops programs for direct field accesses bypassing the helper
- Enable LSM or seccomp policies that limit untrusted BPF attachment
The record
In the Linux kernel, the following vulnerability has been resolved: bpf: Fix out-of-bounds read of rtt_min in sock_ops A sockops prog reading skops->rtt_min never checks the sk type: on the tcp_conn_request() path sock_ops->sk is a request_sock (non-full), and the ctx rewrite casts it to a tcp_sock (full) and reads rtt_min past the end of the request_sock, returning dirty adjacent memory. SEC("sockops") int prog(struct bpf_sock_ops *skops) { switch (skops->op) { case BPF_SOCK_OPS_RWND_INIT: leak = skops->rtt_min; /* reads the request_sock OOB */ ... } } For instance one such read returned rtt_min=0xffff8881, the high half of a leaked kernel pointer. Guarding that cast is exactly what SOCK_OPS_GET_FIELD() does -- it checks is_locked_tcp_sock and returns 0 when sock_ops->sk is not a locked full socket. Every other tcp_sock field in sock_ops goes through it; rtt_min is the only one open-coded, so it skips the check. Read rtt_min through SOCK_OPS_GET_FIELD() too. rtt_min is a bit special: it is a struct minmax and we only want the current min, so pass rtt_min.s[0].v. That is equivalent to the old hand-computed offset offsetof(struct tcp_sock, rtt_min) + sizeof_field(struct minmax_sample, t) (s[0] sits at rtt_min + 0 and .v at + sizeof(.t), i.e. what minmax_get() returns), so the loaded field is unchanged and only the full-sock guard is added. The two BUILD_BUG_ON()s that protected the hand-computed offset are no longer needed. Before patch: 0: r1 = *(u64 *)(r1 +0) ; r1 = skops->sk 1: r1 = *(u32 *)(r1 +2324) ; ((tcp_sock *)sk)->rtt_min.s[0].v After patch: 0: *(u64 *)(r1 +56) = r9 1: r9 = *(u8 *)(r1 +50) ; is_locked_tcp_sock 2: if r9 == 0 goto pc+4 ; not a locked full sock -> 0 3: r9 = *(u64 *)(r1 +56) 4: r1 = *(u64 *)(r1 +0) ; r1 = skops->sk 5: r1 = *(u32 *)(r1 +2324) ; rtt_min.s[0].v 6: goto pc+2 7: r9 = *(u64 *)(r1 +56) 8: r1 = 0
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|