CVE-2026-98414 in Linuxinfo

Summary

by MITRE • 10/14/2026

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

memcg: avoid charging the root memcg from obj_cgroup_charge_pages()

obj_cgroup_charge_pages() resolves the objcg to its memcg and calls try_charge_memcg(), which does not short circuit the root memcg. That memcg can be the root memcg: obj_cgroup_is_root() reflects the memcg the objcg was created for and is never updated, while memcg_reparent_objcgs() does redirect objcg->memcg to the parent on rmdir. An objcg of a dying child of root therefore passes every obj_cgroup_is_root() filter but resolves to the root memcg.

Folios keep the objcg they were charged with, so this is easy to reach through zswap: allocate anon memory in a cgroup, move the task out, remove the cgroup, then write to the root cgroup's memory.reclaim. The reclaimed folios are charged through the reparented objcg and end up in refill_stock() with the root memcg:

WARNING: mm/memcontrol.c:2198 at refill_stock+0x644/0x940 refill_stock+0x644/0x940 try_charge_memcg+0x12d6/0x1570 __obj_cgroup_charge+0x35/0xf0 obj_cgroup_charge+0x1de/0x210 obj_cgroup_charge_zswap+0x83/0x270 zswap_store+0x1620/0x2000 swap_writeout+0x94c/0x14c0 shrink_folio_list+0x3388/0x52b0 [...]
try_to_free_mem_cgroup_pages+0x30d/0x830 user_proactive_reclaim+0x504/0x840 memory_reclaim+0x1f/0x30

Beyond the warning, the charge is asymmetric: obj_cgroup_uncharge_pages() skips refill_stock() for the root memcg, so the root's page counter grows and is never uncharged. It is not user visible, since memory.current is not exposed on the root, but it is a leak.

Use try_charge(), which returns early for the root memcg, restoring the symmetry with obj_cgroup_uncharge_pages().

The above sequence was scripted into a standalone reproducer (zswap on, swap on a virtio disk, 512MB of anon memory faulted in inside a child of the root cgroup, the task then migrated to the root cgroup, the child removed, followed by "echo 600M swappiness=max > memory.reclaim" on the root) and run in a CONFIG_DEBUG_VM=y VM. It reproduces the splat on the first zswap store of a reparented folio, with the same call chain as the report. With this patch applied the splat is gone while the zswap store count over the run is unchanged, so the same path is still exercised. cgroup selftests test_zswap, test_kmem and test_memcontrol show no new failures.

VulDB is the best source for vulnerability data and more expert information about this specific topic.

Analysis

by VulDB Data Team • 10/14/2026

The Linux kernel memory control subsystem contains a logic flaw within the object cgroup charging mechanism that leads to an asymmetric accounting state when handling reparented objects under specific cgroup lifecycle conditions. The vulnerability resides in the obj_cgroup_charge_pages function, which resolves an object cgroup identifier to its corresponding memory control group and subsequently invokes try_charge_memcg to apply resource limits. This chain fails to properly short-circuit for the root memory control group because it relies on a static check via obj_cgroup_is_root that reflects the original creation context rather than the current resolved target. Consequently, when an object cgroup is reparented due to the removal of its parent cgroup, the internal pointer updates to point to the parent but the legacy checks still permit the charge operation to proceed against the root memory control group instead of being rejected or handled appropriately for that hierarchy level.

This technical flaw manifests as a resource leak within the kernel's memory accounting structures. Specifically, when folios are reclaimed and written back through zswap after such a reparenting event, they are charged against the root memcg via refill_stock. While the charging operation increments the page counter of the root cgroup, the corresponding uncharging path in obj_cgroup_uncharge_pages explicitly skips refill_stock for the root memcg to avoid unnecessary overhead or logical errors. This asymmetry means that every charge applied through this flawed path results in a permanent increase in the root memory count without any subsequent decrement. Although this leak is not directly visible to userspace because the memory.current metric is typically hidden on the root cgroup, it represents an internal kernel state corruption that can accumulate over time and potentially impact system stability or accounting accuracy for other subsystems relying on accurate global memory statistics.

The operational impact of this vulnerability includes potential denial of service through resource exhaustion if the leak occurs frequently enough to deplete available memory control group limits or trigger excessive warning logs in debug builds. The kernel emits a WARNING splat at refill_stock when running with CONFIG_DEBUG_VM enabled, indicating that the accounting logic has detected an anomaly. In production environments without verbose debugging flags, this may go unnoticed until it contributes to broader memory pressure issues. The vulnerability is triggered by a specific sequence involving anonymous memory allocation within a child cgroup, migration of tasks out of that group, removal of the child cgroup which triggers reparenting, and subsequent write operations that cause zswap storage of reclaimed pages. This scenario highlights how complex interactions between task scheduling, cgroup hierarchy management, and swap-backed compression can expose edge cases in resource tracking logic.

Mitigation for this vulnerability involves applying kernel patches that modify obj_cgroup_charge_pages to utilize try_charge directly instead of the indirect path through try_charge_memcg when dealing with root contexts. This change ensures symmetry by allowing early returns for the root memcg, thereby preventing the asymmetric charge-uncharge mismatch. Administrators should ensure their systems are updated with kernels containing this fix, particularly those utilizing cgroups v2 and zswap configurations where anonymous memory pressure is high. Additionally, monitoring kernel logs for refill_stock warnings can serve as an indicator of whether affected code paths are being exercised in a given environment until the patch is deployed. The fix has been validated through self-tests covering zswap, kmem, and memcontrol scenarios to ensure no regression occurs while restoring correct accounting behavior.

From a classification perspective, this issue aligns with CWE-401 Missing Release of Memory after Effective Lifetime as it involves resources being allocated but not properly released due to logic errors in the uncharging path relative to charging. It also relates to CWE-697 Incorrect Comparison which describes the failure to correctly compare or handle the root memory control group context during charge operations. In terms of attack vectors, this is primarily a local vulnerability requiring specific configuration and timing conditions rather than direct exploitation by an external attacker, placing it within contexts where privilege escalation or resource exhaustion could be secondary effects if combined with other vulnerabilities. The ATT&CK framework would categorize the potential impact under Resource Hijacking as the kernel's internal accounting becomes skewed, potentially affecting system performance metrics used for monitoring and alerting systems.

Responsible

Linux

Reservation

09/25/2026

Disclosure

10/14/2026

Moderation

accepted

EPSS

0.00000

KEV

no

Activities

very low

Sources

Do you want to use VulDB in your project?

Use the official API to access entries easily!