]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: SEV: Check PSC request indices against the actual size of the buffer
authorSean Christopherson <seanjc@google.com>
Fri, 1 May 2026 20:22:34 +0000 (13:22 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 29 May 2026 18:25:29 +0000 (20:25 +0200)
When processing Page State Change (PSC) requests, validate the PSC buffer
against the effective size of the scratch area, which could be less than
the maximum size if the guest provided a pointer that isn't exactly at the
start of the GHCB shared buffer.

Fixes: 9b54e248d264 ("KVM: SEV: Add support to handle Page State Change VMGEXIT")
Cc: stable@vger.kernel.org
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Reviewed-by: Michael Roth <michael.roth@amd.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20260501202250.2115252-10-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/svm/sev.c

index 8577451b82b27e8e71abe06c63fd259607648b15..6e8cbae2135a3be497e2698cfcec8f75d6a67d91 100644 (file)
@@ -3903,7 +3903,7 @@ static int snp_begin_psc(struct vcpu_svm *svm)
        struct kvm_vcpu *vcpu = &svm->vcpu;
        struct psc_hdr *hdr = &psc->hdr;
        struct psc_entry entry_start;
-       u16 idx, idx_start, idx_end;
+       u16 idx, idx_start, idx_end, max_nr_entries;
        int npages;
        bool huge;
        u64 gfn;
@@ -3913,6 +3913,19 @@ static int snp_begin_psc(struct vcpu_svm *svm)
                return 1;
        }
 
+       /*
+        * GHCB v2 requires the scratch area to reside within the GHCB itself,
+        * and PSC requests are only supported for GHCB v2+.  Thus it should be
+        * impossible to exceed the max PSC entry count (which is derived from
+        * the size of the shared GHCB buffer).
+        */
+       max_nr_entries = (sev_es->ghcb_sa_len - sizeof(struct psc_hdr)) /
+                        sizeof(struct psc_entry);
+       if (WARN_ON_ONCE(max_nr_entries > VMGEXIT_PSC_MAX_COUNT)) {
+               snp_complete_psc(svm, VMGEXIT_PSC_ERROR_GENERIC);
+               return 1;
+       }
+
 next_range:
        /* There should be no other PSCs in-flight at this point. */
        if (WARN_ON_ONCE(svm->sev_es.psc_inflight)) {
@@ -3928,7 +3941,7 @@ next_range:
        idx_start = hdr->cur_entry;
        idx_end = hdr->end_entry;
 
-       if (idx_end >= VMGEXIT_PSC_MAX_COUNT) {
+       if (idx_end >= max_nr_entries) {
                snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR);
                return 1;
        }