]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
kvm:vmx: more complete state update on APICv on/off
authorRoman Kagan <rkagan@virtuozzo.com>
Wed, 18 May 2016 14:48:20 +0000 (17:48 +0300)
committerChuck Anderson <chuck.anderson@oracle.com>
Sun, 30 Oct 2016 23:45:25 +0000 (16:45 -0700)
The function to update APICv on/off state (in particular, to deactivate
it when enabling Hyper-V SynIC) is incomplete: it doesn't adjust
APICv-related fields among secondary processor-based VM-execution
controls.  As a result, Windows 2012 guests get stuck when SynIC-based
auto-EOI interrupt intersected with e.g. an IPI in the guest.

In addition, the MSR intercept bitmap isn't updated every time "virtualize
x2APIC mode" is toggled.  This path can only be triggered by a malicious
guest, because Windows didn't use x2APIC but rather their own synthetic
APIC access MSRs; however a guest running in a SynIC-enabled VM could
switch to x2APIC and thus obtain direct access to host APIC MSRs
(CVE-2016-4440).

The patch fixes those omissions.

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Reported-by: Steve Rutherford <srutherford@google.com>
Reported-by: Yang Zhang <yang.zhang.wz@gmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Orabug: 23347009
CVE: CVE-2016-4440
Signed-off-by: Manjunath Govindashetty <manjunath.govindashetty@oracle.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/lapic.h
arch/x86/kvm/vmx.c

index 41b06fca39f70f11315e2ea9e546662e71b58336..9a8643ad8d7890cdf83f5eccb8e9499088fd9863 100644 (file)
@@ -364,6 +364,8 @@ struct kvm_vcpu_arch {
        u64 efer;
        u64 apic_base;
        struct kvm_lapic *apic;    /* kernel irqchip context */
+       bool apicv_active;
+       DECLARE_BITMAP(ioapic_handled_vectors, 256);
        unsigned long apic_attention;
        int32_t apic_arb_prio;
        int mp_state;
index c4ea87eedf8a71128b265efacf6f8fdc01b62dc2..b9a01ae8cfb0d495232db24229efc00407c3815d 100644 (file)
@@ -143,6 +143,11 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic)
        return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
 }
 
+static inline bool kvm_vcpu_apicv_active(struct kvm_vcpu *vcpu)
+{
+         return vcpu->arch.apic && vcpu->arch.apicv_active;
+}
+
 static inline bool kvm_apic_vid_enabled(struct kvm *kvm)
 {
        return kvm_x86_ops->vm_has_apicv(kvm);
index 2790ecbfa376abd7ffcae7a8a967f8e8af3d401d..57d10f7c80a234a57d16921eb60ec90de88b43ee 100644 (file)
@@ -19,6 +19,7 @@
 #include "irq.h"
 #include "mmu.h"
 #include "cpuid.h"
+#include "lapic.h"
 
 #include <linux/kvm_host.h>
 #include <linux/module.h>
@@ -2187,8 +2188,9 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
 
        if (is_guest_mode(vcpu))
                msr_bitmap = vmx_msr_bitmap_nested;
-       else if (irqchip_in_kernel(vcpu->kvm) &&
-               apic_x2apic_mode(vcpu->arch.apic)) {
+       else if (cpu_has_secondary_exec_ctrls() &&
+                (vmcs_read32(SECONDARY_VM_EXEC_CONTROL) &
+                 SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
                if (is_long_mode(vcpu))
                        msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
                else
@@ -4544,6 +4546,26 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
        return pin_based_exec_ctrl;
 }
 
+static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
+{
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+       vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
+       if (cpu_has_secondary_exec_ctrls()) {
+               if (kvm_vcpu_apicv_active(vcpu))
+                       vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
+                                     SECONDARY_EXEC_APIC_REGISTER_VIRT |
+                                     SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
+               else
+                       vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
+                                       SECONDARY_EXEC_APIC_REGISTER_VIRT |
+                                       SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
+       }
+
+       if (cpu_has_vmx_msr_bitmap())
+               vmx_set_msr_bitmap(vcpu);
+}
+
 static u32 vmx_exec_control(struct vcpu_vmx *vmx)
 {
        u32 exec_control = vmcs_config.cpu_based_exec_ctrl;
@@ -6163,23 +6185,20 @@ static __init int hardware_setup(void)
 
        set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
 
-       if (enable_apicv) {
-               for (msr = 0x800; msr <= 0x8ff; msr++)
-                       vmx_disable_intercept_msr_read_x2apic(msr);
-
-               /* According SDM, in x2apic mode, the whole id reg is used.
-                * But in KVM, it only use the highest eight bits. Need to
-                * intercept it */
-               vmx_enable_intercept_msr_read_x2apic(0x802);
-               /* TMCCT */
-               vmx_enable_intercept_msr_read_x2apic(0x839);
-               /* TPR */
-               vmx_disable_intercept_msr_write_x2apic(0x808);
-               /* EOI */
-               vmx_disable_intercept_msr_write_x2apic(0x80b);
-               /* SELF-IPI */
-               vmx_disable_intercept_msr_write_x2apic(0x83f);
-       }
+       for (msr = 0x800; msr <= 0x8ff; msr++)
+               vmx_disable_intercept_msr_read_x2apic(msr);
+
+       /* According SDM, in x2apic mode, the whole id reg is used.  But in
+        * KVM, it only use the highest eight bits. Need to intercept it */
+       vmx_enable_intercept_msr_read_x2apic(0x802);
+       /* TMCCT */
+       vmx_enable_intercept_msr_read_x2apic(0x839);
+       /* TPR */
+       vmx_disable_intercept_msr_write_x2apic(0x808);
+       /* EOI */
+       vmx_disable_intercept_msr_write_x2apic(0x80b);
+       /* SELF-IPI */
+       vmx_disable_intercept_msr_write_x2apic(0x83f);
 
        if (enable_ept) {
                kvm_mmu_set_mask_ptes(0ull,