Skip to content

Commit 71bf395

Browse files
committed
KVM: x86: Enforce x2APIC's must-be-zero reserved ICR bits
Inject a #GP on a WRMSR(ICR) that attempts to set any reserved bits that are must-be-zero on both Intel and AMD, i.e. any reserved bits other than the BUSY bit, which Intel ignores and basically says is undefined. KVM's xapic_state_test selftest has been fudging the bug since commit 4b88b1a ("KVM: selftests: Enhance handling WRMSR ICR register in x2APIC mode"), which essentially removed the testcase instead of fixing the bug. WARN if the nodecode path triggers a #GP, as the CPU is supposed to check reserved bits for ICR when it's partially virtualized. Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sean Christopherson <[email protected]>
1 parent 44dd0f5 commit 71bf395

File tree

1 file changed

+14
-1
lines changed

1 file changed

+14
-1
lines changed

arch/x86/kvm/lapic.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2470,7 +2470,7 @@ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset)
24702470
* maybe-unecessary write, and both are in the noise anyways.
24712471
*/
24722472
if (apic_x2apic_mode(apic) && offset == APIC_ICR)
2473-
kvm_x2apic_icr_write(apic, kvm_lapic_get_reg64(apic, APIC_ICR));
2473+
WARN_ON_ONCE(kvm_x2apic_icr_write(apic, kvm_lapic_get_reg64(apic, APIC_ICR)));
24742474
else
24752475
kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset));
24762476
}
@@ -3194,8 +3194,21 @@ int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
31943194
return 0;
31953195
}
31963196

3197+
#define X2APIC_ICR_RESERVED_BITS (GENMASK_ULL(31, 20) | GENMASK_ULL(17, 16) | BIT(13))
3198+
31973199
int kvm_x2apic_icr_write(struct kvm_lapic *apic, u64 data)
31983200
{
3201+
if (data & X2APIC_ICR_RESERVED_BITS)
3202+
return 1;
3203+
3204+
/*
3205+
* The BUSY bit is reserved on both Intel and AMD in x2APIC mode, but
3206+
* only AMD requires it to be zero, Intel essentially just ignores the
3207+
* bit. And if IPI virtualization (Intel) or x2AVIC (AMD) is enabled,
3208+
* the CPU performs the reserved bits checks, i.e. the underlying CPU
3209+
* behavior will "win". Arbitrarily clear the BUSY bit, as there is no
3210+
* sane way to provide consistent behavior with respect to hardware.
3211+
*/
31993212
data &= ~APIC_ICR_BUSY;
32003213

32013214
kvm_apic_send_ipi(apic, (u32)data, (u32)(data >> 32));

0 commit comments

Comments
 (0)