From a5264387c2ee42fca92ac792199008fc60ee82f1 Mon Sep 17 00:00:00 2001 From: Manuel Andreas Date: Thu, 19 Feb 2026 21:05:49 +0100 Subject: [PATCH] KVM: x86: hyper-v: Validate all GVAs during PV TLB flush In KVM guests with Hyper-V hypercalls enabled, the hypercalls HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST and HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST_EX allow a guest to request invalidation of portions of a virtual TLB. For this, the hypercall parameter includes a list of GVAs that are supposed to be invalidated. Currently, only the base GVA is checked to be canonical. In reality, this check needs to be performed for the entire range of GVAs, as checking only the base GVA enables guests running on Intel hardware to trigger a WARN_ONCE in the host (see Fixes commit below). Move the check for non-canonical addresses to be performed for every GVA of the supplied range to avoid the splat, and to be more in line with the Hyper-V specification, since, although unlikely, a range starting with an invalid GVA may still contain GVAs that are valid. Fixes: fa787ac07b3c ("KVM: x86/hyper-v: Skip non-canonical addresses during PV TLB flush") Signed-off-by: Manuel Andreas Reviewed-by: Vitaly Kuznetsov Link: https://patch.msgid.link/00a7a31b-573b-4d92-91f8-7d7e2f88ea48@tum.de [sean: massage changelog] Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/hyperv.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 30202942289a..9b140bbdc1d8 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1981,16 +1981,17 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcpu *vcpu) if (entries[i] == KVM_HV_TLB_FLUSHALL_ENTRY) goto out_flush_all; - if (is_noncanonical_invlpg_address(entries[i], vcpu)) - continue; - /* * Lower 12 bits of 'address' encode the number of additional * pages to flush. */ gva = entries[i] & PAGE_MASK; - for (j = 0; j < (entries[i] & ~PAGE_MASK) + 1; j++) + for (j = 0; j < (entries[i] & ~PAGE_MASK) + 1; j++) { + if (is_noncanonical_invlpg_address(gva + j * PAGE_SIZE, vcpu)) + continue; + kvm_x86_call(flush_tlb_gva)(vcpu, gva + j * PAGE_SIZE); + } ++vcpu->stat.tlb_flush; }