]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: x86: Harden SEV-ES MMIO against on-stack use-after-free
authorSean Christopherson <seanjc@google.com>
Wed, 25 Feb 2026 01:20:42 +0000 (17:20 -0800)
committerSean Christopherson <seanjc@google.com>
Tue, 3 Mar 2026 00:02:52 +0000 (16:02 -0800)
Add a sanity check to ensure KVM doesn't use an on-stack variable when
handling an MMIO request for an SEV-ES guest.  The source/destination
for SEV-ES MMIO should _always_ be the #VMGEXIT scratch area.

Opportunistically update the comment in the completion side of things
to clarify that frag->data doesn't need to be copied anywhere, and the
VMEGEXIT is trap-like (the current comment doesn't clarify *how* RIP is
advanced).

Tested-by: Tom Lendacky <thomas.lendacky@gmail.com>
Tested-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Link: https://patch.msgid.link/20260225012049.920665-8-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/x86.c

index 0f4cfc3374a68ec5d88c8b6b4013b3252ed576b7..5752ec3fc8f2f693c69d993975ca00d4aef4d625 100644 (file)
@@ -14272,8 +14272,10 @@ static int complete_sev_es_emulated_mmio(struct kvm_vcpu *vcpu)
        if (vcpu->mmio_cur_fragment >= vcpu->mmio_nr_fragments) {
                vcpu->mmio_needed = 0;
 
-               // VMG change, at this point, we're always done
-               // RIP has already been advanced
+               /*
+                * All done, as frag->data always points at the GHCB scratch
+                * area and VMGEXIT is trap-like (RIP is advanced by hardware).
+                */
                return 1;
        }
 
@@ -14296,7 +14298,7 @@ int kvm_sev_es_mmio_write(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes,
        int handled;
        struct kvm_mmio_fragment *frag;
 
-       if (!data)
+       if (!data || WARN_ON_ONCE(object_is_on_stack(data)))
                return -EINVAL;
 
        handled = write_emultor.read_write_mmio(vcpu, gpa, bytes, data);
@@ -14335,7 +14337,7 @@ int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes,
        int handled;
        struct kvm_mmio_fragment *frag;
 
-       if (!data)
+       if (!data || WARN_ON_ONCE(object_is_on_stack(data)))
                return -EINVAL;
 
        handled = read_emultor.read_write_mmio(vcpu, gpa, bytes, data);