KVM: x86: Convert vapic synchronization to _cached functions (CVE-2013-6368)
[pandora-kernel.git] / arch / x86 / kvm / lapic.c
index 54abb40..757c716 100644 (file)
@@ -537,7 +537,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
        ASSERT(apic != NULL);
 
        /* if initial count is 0, current count should also be 0 */
-       if (apic_get_reg(apic, APIC_TMICT) == 0)
+       if (apic_get_reg(apic, APIC_TMICT) == 0 ||
+               apic->lapic_timer.period == 0)
                return 0;
 
        remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
@@ -1277,14 +1278,12 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
 void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu)
 {
        u32 data;
-       void *vapic;
 
        if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr)
                return;
 
-       vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0);
-       data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr));
-       kunmap_atomic(vapic, KM_USER0);
+       kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
+                               sizeof(u32));
 
        apic_set_tpr(vcpu->arch.apic, data & 0xff);
 }
@@ -1294,7 +1293,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
        u32 data, tpr;
        int max_irr, max_isr;
        struct kvm_lapic *apic;
-       void *vapic;
 
        if (!irqchip_in_kernel(vcpu->kvm) || !vcpu->arch.apic->vapic_addr)
                return;
@@ -1309,17 +1307,22 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
                max_isr = 0;
        data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24);
 
-       vapic = kmap_atomic(vcpu->arch.apic->vapic_page, KM_USER0);
-       *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data;
-       kunmap_atomic(vapic, KM_USER0);
+       kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data,
+                               sizeof(u32));
 }
 
-void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
+int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr)
 {
        if (!irqchip_in_kernel(vcpu->kvm))
-               return;
+               return 0;
+
+       if (vapic_addr && kvm_gfn_to_hva_cache_init(vcpu->kvm,
+                                         &vcpu->arch.apic->vapic_cache,
+                                         vapic_addr, sizeof(u32)))
+               return -EINVAL;
 
        vcpu->arch.apic->vapic_addr = vapic_addr;
+       return 0;
 }
 
 int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data)