]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: SVM: Properly check RAX in the emulator for SVM instructions
authorYosry Ahmed <yosry@kernel.org>
Mon, 16 Mar 2026 20:27:24 +0000 (20:27 +0000)
committerSean Christopherson <seanjc@google.com>
Fri, 3 Apr 2026 23:08:00 +0000 (16:08 -0700)
Architecturally, VMRUN/VMLOAD/VMSAVE should generate a #GP if the
physical address in RAX is not supported. check_svme_pa() hardcodes this
to checking that bits 63-48 are not set. This is incorrect on HW
supporting 52 bits of physical address space. Additionally, the emulator
does not check if the address is not aligned, which should also result
in #GP.

Use page_address_valid() which properly checks alignment and the address
legality based on the guest's MAXPHYADDR. Plumb it through
x86_emulate_ops, similar to is_canonical_addr(), to avoid directly
accessing the vCPU object in emulator code.

Fixes: 01de8b09e606 ("KVM: SVM: Add intercept checks for SVM instructions")
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Yosry Ahmed <yosry@kernel.org>
Link: https://patch.msgid.link/20260316202732.3164936-2-yosry@kernel.org
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/emulate.c
arch/x86/kvm/kvm_emulate.h
arch/x86/kvm/x86.c

index c8e292e9a24dfee3d46c5553de1231b05a58da3b..202c376ff5019a1fdc924e2ca50a73d9f49b7f91 100644 (file)
@@ -3874,8 +3874,7 @@ static int check_svme_pa(struct x86_emulate_ctxt *ctxt)
 {
        u64 rax = reg_read(ctxt, VCPU_REGS_RAX);
 
-       /* Valid physical address? */
-       if (rax & 0xffff000000000000ULL)
+       if (!ctxt->ops->page_address_valid(ctxt, rax))
                return emulate_gp(ctxt, 0);
 
        return check_svme(ctxt);
index fb3dab4b5a53e7cad211c7ba959c96a4fa387e36..0abff36d099429660bceb5888ab6abd9ccb7a3b0 100644 (file)
@@ -245,6 +245,8 @@ struct x86_emulate_ops {
 
        bool (*is_canonical_addr)(struct x86_emulate_ctxt *ctxt, gva_t addr,
                                  unsigned int flags);
+
+       bool (*page_address_valid)(struct x86_emulate_ctxt *ctxt, gpa_t gpa);
 };
 
 /* Type, address-of, and value of an instruction's operand. */
index aa29f90c6e963b785e6558526080f0966d9724be..2410401c57d8197d7ebcb0c41d76d317cfcfe97b 100644 (file)
@@ -8907,6 +8907,11 @@ static bool emulator_is_canonical_addr(struct x86_emulate_ctxt *ctxt,
        return !is_noncanonical_address(addr, emul_to_vcpu(ctxt), flags);
 }
 
+static bool emulator_page_address_valid(struct x86_emulate_ctxt *ctxt, gpa_t gpa)
+{
+       return page_address_valid(emul_to_vcpu(ctxt), gpa);
+}
+
 static const struct x86_emulate_ops emulate_ops = {
        .vm_bugged           = emulator_vm_bugged,
        .read_gpr            = emulator_read_gpr,
@@ -8954,6 +8959,7 @@ static const struct x86_emulate_ops emulate_ops = {
        .set_xcr             = emulator_set_xcr,
        .get_untagged_addr   = emulator_get_untagged_addr,
        .is_canonical_addr   = emulator_is_canonical_addr,
+       .page_address_valid  = emulator_page_address_valid,
 };
 
 static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)