{"id":15079,"date":"2026-09-04T19:02:24","date_gmt":"2026-09-04T11:02:24","guid":{"rendered":"https:\/\/www.54iter.cn\/?vuln=cve-2026-64109"},"modified":"2026-09-04T19:02:24","modified_gmt":"2026-09-04T11:02:24","slug":"cve-2026-64109","status":"publish","type":"vuln","link":"https:\/\/www.54iter.cn\/?vuln=cve-2026-64109","title":{"rendered":"CVE-2026-64109 [HIGH] &#8211; In the Linux kernel, the following vulnerability has been resolved:\n\naf_unix: Fix UAF read"},"content":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>af_unix: Fix UAF read of tail-&gt;len in unix_stream_data_wait()<\/p>\n<p>unix_stream_data_wait() does skb_peek_tail(&amp;sk-&gt;sk_receive_queue) without<br \/>\nholding any lock that prevents SKBs on that queue from being dequeued and<br \/>\nfreed.<br \/>\nThis has been the case since commit 79f632c71bea (&#8220;unix\/stream: fix<br \/>\npeeking with an offset larger than data in queue&#8221;).<br \/>\nThe first consequence of this is that the pointer comparison<br \/>\n`tail != last` can be false even if `last` semantically refers to an<br \/>\nalready-freed SKB while `tail` is a new SKB allocated at the same address;<br \/>\nwhich can cause unix_stream_data_wait() to wrongly keep blocking after new<br \/>\ndata has arrived, but only in a weird scenario where a peeking recv() and<br \/>\na normal recv() on the same socket are racing, which is probably not a<br \/>\nreal problem.<\/p>\n<p>But since commit 2b514574f7e8 (&#8220;net: af_unix: implement splice for stream<br \/>\naf_unix sockets&#8221;), `tail` is actually dereferenced, which can cause UAF in<br \/>\nthe following race scenario (where test_setup() runs single-threaded,<br \/>\nand afterwards, test_thread1() and test_thread2() run concurrently in<br \/>\ntwo threads:<br \/>\n&#8220;`<br \/>\nstatic int socks[2];<br \/>\nvoid test_setup(void) {<br \/>\n  socketpair(AF_UNIX, SOCK_STREAM, 0, socks);<br \/>\n  send(socks[1], &#8220;A&#8221;, 1, 0);<br \/>\n  int peekoff = 1;<br \/>\n  setsockopt(socks[0], SOL_SOCKET, SO_PEEK_OFF, &amp;peekoff, sizeof(peekoff));<br \/>\n}<br \/>\nvoid test_thread1(void) {<br \/>\n  char dummy;<br \/>\n  recv(socks[0], &amp;dummy, 1, MSG_PEEK);<br \/>\n}<br \/>\nvoid test_thread2(void) {<br \/>\n  char dummy;<br \/>\n  recv(socks[0], &amp;dummy, 1, 0);<br \/>\n  shutdown(socks[1], SHUT_WR);<br \/>\n}<br \/>\n&#8220;`<\/p>\n<p>when racing like this:<br \/>\n&#8220;`<br \/>\nthread1                       thread2<br \/>\nunix_stream_read_generic<br \/>\n  mutex_lock(&amp;u-&gt;iolock)<br \/>\n  skb_peek(&amp;sk-&gt;sk_receive_queue)<br \/>\n  skb_peek_next(skb, &amp;sk-&gt;sk_receive_queue)<br \/>\n  mutex_unlock(&amp;u-&gt;iolock)<br \/>\n                              unix_stream_read_generic<br \/>\n                                unix_state_lock(sk)<br \/>\n                                skb_peek(&amp;sk-&gt;sk_receive_queue)<br \/>\n                                unix_state_unlock(sk)<br \/>\n  unix_stream_data_wait<br \/>\n    unix_state_lock(sk)<br \/>\n    tail = skb_peek_tail(&amp;sk-&gt;sk_receive_queue)<br \/>\n                                spin_lock(&amp;sk-&gt;sk_receive_queue.lock)<br \/>\n                                __skb_unlink(skb, &amp;sk-&gt;sk_receive_queue)<br \/>\n                                spin_unlock(&amp;sk-&gt;sk_receive_queue.lock)<br \/>\n                                consume_skb(skb) [frees the SKB]<br \/>\n    `tail != last`: false<br \/>\n    `tail`: true<br \/>\n    `tail-&gt;len != last_len` ***UAF***<br \/>\n&#8220;`<\/p>\n<p>Fix the UAF by removing the read of tail-&gt;len; checking tail-&gt;len would<br \/>\nonly make sense if SKBs in the receive queue of a UNIX socket could grow,<br \/>\nwhich can no longer happen.<\/p>\n<p>Kuniyuki explained:<\/p>\n<p>&gt; When commit 869e7c62486e (&#8220;net: af_unix: implement stream sendpage<br \/>\n&gt; support&#8221;) added sendpage() support, data could be appended to the last<br \/>\n&gt; skb in the receiver&#8217;s queue.<br \/>\n&gt;<br \/>\n&gt; That&#8217;s why we needed to check if the length of the last skb was changed<br \/>\n&gt; while waiting for new data in unix_stream_data_wait().<br \/>\n&gt;<br \/>\n&gt; However, commit a0dbf5f818f9 (&#8220;af_unix: Support MSG_SPLICE_PAGES&#8221;) and<br \/>\n&gt; commit 57d44a354a43 (&#8220;unix: Convert unix_stream_sendpage() to use<br \/>\n&gt; MSG_SPLICE_PAGES&#8221;) refactored sendmsg(), and now data is always added<br \/>\n&gt; to a new skb.<\/p>\n<p>That means this fix is not suitable for kernels before 6.5.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the Linux kernel, the following vulnerability has been resolved:<\/p>\n<p>af_unix: Fix UAF read of tail-&gt;len in unix_stream_data_wait()<\/p>\n<p>unix_stream_data_wait() does skb_peek_tail(&amp;sk-&gt;sk_receive_queue) wi<\/p>\n","protected":false},"template":"","meta":[],"categories":[],"tags":[],"class_list":["post-15079","vuln","type-vuln","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln\/15079","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/vuln"}],"about":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=\/wp\/v2\/types\/vuln"}],"wp:attachment":[{"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=15079"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=15079"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.54iter.cn\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=15079"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}