2022-10-01 01:15:34

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH v4 06/32] KVM: x86: Track xAPIC ID only on userspace SET, _after_ vAPIC is updated

Track potential changes to a vCPU's xAPIC ID only for KVM_SET_LAPIC, i.e.
not for KVM_GET_LAPIC, and process the update after the incoming state
provided by userspace is copied to KVM's in-kernel vAPIC. The latter bug
is the most problematic issue, as processing the update before KVM's
vAPIC is actually updated can result in false positives, e.g. due to the
APIC holding an x2APIC ID (wrong format), and false negatives, e.g. due
to KVM failing to detect an xAPIC ID "mismatch".

Processing an "update" in KVM_GET_LAPIC is likely a benign bug now that
the update helper ignores mismatches, but prior to that fix, invoking
KVM_GET_LAPIC while the APIC is disabled could effectively cause KVM to
consume stale state, e.g. if the APIC were in x2APIC mode before being
hardware disabled.

Fixes: 3743c2f02517 ("KVM: x86: inhibit APICv/AVIC on changes to APIC ID or APIC base")
Reported-by: Alejandro Jimenez <[email protected]>
Cc: [email protected]
Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/lapic.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 67260f7ce43a..251856ba0750 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2720,8 +2720,6 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
icr = __kvm_lapic_get_reg64(s->regs, APIC_ICR);
__kvm_lapic_set_reg(s->regs, APIC_ICR2, icr >> 32);
}
- } else {
- kvm_lapic_xapic_id_updated(vcpu->arch.apic);
}

return 0;
@@ -2757,6 +2755,9 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
}
memcpy(vcpu->arch.apic->regs, s->regs, sizeof(*s));

+ if (!apic_x2apic_mode(vcpu->arch.apic))
+ kvm_lapic_xapic_id_updated(vcpu->arch.apic);
+
atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
kvm_recalculate_apic_map(vcpu->kvm);
kvm_apic_set_version(vcpu);
--
2.38.0.rc1.362.ged0d419d3c-goog


2022-12-08 22:39:17

by Maxim Levitsky

[permalink] [raw]
Subject: Re: [PATCH v4 06/32] KVM: x86: Track xAPIC ID only on userspace SET, _after_ vAPIC is updated

On Sat, 2022-10-01 at 00:58 +0000, Sean Christopherson wrote:
> Track potential changes to a vCPU's xAPIC ID only for KVM_SET_LAPIC, i.e.
> not for KVM_GET_LAPIC, and process the update after the incoming state
> provided by userspace is copied to KVM's in-kernel vAPIC. The latter bug
> is the most problematic issue, as processing the update before KVM's
> vAPIC is actually updated can result in false positives, e.g. due to the
> APIC holding an x2APIC ID (wrong format), and false negatives, e.g. due
> to KVM failing to detect an xAPIC ID "mismatch".
>
> Processing an "update" in KVM_GET_LAPIC is likely a benign bug now that
> the update helper ignores mismatches, but prior to that fix, invoking
> KVM_GET_LAPIC while the APIC is disabled could effectively cause KVM to
> consume stale state, e.g. if the APIC were in x2APIC mode before being
> hardware disabled.
>
> Fixes: 3743c2f02517 ("KVM: x86: inhibit APICv/AVIC on changes to APIC ID or APIC base")
> Reported-by: Alejandro Jimenez <[email protected]>
> Cc: [email protected]
> Signed-off-by: Sean Christopherson <[email protected]>
> ---
> arch/x86/kvm/lapic.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
> index 67260f7ce43a..251856ba0750 100644
> --- a/arch/x86/kvm/lapic.c
> +++ b/arch/x86/kvm/lapic.c
> @@ -2720,8 +2720,6 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu,
> icr = __kvm_lapic_get_reg64(s->regs, APIC_ICR);
> __kvm_lapic_set_reg(s->regs, APIC_ICR2, icr >> 32);
> }
> - } else {
> - kvm_lapic_xapic_id_updated(vcpu->arch.apic);
> }
>
> return 0;
> @@ -2757,6 +2755,9 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s)
> }
> memcpy(vcpu->arch.apic->regs, s->regs, sizeof(*s));
>
> + if (!apic_x2apic_mode(vcpu->arch.apic))
> + kvm_lapic_xapic_id_updated(vcpu->arch.apic);
> +
> atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
> kvm_recalculate_apic_map(vcpu->kvm);
> kvm_apic_set_version(vcpu);


Reviewed-by: Maxim Levitsky <[email protected]>

Best regards,
Maxim Levitsky