]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: SEV: Use READ_ONCE() when reading entries/indices from PSC buffer
authorSean Christopherson <seanjc@google.com>
Fri, 1 May 2026 20:22:35 +0000 (13:22 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 29 May 2026 18:25:29 +0000 (20:25 +0200)
Use READ_ONCE() when reading entries/indices from the guest-accessible
Page State Change buffer to defend against TOCTOU bugs.

Don't bother with READ_ONCE()/WRITE_ONCE() for cases where KVM is writing
(and not consuming the result!), as the guest isn't supposed to touch the
buffer while it's being processed.  I.e. using READ_ONCE() is all about
protecting against misbehaving guests.

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>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-ID: <20260501202250.2115252-11-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/svm/sev.c

index 6e8cbae2135a3be497e2698cfcec8f75d6a67d91..62b5befe0eed90769273a6eea3ddfca8f9147da2 100644 (file)
@@ -3872,9 +3872,9 @@ static void __snp_complete_one_psc(struct vcpu_svm *svm)
         */
        for (idx = svm->sev_es.psc_idx; svm->sev_es.psc_inflight;
             svm->sev_es.psc_inflight--, idx++) {
-               struct psc_entry *entry = &entries[idx];
+               struct psc_entry entry = READ_ONCE(entries[idx]);
 
-               entry->cur_page = entry->pagesize ? 512 : 1;
+               entries[idx].cur_page = entry.pagesize ? 512 : 1;
        }
 
        hdr->cur_entry = idx;
@@ -3938,8 +3938,8 @@ next_range:
         * validation, so take care to only use validated copies of values used
         * for things like array indexing.
         */
-       idx_start = hdr->cur_entry;
-       idx_end = hdr->end_entry;
+       idx_start = READ_ONCE(hdr->cur_entry);
+       idx_end = READ_ONCE(hdr->end_entry);
 
        if (idx_end >= max_nr_entries) {
                snp_complete_psc(svm, VMGEXIT_PSC_ERROR_INVALID_HDR);
@@ -3948,7 +3948,7 @@ next_range:
 
        /* Find the start of the next range which needs processing. */
        for (idx = idx_start; idx <= idx_end; idx++, hdr->cur_entry++) {
-               entry_start = entries[idx];
+               entry_start = READ_ONCE(entries[idx]);
 
                gfn = entry_start.gfn;
                huge = entry_start.pagesize;
@@ -3992,7 +3992,7 @@ next_range:
         * KVM_HC_MAP_GPA_RANGE exit.
         */
        while (++idx <= idx_end) {
-               struct psc_entry entry = entries[idx];
+               struct psc_entry entry = READ_ONCE(entries[idx]);
 
                if (entry.operation != entry_start.operation ||
                    entry.gfn != entry_start.gfn + npages ||