CVE-2025-40214
Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
04/12/2025
Last modified:
04/12/2025
Description
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
af_unix: Initialise scc_index in unix_add_edge().<br />
<br />
Quang Le reported that the AF_UNIX GC could garbage-collect a<br />
receive queue of an alive in-flight socket, with a nice repro.<br />
<br />
The repro consists of three stages.<br />
<br />
1)<br />
1-a. Create a single cyclic reference with many sockets<br />
1-b. close() all sockets<br />
1-c. Trigger GC<br />
<br />
2)<br />
2-a. Pass sk-A to an embryo sk-B<br />
2-b. Pass sk-X to sk-X<br />
2-c. Trigger GC<br />
<br />
3)<br />
3-a. accept() the embryo sk-B<br />
3-b. Pass sk-B to sk-C<br />
3-c. close() the in-flight sk-A<br />
3-d. Trigger GC<br />
<br />
As of 2-c, sk-A and sk-X are linked to unix_unvisited_vertices,<br />
and unix_walk_scc() groups them into two different SCCs:<br />
<br />
unix_sk(sk-A)->vertex->scc_index = 2 (UNIX_VERTEX_INDEX_START)<br />
unix_sk(sk-X)->vertex->scc_index = 3<br />
<br />
Once GC completes, unix_graph_grouped is set to true.<br />
Also, unix_graph_maybe_cyclic is set to true due to sk-X&#39;s<br />
cyclic self-reference, which makes close() trigger GC.<br />
<br />
At 3-b, unix_add_edge() allocates unix_sk(sk-B)->vertex and<br />
links it to unix_unvisited_vertices.<br />
<br />
unix_update_graph() is called at 3-a. and 3-b., but neither<br />
unix_graph_grouped nor unix_graph_maybe_cyclic is changed<br />
because both sk-B&#39;s listener and sk-C are not in-flight.<br />
<br />
3-c decrements sk-A&#39;s file refcnt to 1.<br />
<br />
Since unix_graph_grouped is true at 3-d, unix_walk_scc_fast()<br />
is finally called and iterates 3 sockets sk-A, sk-B, and sk-X:<br />
<br />
sk-A -> sk-B (-> sk-C)<br />
sk-X -> sk-X<br />
<br />
This is totally fine. All of them are not yet close()d and<br />
should be grouped into different SCCs.<br />
<br />
However, unix_vertex_dead() misjudges that sk-A and sk-B are<br />
in the same SCC and sk-A is dead.<br />
<br />
unix_sk(sk-A)->scc_index == unix_sk(sk-B)->scc_index vertex->out_degree<br />
^-- 1 in-flight count for sk-B<br />
-> sk-A is dead !?<br />
<br />
The problem is that unix_add_edge() does not initialise scc_index.<br />
<br />
Stage 1) is used for heap spraying, making a newly allocated<br />
vertex have vertex->scc_index == 2 (UNIX_VERTEX_INDEX_START)<br />
set by unix_walk_scc() at 1-c.<br />
<br />
Let&#39;s track the max SCC index from the previous unix_walk_scc()<br />
call and assign the max + 1 to a new vertex&#39;s scc_index.<br />
<br />
This way, we can continue to avoid Tarjan&#39;s algorithm while<br />
preventing misjudgments.



