CVE-2026-98643: bpf: Fix out-of-bounds read of rtt_min in sock_ops
In the Linux kernel, the following vulnerability has been resolved:
bpf: Fix out-of-bounds read of rttmin in sockops
A sockops prog reading skops->rttmin never checks the sk type: on the tcpconnrequest() path sockops->sk is a requestsock (non-full), and the ctx rewrite casts it to a tcpsock (full) and reads rttmin past the end of the requestsock, returning dirty adjacent memory.
SEC("sockops") int prog(struct bpfsockops skops) { switch (skops->op) { case BPFSOCKOPSRWNDINIT: leak = skops->rttmin; / reads the requestsock OOB / ... } }
For instance one such read returned rttmin=0xffff8881, the high half of a leaked kernel pointer.
Guarding that cast is exactly what SOCKOPSGETFIELD() does -- it checks islockedtcpsock and returns 0 when sockops->sk is not a locked full socket. Every other tcpsock field in sockops goes through it; rttmin is the only one open-coded, so it skips the check.
Read rttmin through SOCKOPSGETFIELD() too. rttmin is a bit special: it is a struct minmax and we only want the current min, so pass rttmin.s[0].v. That is equivalent to the old hand-computed offset
offsetof(struct tcpsock, rttmin) + sizeoffield(struct minmaxsample, t)
(s[0] sits at rttmin + 0 and .v at + sizeof(.t), i.e. what minmaxget() returns), so the loaded field is unchanged and only the full-sock guard is added. The two BUILDBUGON()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) ; ((tcpsock )sk)->rttmin.s[0].v
After patch:
0: (u64 )(r1 +56) = r9 1: r9 = (u8 )(r1 +50) ; islockedtcpsock 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) ; rttmin.s[0].v 6: goto pc+2 7: r9 = (u64 )(r1 +56) 8: r1 = 0
Affected Software
Event History
Frequently Asked Questions
Which workloads can trigger the out-of-bounds read?
A BPF program of type sockops can trigger it when it reads skops->rtt_min during the BPF_SOCK_OPS_RWND_INIT operation. On the tcp_conn_request() path, sock_ops->sk is a request_sock rather than a full TCP socket.
What information may be exposed by the read?
The read can return adjacent kernel memory rather than the intended RTT value. One observed value contained the high half of a leaked kernel pointer.
How does the fix change the result for non-full sockets?
The fix reads rtt_min through SOCK_OPS_GET_FIELD(), which checks whether the socket is a locked full TCP socket. If it is not, the field access returns 0 instead of reading beyond the request_sock.