kvm_vm_set_mem_attributes() passes GFP_KERNEL_ACCOUNT when reserving xarray entries, but the nodes are allocated by xas_alloc(), which hardcodes GFP_NOWAIT and only adds __GFP_ACCOUNT when the xarray carries XA_FLAGS_ACCOUNT. mem_attr_array is initialized with plain xa_init(), so the flag is never set and nodes taken from that fast path -- the overwhelming majority -- are not charged to the caller; only the rare __xas_nomem() slow path is, because it receives the caller's gfp. Measured on v6.18.48: a process in a cgroup limited to 256 MiB grew radix_tree_node slab by ~512 MiB while its memory.current stayed near 0. Per-tenant memcg limits therefore do not contain the growth. Set XA_FLAGS_ACCOUNT so the intended accounting takes effect. Note this is a change in reachability, not in contract. KVM_SET_MEMORY_ATTRIBUTES could already return -ENOMEM, but only under global memory pressure, since the fast path allocated with plain GFP_NOWAIT. With the nodes accounted, a tenant under a memory.max limit can now hit it from a cgroup-local condition, i.e. conversions that previously succeeded may fail. That is intended and matches every other GFP_KERNEL_ACCOUNT allocation in KVM; the alternative is letting the tenant grow host memory that is never charged to it. Userspace driving conversions from guest KVM_HC_MAP_GPA_RANGE hypercalls surfaces the failure on that path. Runtime-verified on v6.18.48 (isolated VM, no KASAN): without the flag a process in a 256 MiB cgroup materializes 512 MiB of radix_tree_node slab with memory.current flat (the memcg is inert); with the flag the same process is contained by the cgroup -- the memcg OOM killer selects the attacker inside its own slice (CONSTRAINT_MEMCG) instead of exhausting global memory. Found by an AI-assisted security audit. Not tagged for stable: unlike 1/3 and 2/3, which are pure corrections, this one changes observable behaviour, and new -ENOMEM returns for cgroup-limited tenants are a poor fit for stable's regression-risk bar. Happy to send it to stable separately if maintainers disagree. Fixes: 5a475554db1e ("KVM: Introduce per-page memory attributes") Assisted-by: Claude-Code:claude-opus-5 Signed-off-by: David Ballesteros --- virt/kvm/kvm_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1116,7 +1116,7 @@ static struct kvm *kvm_create_vm(unsigned long type, const char *fdname) rcuwait_init(&kvm->mn_memslots_update_rcuwait); xa_init(&kvm->vcpu_array); #ifdef CONFIG_KVM_GENERIC_MEMORY_ATTRIBUTES - xa_init(&kvm->mem_attr_array); + xa_init_flags(&kvm->mem_attr_array, XA_FLAGS_ACCOUNT); #endif INIT_LIST_HEAD(&kvm->gpc_list);