Skip to content

Commit 4135a9a

Browse files
committed
KVM: SEV: Validate XCR0 provided by guest in GHCB
Use __kvm_set_xcr() to propagate XCR0 changes from the GHCB to KVM's software model in order to validate the new XCR0 against KVM's view of the supported XCR0. Allowing garbage is thankfully mostly benign, as kvm_load_{guest,host}_xsave_state() bail early for vCPUs with protected state, xstate_required_size() will simply provide garbage back to the guest, and attempting to save/restore the bad value via KVM_{G,S}ET_XCRS will only harm the guest (setting XCR0 will fail). However, allowing the guest to put junk into a field that KVM assumes is valid is a CVE waiting to happen. And as a bonus, using the proper API eliminates the ugly open coding of setting arch.cpuid_dynamic_bits_dirty. Simply ignore bad values, as either the guest managed to get an unsupported value into hardware, or the guest is misbehaving and providing pure garbage. In either case, KVM can't fix the broken guest. Note, using __kvm_set_xcr() also avoids recomputing dynamic CPUID bits if XCR0 isn't actually changing (relatively to KVM's previous snapshot). Cc: Tom Lendacky <thomas.lendacky@amd.com> Fixes: 291bd20 ("KVM: SVM: Add initial support for a VMGEXIT VMEXIT") Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com> Link: https://lore.kernel.org/r/20250919223258.1604852-4-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent bd5f500 commit 4135a9a

File tree

3 files changed

+5
-5
lines changed

3 files changed

+5
-5
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2187,6 +2187,7 @@ int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val);
21872187
unsigned long kvm_get_dr(struct kvm_vcpu *vcpu, int dr);
21882188
unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu);
21892189
void kvm_lmsw(struct kvm_vcpu *vcpu, unsigned long msw);
2190+
int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr);
21902191
int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu);
21912192

21922193
int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr);

arch/x86/kvm/svm/sev.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3307,10 +3307,8 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
33073307

33083308
svm->vmcb->save.cpl = kvm_ghcb_get_cpl_if_valid(svm);
33093309

3310-
if (kvm_ghcb_xcr0_is_valid(svm)) {
3311-
vcpu->arch.xcr0 = kvm_ghcb_get_xcr0(svm);
3312-
vcpu->arch.cpuid_dynamic_bits_dirty = true;
3313-
}
3310+
if (kvm_ghcb_xcr0_is_valid(svm))
3311+
__kvm_set_xcr(vcpu, 0, kvm_ghcb_get_xcr0(svm));
33143312

33153313
/* Copy the GHCB exit information into the VMCB fields */
33163314
exit_code = kvm_ghcb_get_sw_exit_code(svm);

arch/x86/kvm/x86.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1237,7 +1237,7 @@ static inline u64 kvm_guest_supported_xfd(struct kvm_vcpu *vcpu)
12371237
}
12381238
#endif
12391239

1240-
static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
1240+
int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
12411241
{
12421242
u64 xcr0 = xcr;
12431243
u64 old_xcr0 = vcpu->arch.xcr0;
@@ -1281,6 +1281,7 @@ static int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr)
12811281
vcpu->arch.cpuid_dynamic_bits_dirty = true;
12821282
return 0;
12831283
}
1284+
EXPORT_SYMBOL_GPL(__kvm_set_xcr);
12841285

12851286
int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu)
12861287
{

0 commit comments

Comments
 (0)