diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-12 18:46:06 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-12 18:46:06 -0500 |
commit | 54fb723cc48db2fde964fb9bb0eaaccf2cf31a9f (patch) | |
tree | 71a21d846cd6fe301f1077c98cdf6dfff58048d2 /arch | |
parent | ea1e61cbb9b1397192a478eca4c3138bd1b4441c (diff) | |
parent | 17d68b763f09a9ce824ae23eb62c9efc57b69271 (diff) |
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini:
"Four security fixes for KVM on x86. Thanks to Andrew Honig and Lars
Bull from Google for reporting them"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
KVM: x86: fix guest-initiated crash with x2apic (CVE-2013-6376)
KVM: x86: Convert vapic synchronization to _cached functions (CVE-2013-6368)
KVM: x86: Fix potential divide by 0 in lapic (CVE-2013-6367)
KVM: Improve create VCPU parameter (CVE-2013-4587)
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/lapic.c | 35 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 4 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 40 |
3 files changed, 24 insertions, 55 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 5439117d5c4c..dec48bfaddb8 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -143,6 +143,8 @@ static inline int kvm_apic_id(struct kvm_lapic *apic) | |||
143 | return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; | 143 | return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; |
144 | } | 144 | } |
145 | 145 | ||
146 | #define KVM_X2APIC_CID_BITS 0 | ||
147 | |||
146 | static void recalculate_apic_map(struct kvm *kvm) | 148 | static void recalculate_apic_map(struct kvm *kvm) |
147 | { | 149 | { |
148 | struct kvm_apic_map *new, *old = NULL; | 150 | struct kvm_apic_map *new, *old = NULL; |
@@ -180,7 +182,8 @@ static void recalculate_apic_map(struct kvm *kvm) | |||
180 | if (apic_x2apic_mode(apic)) { | 182 | if (apic_x2apic_mode(apic)) { |
181 | new->ldr_bits = 32; | 183 | new->ldr_bits = 32; |
182 | new->cid_shift = 16; | 184 | new->cid_shift = 16; |
183 | new->cid_mask = new->lid_mask = 0xffff; | 185 | new->cid_mask = (1 << KVM_X2APIC_CID_BITS) - 1; |
186 | new->lid_mask = 0xffff; | ||
184 | } else if (kvm_apic_sw_enabled(apic) && | 187 | } else if (kvm_apic_sw_enabled(apic) && |
185 | !new->cid_mask /* flat mode */ && | 188 | !new->cid_mask /* flat mode */ && |
186 | kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) { | 189 | kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) { |
@@ -841,7 +844,8 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) | |||
841 | ASSERT(apic != NULL); | 844 | ASSERT(apic != NULL); |
842 | 845 | ||
843 | /* if initial count is 0, current count should also be 0 */ | 846 | /* if initial count is 0, current count should also be 0 */ |
844 | if (kvm_apic_get_reg(apic, APIC_TMICT) == 0) | 847 | if (kvm_apic_get_reg(apic, APIC_TMICT) == 0 || |
848 | apic->lapic_timer.period == 0) | ||
845 | return 0; | 849 | return 0; |
846 | 850 | ||
847 | remaining = hrtimer_get_remaining(&apic->lapic_timer.timer); | 851 | remaining = hrtimer_get_remaining(&apic->lapic_timer.timer); |
@@ -1691,7 +1695,6 @@ static void apic_sync_pv_eoi_from_guest(struct kvm_vcpu *vcpu, | |||
1691 | void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) | 1695 | void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) |
1692 | { | 1696 | { |
1693 | u32 data; | 1697 | u32 data; |
1694 | void *vapic; | ||
1695 | 1698 | ||
1696 | if (test_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention)) | 1699 | if (test_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention)) |
1697 | apic_sync_pv_eoi_from_guest(vcpu, vcpu->arch.apic); | 1700 | apic_sync_pv_eoi_from_guest(vcpu, vcpu->arch.apic); |
@@ -1699,9 +1702,8 @@ void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) | |||
1699 | if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention)) | 1702 | if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention)) |
1700 | return; | 1703 | return; |
1701 | 1704 | ||
1702 | vapic = kmap_atomic(vcpu->arch.apic->vapic_page); | 1705 | kvm_read_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data, |
1703 | data = *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)); | 1706 | sizeof(u32)); |
1704 | kunmap_atomic(vapic); | ||
1705 | 1707 | ||
1706 | apic_set_tpr(vcpu->arch.apic, data & 0xff); | 1708 | apic_set_tpr(vcpu->arch.apic, data & 0xff); |
1707 | } | 1709 | } |
@@ -1737,7 +1739,6 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) | |||
1737 | u32 data, tpr; | 1739 | u32 data, tpr; |
1738 | int max_irr, max_isr; | 1740 | int max_irr, max_isr; |
1739 | struct kvm_lapic *apic = vcpu->arch.apic; | 1741 | struct kvm_lapic *apic = vcpu->arch.apic; |
1740 | void *vapic; | ||
1741 | 1742 | ||
1742 | apic_sync_pv_eoi_to_guest(vcpu, apic); | 1743 | apic_sync_pv_eoi_to_guest(vcpu, apic); |
1743 | 1744 | ||
@@ -1753,18 +1754,24 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu) | |||
1753 | max_isr = 0; | 1754 | max_isr = 0; |
1754 | data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24); | 1755 | data = (tpr & 0xff) | ((max_isr & 0xf0) << 8) | (max_irr << 24); |
1755 | 1756 | ||
1756 | vapic = kmap_atomic(vcpu->arch.apic->vapic_page); | 1757 | kvm_write_guest_cached(vcpu->kvm, &vcpu->arch.apic->vapic_cache, &data, |
1757 | *(u32 *)(vapic + offset_in_page(vcpu->arch.apic->vapic_addr)) = data; | 1758 | sizeof(u32)); |
1758 | kunmap_atomic(vapic); | ||
1759 | } | 1759 | } |
1760 | 1760 | ||
1761 | void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr) | 1761 | int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr) |
1762 | { | 1762 | { |
1763 | vcpu->arch.apic->vapic_addr = vapic_addr; | 1763 | if (vapic_addr) { |
1764 | if (vapic_addr) | 1764 | if (kvm_gfn_to_hva_cache_init(vcpu->kvm, |
1765 | &vcpu->arch.apic->vapic_cache, | ||
1766 | vapic_addr, sizeof(u32))) | ||
1767 | return -EINVAL; | ||
1765 | __set_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention); | 1768 | __set_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention); |
1766 | else | 1769 | } else { |
1767 | __clear_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention); | 1770 | __clear_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention); |
1771 | } | ||
1772 | |||
1773 | vcpu->arch.apic->vapic_addr = vapic_addr; | ||
1774 | return 0; | ||
1768 | } | 1775 | } |
1769 | 1776 | ||
1770 | int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data) | 1777 | int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data) |
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index c730ac9fe801..c8b0d0d2da5c 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -34,7 +34,7 @@ struct kvm_lapic { | |||
34 | */ | 34 | */ |
35 | void *regs; | 35 | void *regs; |
36 | gpa_t vapic_addr; | 36 | gpa_t vapic_addr; |
37 | struct page *vapic_page; | 37 | struct gfn_to_hva_cache vapic_cache; |
38 | unsigned long pending_events; | 38 | unsigned long pending_events; |
39 | unsigned int sipi_vector; | 39 | unsigned int sipi_vector; |
40 | }; | 40 | }; |
@@ -76,7 +76,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data); | |||
76 | void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset); | 76 | void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset); |
77 | void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector); | 77 | void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector); |
78 | 78 | ||
79 | void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); | 79 | int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); |
80 | void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); | 80 | void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); |
81 | void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu); | 81 | void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu); |
82 | 82 | ||
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 21ef1ba184ae..5d004da1e35d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -3214,8 +3214,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
3214 | r = -EFAULT; | 3214 | r = -EFAULT; |
3215 | if (copy_from_user(&va, argp, sizeof va)) | 3215 | if (copy_from_user(&va, argp, sizeof va)) |
3216 | goto out; | 3216 | goto out; |
3217 | r = 0; | 3217 | r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr); |
3218 | kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr); | ||
3219 | break; | 3218 | break; |
3220 | } | 3219 | } |
3221 | case KVM_X86_SETUP_MCE: { | 3220 | case KVM_X86_SETUP_MCE: { |
@@ -5739,36 +5738,6 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) | |||
5739 | !kvm_event_needs_reinjection(vcpu); | 5738 | !kvm_event_needs_reinjection(vcpu); |
5740 | } | 5739 | } |
5741 | 5740 | ||
5742 | static int vapic_enter(struct kvm_vcpu *vcpu) | ||
5743 | { | ||
5744 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
5745 | struct page *page; | ||
5746 | |||
5747 | if (!apic || !apic->vapic_addr) | ||
5748 | return 0; | ||
5749 | |||
5750 | page = gfn_to_page(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); | ||
5751 | if (is_error_page(page)) | ||
5752 | return -EFAULT; | ||
5753 | |||
5754 | vcpu->arch.apic->vapic_page = page; | ||
5755 | return 0; | ||
5756 | } | ||
5757 | |||
5758 | static void vapic_exit(struct kvm_vcpu *vcpu) | ||
5759 | { | ||
5760 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
5761 | int idx; | ||
5762 | |||
5763 | if (!apic || !apic->vapic_addr) | ||
5764 | return; | ||
5765 | |||
5766 | idx = srcu_read_lock(&vcpu->kvm->srcu); | ||
5767 | kvm_release_page_dirty(apic->vapic_page); | ||
5768 | mark_page_dirty(vcpu->kvm, apic->vapic_addr >> PAGE_SHIFT); | ||
5769 | srcu_read_unlock(&vcpu->kvm->srcu, idx); | ||
5770 | } | ||
5771 | |||
5772 | static void update_cr8_intercept(struct kvm_vcpu *vcpu) | 5741 | static void update_cr8_intercept(struct kvm_vcpu *vcpu) |
5773 | { | 5742 | { |
5774 | int max_irr, tpr; | 5743 | int max_irr, tpr; |
@@ -6069,11 +6038,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) | |||
6069 | struct kvm *kvm = vcpu->kvm; | 6038 | struct kvm *kvm = vcpu->kvm; |
6070 | 6039 | ||
6071 | vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); | 6040 | vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); |
6072 | r = vapic_enter(vcpu); | ||
6073 | if (r) { | ||
6074 | srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx); | ||
6075 | return r; | ||
6076 | } | ||
6077 | 6041 | ||
6078 | r = 1; | 6042 | r = 1; |
6079 | while (r > 0) { | 6043 | while (r > 0) { |
@@ -6132,8 +6096,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) | |||
6132 | 6096 | ||
6133 | srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx); | 6097 | srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx); |
6134 | 6098 | ||
6135 | vapic_exit(vcpu); | ||
6136 | |||
6137 | return r; | 6099 | return r; |
6138 | } | 6100 | } |
6139 | 6101 | ||