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&#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]
Impact
Base Score 3.x
7.80
Severity 3.x
HIGH
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:*:*:*:*:*:* |
To consult the complete list of CPE names with products and versions, see this page



