CVE-2026-23394
Publication date:
25/03/2026
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
af_unix: Give up GC if MSG_PEEK intervened.<br />
<br />
Igor Ushakov reported that GC purged the receive queue of<br />
an alive socket due to a race with MSG_PEEK with a nice repro.<br />
<br />
This is the exact same issue previously fixed by commit<br />
cbcf01128d0a ("af_unix: fix garbage collect vs MSG_PEEK").<br />
<br />
After GC was replaced with the current algorithm, the cited<br />
commit removed the locking dance in unix_peek_fds() and<br />
reintroduced the same issue.<br />
<br />
The problem is that MSG_PEEK bumps a file refcount without<br />
interacting with GC.<br />
<br />
Consider an SCC containing sk-A and sk-B, where sk-A is<br />
close()d but can be recv()ed via sk-B.<br />
<br />
The bad thing happens if sk-A is recv()ed with MSG_PEEK from<br />
sk-B and sk-B is close()d while GC is checking unix_vertex_dead()<br />
for sk-A and sk-B.<br />
<br />
GC thread User thread<br />
--------- -----------<br />
unix_vertex_dead(sk-A)<br />
-> true sk-A&#39;s file refcount : 1 -> 2<br />
<br />
close(sk-B)<br />
-> sk-B&#39;s file refcount : 2 -> 1<br />
unix_vertex_dead(sk-B)<br />
-> true<br />
<br />
Initially, sk-A&#39;s file refcount is 1 by the inflight fd in sk-B<br />
recvq. GC thinks sk-A is dead because the file refcount is the<br />
same as the number of its inflight fds.<br />
<br />
However, sk-A&#39;s file refcount is bumped silently by MSG_PEEK,<br />
which invalidates the previous evaluation.<br />
<br />
At this moment, sk-B&#39;s file refcount is 2; one by the open fd,<br />
and one by the inflight fd in sk-A. The subsequent close()<br />
releases one refcount by the former.<br />
<br />
Finally, GC incorrectly concludes that both sk-A and sk-B are dead.<br />
<br />
One option is to restore the locking dance in unix_peek_fds(),<br />
but we can resolve this more elegantly thanks to the new algorithm.<br />
<br />
The point is that the issue does not occur without the subsequent<br />
close() and we actually do not need to synchronise MSG_PEEK with<br />
the dead SCC detection.<br />
<br />
When the issue occurs, close() and GC touch the same file refcount.<br />
If GC sees the refcount being decremented by close(), it can just<br />
give up garbage-collecting the SCC.<br />
<br />
Therefore, we only need to signal the race during MSG_PEEK with<br />
a proper memory barrier to make it visible to the GC.<br />
<br />
Let&#39;s use seqcount_t to notify GC when MSG_PEEK occurs and let<br />
it defer the SCC to the next run.<br />
<br />
This way no locking is needed on the MSG_PEEK side, and we can<br />
avoid imposing a penalty on every MSG_PEEK unnecessarily.<br />
<br />
Note that we can retry within unix_scc_dead() if MSG_PEEK is<br />
detected, but we do not do so to avoid hung task splat from<br />
abusive MSG_PEEK calls.
Severity CVSS v4.0: Pending analysis
Last modification:
25/03/2026