summaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorMaxim Levitsky <mlevitsk@redhat.com>2024-09-07 00:18:24 +0200
committerSean Christopherson <seanjc@google.com>2024-11-01 17:22:27 +0100
commit90a877216e6bd4cc336ecd85ad4e95cf7a1aa1c8 (patch)
tree8795556f872d710d867fb8e864f85a5f8625ba57 /arch/x86/kvm
parentKVM: x86: model canonical checks more precisely (diff)
downloadlinux-90a877216e6bd4cc336ecd85ad4e95cf7a1aa1c8.tar.xz
linux-90a877216e6bd4cc336ecd85ad4e95cf7a1aa1c8.zip
KVM: nVMX: fix canonical check of vmcs12 HOST_RIP
HOST_RIP canonical check should check the L1 of CR4.LA57 stored in the vmcs12 rather than the current L1's because it is legal to change the CR4.LA57 value during VM exit from L2 to L1. This is a theoretical bug though, because it is highly unlikely that a VM exit will change the CR4.LA57 from the value it had on VM entry. Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com> Link: https://lore.kernel.org/r/20240906221824.491834-5-mlevitsk@redhat.com Signed-off-by: Sean Christopherson <seanjc@google.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/vmx/nested.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
index 7ce44437394d..66c6d29fa5ec 100644
--- a/arch/x86/kvm/vmx/nested.c
+++ b/arch/x86/kvm/vmx/nested.c
@@ -2996,6 +2996,17 @@ static int nested_vmx_check_address_space_size(struct kvm_vcpu *vcpu,
return 0;
}
+static bool is_l1_noncanonical_address_on_vmexit(u64 la, struct vmcs12 *vmcs12)
+{
+ /*
+ * Check that the given linear address is canonical after a VM exit
+ * from L2, based on HOST_CR4.LA57 value that will be loaded for L1.
+ */
+ u8 l1_address_bits_on_exit = (vmcs12->host_cr4 & X86_CR4_LA57) ? 57 : 48;
+
+ return !__is_canonical_address(la, l1_address_bits_on_exit);
+}
+
static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
struct vmcs12 *vmcs12)
{
@@ -3046,7 +3057,7 @@ static int nested_vmx_check_host_state(struct kvm_vcpu *vcpu,
CC(is_noncanonical_base_address(vmcs12->host_gdtr_base, vcpu)) ||
CC(is_noncanonical_base_address(vmcs12->host_idtr_base, vcpu)) ||
CC(is_noncanonical_base_address(vmcs12->host_tr_base, vcpu)) ||
- CC(is_noncanonical_address(vmcs12->host_rip, vcpu, 0)))
+ CC(is_l1_noncanonical_address_on_vmexit(vmcs12->host_rip, vmcs12)))
return -EINVAL;
/*