CVE-2026-74714
Publication date:
22/08/2026
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
bpf: tcp: Fix use-after-free in bpf_iter_tcp_established_batch()<br />
<br />
reqsk_queue_hash_req() publishes a TCP_NEW_SYN_RECV request_sock onto<br />
the ehash chain, drops the bucket lock, and only afterwards sets<br />
rsk_refcnt to 3.<br />
<br />
Lockless readers such as __inet_lookup_established() handle this with<br />
refcount_inc_not_zero(), but bpf_iter_tcp_established_batch() uses plain<br />
sock_hold() while holding the bucket lock, on the assumption that the<br />
lock guarantees sk_refcnt > 0. That assumption does not hold for<br />
request_sock:<br />
<br />
CPU 0 CPU 1<br />
----- -----<br />
tcp_conn_request()<br />
reqsk_queue_hash_req()<br />
inet_ehash_insert(req)<br />
spin_lock(bucket)<br />
__sk_nulls_add_node_rcu(req) // rsk_refcnt == 0<br />
spin_unlock(bucket)<br />
bpf_iter_tcp_established_batch()<br />
spin_lock(bucket)<br />
sock_hold(req) rsk_refcnt, 3) // clobbers saturated value<br />
<br />
which surfaces as:<br />
<br />
refcount_t: addition on 0; use-after-free.<br />
WARNING: lib/refcount.c:25 at refcount_warn_saturate+0x48/0x90, CPU#1<br />
Call Trace:<br />
bpf_iter_tcp_established_batch+0x14e/0x170<br />
bpf_iter_tcp_batch+0x53/0x200<br />
bpf_iter_tcp_seq_next+0x27/0x70<br />
bpf_seq_read+0x107/0x410<br />
vfs_read+0xb9/0x380<br />
<br />
The iterator&#39;s stolen reference is lost when the publishing CPU&#39;s<br />
refcount_set() overwrites the count, leaving the socket one reference<br />
short. When the last legitimate owner drops its reference the reqsk is<br />
freed while still reachable, leading to use-after-free.<br />
<br />
This reproduces in seconds with tcp_syncookies=0, a handful of threads<br />
doing connect()/close() to a local listener while others read an<br />
iter/tcp link in a tight loop.<br />
<br />
Use refcount_inc_not_zero() and skip the socket on failure. A skipped<br />
socket is still part of the bucket, so keep counting it in expected.<br />
The reallocations are sized from expected, and a request sock whose<br />
refcount gets published while the lock is held across the last realloc<br />
must already have room.<br />
<br />
A skipped socket is counted in expected but never batched, so end_sk<br />
can be short of expected on a batch that is actually complete. Decide<br />
completeness by whether the walk left any socket behind instead. The<br />
WARN after the locked realloc checks the same, replacing an<br />
end_sk == expected check that could not hold on that path since<br />
commit cdec67a489d4 ("bpf: tcp: Make sure iter->batch always<br />
contains a full bucket snapshot").<br />
<br />
If every matching socket in a bucket is mid-init (refcount 0), end_sk<br />
stays 0. Advance to the next bucket rather than returning a batch entry<br />
that was never filled this round.
Severity CVSS v4.0: Pending analysis
Last modification:
22/08/2026