CVE-2025-21693

Severity CVSS v4.0:
Pending analysis
Type:
CWE-416 Use After Free
Publication date:
10/02/2025
Last modified:
16/04/2025

Description

In the Linux kernel, the following vulnerability has been resolved:<br /> <br /> mm: zswap: properly synchronize freeing resources during CPU hotunplug<br /> <br /> In zswap_compress() and zswap_decompress(), the per-CPU acomp_ctx of the<br /> current CPU at the beginning of the operation is retrieved and used<br /> throughout. However, since neither preemption nor migration are disabled,<br /> it is possible that the operation continues on a different CPU.<br /> <br /> If the original CPU is hotunplugged while the acomp_ctx is still in use,<br /> we run into a UAF bug as some of the resources attached to the acomp_ctx<br /> are freed during hotunplug in zswap_cpu_comp_dead() (i.e. <br /> acomp_ctx.buffer, acomp_ctx.req, or acomp_ctx.acomp).<br /> <br /> The problem was introduced in commit 1ec3b5fe6eec ("mm/zswap: move to use<br /> crypto_acomp API for hardware acceleration") when the switch to the<br /> crypto_acomp API was made. Prior to that, the per-CPU crypto_comp was<br /> retrieved using get_cpu_ptr() which disables preemption and makes sure the<br /> CPU cannot go away from under us. Preemption cannot be disabled with the<br /> crypto_acomp API as a sleepable context is needed.<br /> <br /> Use the acomp_ctx.mutex to synchronize CPU hotplug callbacks allocating<br /> and freeing resources with compression/decompression paths. Make sure<br /> that acomp_ctx.req is NULL when the resources are freed. In the<br /> compression/decompression paths, check if acomp_ctx.req is NULL after<br /> acquiring the mutex (meaning the CPU was offlined) and retry on the new<br /> CPU.<br /> <br /> The initialization of acomp_ctx.mutex is moved from the CPU hotplug<br /> callback to the pool initialization where it belongs (where the mutex is<br /> allocated). In addition to adding clarity, this makes sure that CPU<br /> hotplug cannot reinitialize a mutex that is already locked by<br /> compression/decompression.<br /> <br /> Previously a fix was attempted by holding cpus_read_lock() [1]. This<br /> would have caused a potential deadlock as it is possible for code already<br /> holding the lock to fall into reclaim and enter zswap (causing a<br /> deadlock). A fix was also attempted using SRCU for synchronization, but<br /> Johannes pointed out that synchronize_srcu() cannot be used in CPU hotplug<br /> notifiers [2].<br /> <br /> Alternative fixes that were considered/attempted and could have worked:<br /> - Refcounting the per-CPU acomp_ctx. This involves complexity in<br /> handling the race between the refcount dropping to zero in<br /> zswap_[de]compress() and the refcount being re-initialized when the<br /> CPU is onlined.<br /> - Disabling migration before getting the per-CPU acomp_ctx [3], but<br /> that&amp;#39;s discouraged and is a much bigger hammer than needed, and could<br /> result in subtle performance issues.<br /> <br /> [1]https://lkml.kernel.org/20241219212437.2714151-1-yosryahmed@google.com/<br /> [2]https://lkml.kernel.org/20250107074724.1756696-2-yosryahmed@google.com/<br /> [3]https://lkml.kernel.org/20250107222236.2715883-2-yosryahmed@google.com/<br /> <br /> [yosryahmed@google.com: remove comment]

Vulnerable products and versions

CPE From Up to
cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:* 5.11 (including) 6.12.12 (excluding)
cpe:2.3:o:linux:linux_kernel:6.13:rc1:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.13:rc2:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.13:rc3:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.13:rc4:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.13:rc5:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.13:rc6:*:*:*:*:*:*
cpe:2.3:o:linux:linux_kernel:6.13:rc7:*:*:*:*:*:*