From: Fuad Tabba Date: Wed, 4 Mar 2026 16:22:21 +0000 (+0000) Subject: KVM: arm64: Fix page leak in user_mem_abort() on atomic fault X-Git-Tag: v7.0-rc4~4^2~20^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e07fc9e2da91f6d9eeafa2961be9dc09d65ed633;p=thirdparty%2Fkernel%2Fstable.git KVM: arm64: Fix page leak in user_mem_abort() on atomic fault When a guest performs an atomic/exclusive operation on memory lacking the required attributes, user_mem_abort() injects a data abort and returns early. However, it fails to release the reference to the host page acquired via __kvm_faultin_pfn(). A malicious guest could repeatedly trigger this fault, leaking host page references and eventually causing host memory exhaustion (OOM). Fix this by consolidating the early error returns to a new out_put_page label that correctly calls kvm_release_page_unused(). Fixes: 2937aeec9dc5 ("KVM: arm64: Handle DABT caused by LS64* instructions on unsupported memory") Signed-off-by: Fuad Tabba Reviewed-by: Yuan Yao Link: https://patch.msgid.link/20260304162222.836152-2-tabba@google.com Signed-off-by: Marc Zyngier --- diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index ec2eee857208e..e1d6a4f591a96 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1837,10 +1837,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (exec_fault && s2_force_noncacheable) ret = -ENOEXEC; - if (ret) { - kvm_release_page_unused(page); - return ret; - } + if (ret) + goto out_put_page; /* * Guest performs atomic/exclusive operations on memory with unsupported @@ -1850,7 +1848,8 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, */ if (esr_fsc_is_excl_atomic_fault(kvm_vcpu_get_esr(vcpu))) { kvm_inject_dabt_excl_atomic(vcpu, kvm_vcpu_get_hfar(vcpu)); - return 1; + ret = 1; + goto out_put_page; } if (nested) @@ -1936,6 +1935,10 @@ out_unlock: mark_page_dirty_in_slot(kvm, memslot, gfn); return ret != -EAGAIN ? ret : 0; + +out_put_page: + kvm_release_page_unused(page); + return ret; } /* Resolve the access fault by making the page young again. */