From: tabba@google.com Date: Fri, 29 May 2026 12:17:54 +0000 (+0100) Subject: KVM: arm64: Avoid host/hyp share desync on unshare hypercall failure X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bd2618780ab4584a33ab1049338294a50690d149;p=thirdparty%2Flinux.git KVM: arm64: Avoid host/hyp share desync on unshare hypercall failure unshare_pfn_hyp() erases the tracking node from hyp_shared_pfns and frees it before invoking __pkvm_host_unshare_hyp. If the hypercall fails (e.g. EL2 refcount still held, or page-state mismatch), the host loses its record while EL2 still holds the share, breaking later share/unshare attempts on the same pfn. Invoke the hypercall first; erase and free only on success. Document at the kvm_unshare_hyp() call site that the WARN_ON() is left non-fatal: a failed unshare leaks the page (it stays shared with the hypervisor) but breaks no isolation guarantee. Fixes: 52b28657ebd7 ("KVM: arm64: pkvm: Unshare guest structs during teardown") Reported-by: Sashiko (local):gemini-3.1-pro Suggested-by: Vincent Donnefort Signed-off-by: Fuad Tabba Reviewed-by: Vincent Donnefort Link: https://patch.msgid.link/20260529121755.2923500-3-tabba@google.com Signed-off-by: Marc Zyngier --- diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 0abf3a2d587b..c82d4ececab8 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -524,13 +524,17 @@ static int unshare_pfn_hyp(u64 pfn) goto unlock; } - this->count--; - if (this->count) + if (this->count > 1) { + this->count--; + goto unlock; + } + + ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn); + if (ret) goto unlock; rb_erase(&this->node, &hyp_shared_pfns); kfree(this); - ret = kvm_call_hyp_nvhe(__pkvm_host_unshare_hyp, pfn); unlock: mutex_unlock(&hyp_shared_pfns_lock); @@ -581,6 +585,11 @@ void kvm_unshare_hyp(void *from, void *to) end = PAGE_ALIGN(__pa(to)); for (cur = start; cur < end; cur += PAGE_SIZE) { pfn = __phys_to_pfn(cur); + /* + * A failed unshare leaks the page: it stays shared with the + * hypervisor and is no longer reusable for pKVM. No isolation + * guarantee is broken, and this is not expected in practice. + */ WARN_ON(unshare_pfn_hyp(pfn)); } }