CVE-2025-22058

Severity CVSS v4.0:
Pending analysis
Type:
Unavailable / Other
Publication date:
16/04/2025
Last modified:
17/04/2025

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> udp: Fix memory accounting leak.<br /> <br /> Matt Dowling reported a weird UDP memory usage issue.<br /> <br /> Under normal operation, the UDP memory usage reported in /proc/net/sockstat<br /> remains close to zero. However, it occasionally spiked to 524,288 pages<br /> and never dropped. Moreover, the value doubled when the application was<br /> terminated. Finally, it caused intermittent packet drops.<br /> <br /> We can reproduce the issue with the script below [0]:<br /> <br /> 1. /proc/net/sockstat reports 0 pages<br /> <br /> # cat /proc/net/sockstat | grep UDP:<br /> UDP: inuse 1 mem 0<br /> <br /> 2. Run the script till the report reaches 524,288<br /> <br /> # python3 test.py &amp; sleep 5<br /> # cat /proc/net/sockstat | grep UDP:<br /> UDP: inuse 3 mem 524288 &gt; PAGE_SHIFT<br /> <br /> 3. Kill the socket and confirm the number never drops<br /> <br /> # pkill python3 &amp;&amp; sleep 5<br /> # cat /proc/net/sockstat | grep UDP:<br /> UDP: inuse 1 mem 524288<br /> <br /> 4. (necessary since v6.0) Trigger proto_memory_pcpu_drain()<br /> <br /> # python3 test.py &amp; sleep 1 &amp;&amp; pkill python3<br /> <br /> 5. The number doubles<br /> <br /> # cat /proc/net/sockstat | grep UDP:<br /> UDP: inuse 1 mem 1048577<br /> <br /> The application set INT_MAX to SO_RCVBUF, which triggered an integer<br /> overflow in udp_rmem_release().<br /> <br /> When a socket is close()d, udp_destruct_common() purges its receive<br /> queue and sums up skb-&gt;truesize in the queue. This total is calculated<br /> and stored in a local unsigned integer variable.<br /> <br /> The total size is then passed to udp_rmem_release() to adjust memory<br /> accounting. However, because the function takes a signed integer<br /> argument, the total size can wrap around, causing an overflow.<br /> <br /> Then, the released amount is calculated as follows:<br /> <br /> 1) Add size to sk-&gt;sk_forward_alloc.<br /> 2) Round down sk-&gt;sk_forward_alloc to the nearest lower multiple of<br /> PAGE_SIZE and assign it to amount.<br /> 3) Subtract amount from sk-&gt;sk_forward_alloc.<br /> 4) Pass amount &gt;&gt; PAGE_SHIFT to __sk_mem_reduce_allocated().<br /> <br /> When the issue occurred, the total in udp_destruct_common() was 2147484480<br /> (INT_MAX + 833), which was cast to -2147482816 in udp_rmem_release().<br /> <br /> At 1) sk-&gt;sk_forward_alloc is changed from 3264 to -2147479552, and<br /> 2) sets -2147479552 to amount. 3) reverts the wraparound, so we don&amp;#39;t<br /> see a warning in inet_sock_destruct(). However, udp_memory_allocated<br /> ends up doubling at 4).<br /> <br /> Since commit 3cd3399dd7a8 ("net: implement per-cpu reserves for<br /> memory_allocated"), memory usage no longer doubles immediately after<br /> a socket is close()d because __sk_mem_reduce_allocated() caches the<br /> amount in udp_memory_per_cpu_fw_alloc. However, the next time a UDP<br /> socket receives a packet, the subtraction takes effect, causing UDP<br /> memory usage to double.<br /> <br /> This issue makes further memory allocation fail once the socket&amp;#39;s<br /> sk-&gt;sk_rmem_alloc exceeds net.ipv4.udp_rmem_min, resulting in packet<br /> drops.<br /> <br /> To prevent this issue, let&amp;#39;s use unsigned int for the calculation and<br /> call sk_forward_alloc_add() only once for the small delta.<br /> <br /> Note that first_packet_length() also potentially has the same problem.<br /> <br /> [0]:<br /> from socket import *<br /> <br /> SO_RCVBUFFORCE = 33<br /> INT_MAX = (2 ** 31) - 1<br /> <br /> s = socket(AF_INET, SOCK_DGRAM)<br /> s.bind((&amp;#39;&amp;#39;, 0))<br /> s.setsockopt(SOL_SOCKET, SO_RCVBUFFORCE, INT_MAX)<br /> <br /> c = socket(AF_INET, SOCK_DGRAM)<br /> c.connect(s.getsockname())<br /> <br /> data = b&amp;#39;a&amp;#39; * 100<br /> <br /> while True:<br /> c.send(data)

Impact