CVE-2025-21860

mm/zswap: fix inconsistency when zswap_store_page() fails

published March 12, 2025

CVSS
—
EPSS
0%
Percentile
12.3
In the wild
Unconfirmed
What it is

In the Linux kernel, the following vulnerability has been resolved:

mm/zswap: fix inconsistency when zswap_store_page() fails

Commit b7c0ccdfbafd ("mm: zswap: support large folios in zswap_store()")

skips charging any zswap entries when it failed to zswap the entire folio.

However, when some base pages are zswapped but it failed to zswap the

entire folio, the zswap operation is rolled back. When freeing zswap

entries for those pages, zswap_entry_free() uncharges the zswap entries

that were not previously charged, causing zswap charging to become

inconsistent.

This inconsistency triggers two warnings with following steps:

# On a machine with 64GiB of RAM and 36GiB of zswap

$ stress-ng --bigheap 2 # wait until the OOM-killer kills stress-ng

$ sudo reboot

The two warnings are:

in mm/memcontrol.c:163, function obj_cgroup_release():

WARN_ON_ONCE(nr_bytes & (PAGE_SIZE - 1));

in mm/page_counter.c:60, function page_counter_cancel():

if (WARN_ONCE(new < 0, "page_counter underflow: %ld nr_pages=%lu\n",

new, nr_pages))

zswap_stored_pages also becomes inconsistent in the same way.

As suggested by Kanchana, increment zswap_stored_pages and charge zswap

entries within zswap_store_page() when it succeeds. This way,

zswap_entry_free() will decrement the counter and uncharge the entries

when it failed to zswap the entire folio.

While this could potentially be optimized by batching objcg charging and

incrementing the counter, let's focus on fixing the bug this time and

leave the optimization for later after some evaluation.

After resolving the inconsistency, the warnings disappear.

[[email protected]: refactor zswap_store_page()]

The record
Technical detail
CVSS
Not scored
CVSS v4.0
Not supplied
EPSS
0.00224 · 12.3th percentile
Published
2025-03-12T09:42Z
EPSS history
Timeline
  • 12 MAR 09:42Z
    mm/zswap: fix inconsistency when zswap_store_page() fails
    cvelistv5