| From bippy-1.2.0 Mon Sep 17 00:00:00 2001 |
| From: Greg Kroah-Hartman <gregkh@kernel.org> |
| To: <linux-cve-announce@vger.kernel.org> |
| Reply-to: <cve@kernel.org>, <linux-kernel@vger.kernel.org> |
| Subject: CVE-2025-22058: udp: Fix memory accounting leak. |
| |
| Description |
| =========== |
| |
| In the Linux kernel, the following vulnerability has been resolved: |
| |
| udp: Fix memory accounting leak. |
| |
| Matt Dowling reported a weird UDP memory usage issue. |
| |
| Under normal operation, the UDP memory usage reported in /proc/net/sockstat |
| remains close to zero. However, it occasionally spiked to 524,288 pages |
| and never dropped. Moreover, the value doubled when the application was |
| terminated. Finally, it caused intermittent packet drops. |
| |
| We can reproduce the issue with the script below [0]: |
| |
| 1. /proc/net/sockstat reports 0 pages |
| |
| # cat /proc/net/sockstat | grep UDP: |
| UDP: inuse 1 mem 0 |
| |
| 2. Run the script till the report reaches 524,288 |
| |
| # python3 test.py & sleep 5 |
| # cat /proc/net/sockstat | grep UDP: |
| UDP: inuse 3 mem 524288 <-- (INT_MAX + 1) >> PAGE_SHIFT |
| |
| 3. Kill the socket and confirm the number never drops |
| |
| # pkill python3 && sleep 5 |
| # cat /proc/net/sockstat | grep UDP: |
| UDP: inuse 1 mem 524288 |
| |
| 4. (necessary since v6.0) Trigger proto_memory_pcpu_drain() |
| |
| # python3 test.py & sleep 1 && pkill python3 |
| |
| 5. The number doubles |
| |
| # cat /proc/net/sockstat | grep UDP: |
| UDP: inuse 1 mem 1048577 |
| |
| The application set INT_MAX to SO_RCVBUF, which triggered an integer |
| overflow in udp_rmem_release(). |
| |
| When a socket is close()d, udp_destruct_common() purges its receive |
| queue and sums up skb->truesize in the queue. This total is calculated |
| and stored in a local unsigned integer variable. |
| |
| The total size is then passed to udp_rmem_release() to adjust memory |
| accounting. However, because the function takes a signed integer |
| argument, the total size can wrap around, causing an overflow. |
| |
| Then, the released amount is calculated as follows: |
| |
| 1) Add size to sk->sk_forward_alloc. |
| 2) Round down sk->sk_forward_alloc to the nearest lower multiple of |
| PAGE_SIZE and assign it to amount. |
| 3) Subtract amount from sk->sk_forward_alloc. |
| 4) Pass amount >> PAGE_SHIFT to __sk_mem_reduce_allocated(). |
| |
| When the issue occurred, the total in udp_destruct_common() was 2147484480 |
| (INT_MAX + 833), which was cast to -2147482816 in udp_rmem_release(). |
| |
| At 1) sk->sk_forward_alloc is changed from 3264 to -2147479552, and |
| 2) sets -2147479552 to amount. 3) reverts the wraparound, so we don't |
| see a warning in inet_sock_destruct(). However, udp_memory_allocated |
| ends up doubling at 4). |
| |
| Since commit 3cd3399dd7a8 ("net: implement per-cpu reserves for |
| memory_allocated"), memory usage no longer doubles immediately after |
| a socket is close()d because __sk_mem_reduce_allocated() caches the |
| amount in udp_memory_per_cpu_fw_alloc. However, the next time a UDP |
| socket receives a packet, the subtraction takes effect, causing UDP |
| memory usage to double. |
| |
| This issue makes further memory allocation fail once the socket's |
| sk->sk_rmem_alloc exceeds net.ipv4.udp_rmem_min, resulting in packet |
| drops. |
| |
| To prevent this issue, let's use unsigned int for the calculation and |
| call sk_forward_alloc_add() only once for the small delta. |
| |
| Note that first_packet_length() also potentially has the same problem. |
| |
| [0]: |
| from socket import * |
| |
| SO_RCVBUFFORCE = 33 |
| INT_MAX = (2 ** 31) - 1 |
| |
| s = socket(AF_INET, SOCK_DGRAM) |
| s.bind(('', 0)) |
| s.setsockopt(SOL_SOCKET, SO_RCVBUFFORCE, INT_MAX) |
| |
| c = socket(AF_INET, SOCK_DGRAM) |
| c.connect(s.getsockname()) |
| |
| data = b'a' * 100 |
| |
| while True: |
| c.send(data) |
| |
| The Linux kernel CVE team has assigned CVE-2025-22058 to this issue. |
| |
| |
| Affected and fixed versions |
| =========================== |
| |
| Issue introduced in 4.10 with commit f970bd9e3a06f06df8d8ecf1f8ad2c8615cc17eb and fixed in 6.1.134 with commit 9122fec396950cc866137af7154b1d0d989be52e |
| Issue introduced in 4.10 with commit f970bd9e3a06f06df8d8ecf1f8ad2c8615cc17eb and fixed in 6.6.87 with commit aeef6456692c6f11ae53d278df64f1316a2a405a |
| Issue introduced in 4.10 with commit f970bd9e3a06f06df8d8ecf1f8ad2c8615cc17eb and fixed in 6.12.23 with commit a116b271bf3cb72c8155b6b7f39083c1b80dcd00 |
| Issue introduced in 4.10 with commit f970bd9e3a06f06df8d8ecf1f8ad2c8615cc17eb and fixed in 6.13.11 with commit c4bac6c398118fba79e32b1cd01db22dbfe29fbf |
| Issue introduced in 4.10 with commit f970bd9e3a06f06df8d8ecf1f8ad2c8615cc17eb and fixed in 6.14.2 with commit 3836029448e76c1e6f77cc5fe0adc09b018b5fa8 |
| Issue introduced in 4.10 with commit f970bd9e3a06f06df8d8ecf1f8ad2c8615cc17eb and fixed in 6.15 with commit df207de9d9e7a4d92f8567e2c539d9c8c12fd99d |
| |
| Please see https://www.kernel.org for a full list of currently supported |
| kernel versions by the kernel community. |
| |
| Unaffected versions might change over time as fixes are backported to |
| older supported kernel versions. The official CVE entry at |
| https://cve.org/CVERecord/?id=CVE-2025-22058 |
| will be updated if fixes are backported, please check that for the most |
| up to date information about this issue. |
| |
| |
| Affected files |
| ============== |
| |
| The file(s) affected by this issue are: |
| net/ipv4/udp.c |
| |
| |
| Mitigation |
| ========== |
| |
| The Linux kernel CVE team recommends that you update to the latest |
| stable kernel version for this, and many other bugfixes. Individual |
| changes are never tested alone, but rather are part of a larger kernel |
| release. Cherry-picking individual commits is not recommended or |
| supported by the Linux kernel community at all. If however, updating to |
| the latest release is impossible, the individual changes to resolve this |
| issue can be found at these commits: |
| https://git.kernel.org/stable/c/9122fec396950cc866137af7154b1d0d989be52e |
| https://git.kernel.org/stable/c/aeef6456692c6f11ae53d278df64f1316a2a405a |
| https://git.kernel.org/stable/c/a116b271bf3cb72c8155b6b7f39083c1b80dcd00 |
| https://git.kernel.org/stable/c/c4bac6c398118fba79e32b1cd01db22dbfe29fbf |
| https://git.kernel.org/stable/c/3836029448e76c1e6f77cc5fe0adc09b018b5fa8 |
| https://git.kernel.org/stable/c/df207de9d9e7a4d92f8567e2c539d9c8c12fd99d |