Skip to content

Commit e99b21b

Browse files
sean-jcgregkh
authored andcommitted
KVM: x86: Make x2APIC ID 100% readonly
[ Upstream commit 4b7c3f6 ] Ignore the userspace provided x2APIC ID when fixing up APIC state for KVM_SET_LAPIC, i.e. make the x2APIC fully readonly in KVM. Commit a92e254 ("KVM: x86: use hardware-compatible format for APIC ID register"), which added the fixup, didn't intend to allow userspace to modify the x2APIC ID. In fact, that commit is when KVM first started treating the x2APIC ID as readonly, apparently to fix some race: static inline u32 kvm_apic_id(struct kvm_lapic *apic) { - return (kvm_lapic_get_reg(apic, APIC_ID) >> 24) & 0xff; + /* To avoid a race between apic_base and following APIC_ID update when + * switching to x2apic_mode, the x2apic mode returns initial x2apic id. + */ + if (apic_x2apic_mode(apic)) + return apic->vcpu->vcpu_id; + + return kvm_lapic_get_reg(apic, APIC_ID) >> 24; } Furthermore, KVM doesn't support delivering interrupts to vCPUs with a modified x2APIC ID, but KVM *does* return the modified value on a guest RDMSR and for KVM_GET_LAPIC. I.e. no remotely sane setup can actually work with a modified x2APIC ID. Making the x2APIC ID fully readonly fixes a WARN in KVM's optimized map calculation, which expects the LDR to align with the x2APIC ID. WARNING: CPU: 2 PID: 958 at arch/x86/kvm/lapic.c:331 kvm_recalculate_apic_map+0x609/0xa00 [kvm] CPU: 2 PID: 958 Comm: recalc_apic_map Not tainted 6.4.0-rc3-vanilla+ #35 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.16.2-1-1 04/01/2014 RIP: 0010:kvm_recalculate_apic_map+0x609/0xa00 [kvm] Call Trace: <TASK> kvm_apic_set_state+0x1cf/0x5b0 [kvm] kvm_arch_vcpu_ioctl+0x1806/0x2100 [kvm] kvm_vcpu_ioctl+0x663/0x8a0 [kvm] __x64_sys_ioctl+0xb8/0xf0 do_syscall_64+0x56/0x80 entry_SYSCALL_64_after_hwframe+0x46/0xb0 RIP: 0033:0x7fade8b9dd6f Unfortunately, the WARN can still trigger for other CPUs than the current one by racing against KVM_SET_LAPIC, so remove it completely. Reported-by: Michal Luczaj <[email protected]> Closes: https://lore.kernel.org/all/[email protected] Reported-by: Haoyu Wu <[email protected]> Closes: https://lore.kernel.org/all/[email protected] Reported-by: [email protected] Closes: https://lore.kernel.org/all/[email protected] Signed-off-by: Sean Christopherson <[email protected]> Message-ID: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> Stable-dep-of: 73b42dc ("KVM: x86: Re-split x2APIC ICR into ICR+ICR2 for AMD (x2AVIC)") Signed-off-by: Sasha Levin <[email protected]>
1 parent d9ac05e commit e99b21b

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

arch/x86/kvm/lapic.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,8 @@ static void kvm_recalculate_logical_map(struct kvm_apic_map *new,
351351
* reversing the LDR calculation to get cluster of APICs, i.e. no
352352
* additional work is required.
353353
*/
354-
if (apic_x2apic_mode(apic)) {
355-
WARN_ON_ONCE(ldr != kvm_apic_calc_x2apic_ldr(kvm_x2apic_id(apic)));
354+
if (apic_x2apic_mode(apic))
356355
return;
357-
}
358356

359357
if (WARN_ON_ONCE(!kvm_apic_map_get_logical_dest(new, ldr,
360358
&cluster, &mask))) {
@@ -2987,18 +2985,28 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
29872985
struct kvm_lapic_state *s, bool set)
29882986
{
29892987
if (apic_x2apic_mode(vcpu->arch.apic)) {
2988+
u32 x2apic_id = kvm_x2apic_id(vcpu->arch.apic);
29902989
u32 *id = (u32 *)(s->regs + APIC_ID);
29912990
u32 *ldr = (u32 *)(s->regs + APIC_LDR);
29922991
u64 icr;
29932992

29942993
if (vcpu->kvm->arch.x2apic_format) {
2995-
if (*id != vcpu->vcpu_id)
2994+
if (*id != x2apic_id)
29962995
return -EINVAL;
29972996
} else {
2997+
/*
2998+
* Ignore the userspace value when setting APIC state.
2999+
* KVM's model is that the x2APIC ID is readonly, e.g.
3000+
* KVM only supports delivering interrupts to KVM's
3001+
* version of the x2APIC ID. However, for backwards
3002+
* compatibility, don't reject attempts to set a
3003+
* mismatched ID for userspace that hasn't opted into
3004+
* x2apic_format.
3005+
*/
29983006
if (set)
2999-
*id >>= 24;
3007+
*id = x2apic_id;
30003008
else
3001-
*id <<= 24;
3009+
*id = x2apic_id << 24;
30023010
}
30033011

30043012
/*
@@ -3007,7 +3015,7 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
30073015
* split to ICR+ICR2 in userspace for backwards compatibility.
30083016
*/
30093017
if (set) {
3010-
*ldr = kvm_apic_calc_x2apic_ldr(*id);
3018+
*ldr = kvm_apic_calc_x2apic_ldr(x2apic_id);
30113019

30123020
icr = __kvm_lapic_get_reg(s->regs, APIC_ICR) |
30133021
(u64)__kvm_lapic_get_reg(s->regs, APIC_ICR2) << 32;

0 commit comments

Comments
 (0)