| From stable+bounces-164475-greg=kroah.com@vger.kernel.org Wed Jul 23 17:19:05 2025 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 23 Jul 2025 11:14:16 -0400 |
| Subject: KVM: x86/hyper-v: Skip non-canonical addresses during PV TLB flush |
| To: stable@vger.kernel.org |
| Cc: Manuel Andreas <manuel.andreas@tum.de>, Vitaly Kuznetsov <vkuznets@redhat.com>, Sean Christopherson <seanjc@google.com>, Sasha Levin <sashal@kernel.org> |
| Message-ID: <20250723151416.1092631-5-sashal@kernel.org> |
| |
| From: Manuel Andreas <manuel.andreas@tum.de> |
| |
| [ Upstream commit fa787ac07b3ceb56dd88a62d1866038498e96230 ] |
| |
| 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. |
| |
| However, when non-canonical GVAs are passed, there is currently no |
| filtering in place and they are eventually passed to checked invocations of |
| INVVPID on Intel / INVLPGA on AMD. While AMD's INVLPGA silently ignores |
| non-canonical addresses (effectively a no-op), Intel's INVVPID explicitly |
| signals VM-Fail and ultimately triggers the WARN_ONCE in invvpid_error(): |
| |
| invvpid failed: ext=0x0 vpid=1 gva=0xaaaaaaaaaaaaa000 |
| WARNING: CPU: 6 PID: 326 at arch/x86/kvm/vmx/vmx.c:482 |
| invvpid_error+0x91/0xa0 [kvm_intel] |
| Modules linked in: kvm_intel kvm 9pnet_virtio irqbypass fuse |
| CPU: 6 UID: 0 PID: 326 Comm: kvm-vm Not tainted 6.15.0 #14 PREEMPT(voluntary) |
| RIP: 0010:invvpid_error+0x91/0xa0 [kvm_intel] |
| Call Trace: |
| vmx_flush_tlb_gva+0x320/0x490 [kvm_intel] |
| kvm_hv_vcpu_flush_tlb+0x24f/0x4f0 [kvm] |
| kvm_arch_vcpu_ioctl_run+0x3013/0x5810 [kvm] |
| |
| Hyper-V documents that invalid GVAs (those that are beyond a partition's |
| GVA space) are to be ignored. While not completely clear whether this |
| ruling also applies to non-canonical GVAs, it is likely fine to make that |
| assumption, and manual testing on Azure confirms "real" Hyper-V interprets |
| the specification in the same way. |
| |
| Skip non-canonical GVAs when processing the list of address to avoid |
| tripping the INVVPID failure. Alternatively, KVM could filter out "bad" |
| GVAs before inserting into the FIFO, but practically speaking the only |
| downside of pushing validation to the final processing is that doing so |
| is suboptimal for the guest, and no well-behaved guest will request TLB |
| flushes for non-canonical addresses. |
| |
| Fixes: 260970862c88 ("KVM: x86: hyper-v: Handle HVCALL_FLUSH_VIRTUAL_ADDRESS_LIST{,EX} calls gently") |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Manuel Andreas <manuel.andreas@tum.de> |
| Suggested-by: Vitaly Kuznetsov <vkuznets@redhat.com> |
| Link: https://lore.kernel.org/r/c090efb3-ef82-499f-a5e0-360fc8420fb7@tum.de |
| Signed-off-by: Sean Christopherson <seanjc@google.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/kvm/hyperv.c | 3 +++ |
| 1 file changed, 3 insertions(+) |
| |
| --- a/arch/x86/kvm/hyperv.c |
| +++ b/arch/x86/kvm/hyperv.c |
| @@ -1980,6 +1980,9 @@ int kvm_hv_vcpu_flush_tlb(struct kvm_vcp |
| 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. |