CVE-2026-74714

Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
22/08/2026
Last modified:
22/08/2026

Description

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 &gt; 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&amp;#39;s stolen reference is lost when the publishing CPU&amp;#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-&gt;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.

Impact