Re: [PATCH v6 6/9] KVM: x86: lapic: don't allow to change APIC ID unconditionally

Maxim Levitsky
2022-02-25T14:46:58Z

On Fri, 2022-02-25 at 16:22 +0800, Zeng Guang wrote:
> From: Maxim Levitsky <mlevitsk@redhat.com>
>
> No normal guest has any reason to change physical APIC IDs, and
> allowing this introduces bugs into APIC acceleration code.
>
> And Intel recent hardware just ignores writes to APIC_ID in
> xAPIC mode. More background can be found at:
> https://lore.kernel.org/lkml/Yfw5ddGNOnDqxMLs@google.com/
>
> Looks there is no much value to support writable xAPIC ID in
> guest except supporting some old and crazy use cases which
> probably would fail on real hardware. So, make xAPIC ID
> read-only for KVM guests.
>
> Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
> Signed-off-by: Zeng Guang <guang.zeng@intel.com>

Assuming that this is approved and accepted upstream,
that is even better that my proposal of doing this
when APICv is enabled.

Since now apic id is always read only, now we should not
forget to clean up some parts of kvm like kvm_recalculate_apic_map,
which are not needed anymore.

Best regards,
Maxim Levitsky

> ---
> arch/x86/kvm/lapic.c | 25 ++++++++++++++++++-------
> 1 file changed, 18 insertions(+), 7 deletions(-)
>
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index e4bcdab1fac0..b38288c8a94f 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -2044,10 +2044,17 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
>
> switch (reg) {
> case APIC_ID: /* Local APIC ID */
> - if (!apic_x2apic_mode(apic))
> - kvm_apic_set_xapic_id(apic, val >> 24);
> - else
> + if (apic_x2apic_mode(apic)) {
> ret = 1;
> + break;
> + }
> + /* Don't allow changing APIC ID to avoid unexpected issues */
> + if ((val >> 24) != apic->vcpu->vcpu_id) {
> + kvm_vm_bugged(apic->vcpu->kvm);
> + break;
> + }
> +
> + kvm_apic_set_xapic_id(apic, val >> 24);
> break;
>
> case APIC_TASKPRI:
> @@ -2631,11 +2638,15 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
> static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
> struct kvm_lapic_state *s, bool set)
> {
> - if (apic_x2apic_mode(vcpu->arch.apic)) {
> - u32 *id = (u32 *)(s->regs + APIC_ID);
> - u32 *ldr = (u32 *)(s->regs + APIC_LDR);
> - u64 icr;
> + u32 *id = (u32 *)(s->regs + APIC_ID);
> + u32 *ldr = (u32 *)(s->regs + APIC_LDR);
> + u64 icr;
>
> + if (!apic_x2apic_mode(vcpu->arch.apic)) {
> + /* Don't allow changing APIC ID to avoid unexpected issues */
> + if ((*id >> 24) != vcpu->vcpu_id)
> + return -EINVAL;
> + } else {
> if (vcpu->kvm->arch.x2apic_format) {
> if (*id != vcpu->vcpu_id)
> return -EINVAL;