KVM: SEV: Use READ_ONCE() when reading entries/indices from PSC buffer

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: 9b54e248d2 ("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>
This commit is contained in:
Sean Christopherson 2026-05-01 13:22:35 -07:00 committed by Paolo Bonzini
parent 121d88de56
commit c8cc238093

View 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 @@ static int snp_begin_psc(struct vcpu_svm *svm)
* 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 @@ static int snp_begin_psc(struct vcpu_svm *svm)
/* 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 @@ static int snp_begin_psc(struct vcpu_svm *svm)
* 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 ||