diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-01-13 20:06:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-01-13 20:06:24 -0500 |
commit | 406732c932d47715395345ba036a3d58341cad55 (patch) | |
tree | ea4060958d1a6d18417d6088a523d47f72656ffb | |
parent | a65c92597dc7556eaa219a70336d66c058a9627c (diff) | |
parent | 33ab91103b3415e12457e3104f0e4517ce12d0f3 (diff) |
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull KVM fixes from Paolo Bonzini:
- fix for module unload vs deferred jump labels (note: there might be
other buggy modules!)
- two NULL pointer dereferences from syzkaller
- also syzkaller: fix emulation of fxsave/fxrstor/sgdt/sidt, problem
made worse during this merge window, "just" kernel memory leak on
releases
- fix emulation of "mov ss" - somewhat serious on AMD, less so on Intel
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
KVM: x86: fix emulation of "MOV SS, null selector"
KVM: x86: fix NULL deref in vcpu_scan_ioapic
KVM: eventfd: fix NULL deref irqbypass consumer
KVM: x86: Introduce segmented_write_std
KVM: x86: flush pending lapic jump label updates on module unload
jump_labels: API for flushing deferred jump label updates
-rw-r--r-- | arch/x86/kvm/emulate.c | 70 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 3 | ||||
-rw-r--r-- | include/linux/jump_label_ratelimit.h | 5 | ||||
-rw-r--r-- | kernel/jump_label.c | 7 | ||||
-rw-r--r-- | virt/lib/irqbypass.c | 4 |
7 files changed, 80 insertions, 16 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 56628a44668b..cedbba0f3402 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -818,6 +818,20 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, | |||
818 | return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); | 818 | return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); |
819 | } | 819 | } |
820 | 820 | ||
821 | static int segmented_write_std(struct x86_emulate_ctxt *ctxt, | ||
822 | struct segmented_address addr, | ||
823 | void *data, | ||
824 | unsigned int size) | ||
825 | { | ||
826 | int rc; | ||
827 | ulong linear; | ||
828 | |||
829 | rc = linearize(ctxt, addr, size, true, &linear); | ||
830 | if (rc != X86EMUL_CONTINUE) | ||
831 | return rc; | ||
832 | return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); | ||
833 | } | ||
834 | |||
821 | /* | 835 | /* |
822 | * Prefetch the remaining bytes of the instruction without crossing page | 836 | * Prefetch the remaining bytes of the instruction without crossing page |
823 | * boundary if they are not in fetch_cache yet. | 837 | * boundary if they are not in fetch_cache yet. |
@@ -1571,7 +1585,6 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
1571 | &ctxt->exception); | 1585 | &ctxt->exception); |
1572 | } | 1586 | } |
1573 | 1587 | ||
1574 | /* Does not support long mode */ | ||
1575 | static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, | 1588 | static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, |
1576 | u16 selector, int seg, u8 cpl, | 1589 | u16 selector, int seg, u8 cpl, |
1577 | enum x86_transfer_type transfer, | 1590 | enum x86_transfer_type transfer, |
@@ -1608,20 +1621,34 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
1608 | 1621 | ||
1609 | rpl = selector & 3; | 1622 | rpl = selector & 3; |
1610 | 1623 | ||
1611 | /* NULL selector is not valid for TR, CS and SS (except for long mode) */ | ||
1612 | if ((seg == VCPU_SREG_CS | ||
1613 | || (seg == VCPU_SREG_SS | ||
1614 | && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)) | ||
1615 | || seg == VCPU_SREG_TR) | ||
1616 | && null_selector) | ||
1617 | goto exception; | ||
1618 | |||
1619 | /* TR should be in GDT only */ | 1624 | /* TR should be in GDT only */ |
1620 | if (seg == VCPU_SREG_TR && (selector & (1 << 2))) | 1625 | if (seg == VCPU_SREG_TR && (selector & (1 << 2))) |
1621 | goto exception; | 1626 | goto exception; |
1622 | 1627 | ||
1623 | if (null_selector) /* for NULL selector skip all following checks */ | 1628 | /* NULL selector is not valid for TR, CS and (except for long mode) SS */ |
1629 | if (null_selector) { | ||
1630 | if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR) | ||
1631 | goto exception; | ||
1632 | |||
1633 | if (seg == VCPU_SREG_SS) { | ||
1634 | if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl) | ||
1635 | goto exception; | ||
1636 | |||
1637 | /* | ||
1638 | * ctxt->ops->set_segment expects the CPL to be in | ||
1639 | * SS.DPL, so fake an expand-up 32-bit data segment. | ||
1640 | */ | ||
1641 | seg_desc.type = 3; | ||
1642 | seg_desc.p = 1; | ||
1643 | seg_desc.s = 1; | ||
1644 | seg_desc.dpl = cpl; | ||
1645 | seg_desc.d = 1; | ||
1646 | seg_desc.g = 1; | ||
1647 | } | ||
1648 | |||
1649 | /* Skip all following checks */ | ||
1624 | goto load; | 1650 | goto load; |
1651 | } | ||
1625 | 1652 | ||
1626 | ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr); | 1653 | ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr); |
1627 | if (ret != X86EMUL_CONTINUE) | 1654 | if (ret != X86EMUL_CONTINUE) |
@@ -1737,6 +1764,21 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
1737 | u16 selector, int seg) | 1764 | u16 selector, int seg) |
1738 | { | 1765 | { |
1739 | u8 cpl = ctxt->ops->cpl(ctxt); | 1766 | u8 cpl = ctxt->ops->cpl(ctxt); |
1767 | |||
1768 | /* | ||
1769 | * None of MOV, POP and LSS can load a NULL selector in CPL=3, but | ||
1770 | * they can load it at CPL<3 (Intel's manual says only LSS can, | ||
1771 | * but it's wrong). | ||
1772 | * | ||
1773 | * However, the Intel manual says that putting IST=1/DPL=3 in | ||
1774 | * an interrupt gate will result in SS=3 (the AMD manual instead | ||
1775 | * says it doesn't), so allow SS=3 in __load_segment_descriptor | ||
1776 | * and only forbid it here. | ||
1777 | */ | ||
1778 | if (seg == VCPU_SREG_SS && selector == 3 && | ||
1779 | ctxt->mode == X86EMUL_MODE_PROT64) | ||
1780 | return emulate_exception(ctxt, GP_VECTOR, 0, true); | ||
1781 | |||
1740 | return __load_segment_descriptor(ctxt, selector, seg, cpl, | 1782 | return __load_segment_descriptor(ctxt, selector, seg, cpl, |
1741 | X86_TRANSFER_NONE, NULL); | 1783 | X86_TRANSFER_NONE, NULL); |
1742 | } | 1784 | } |
@@ -3685,8 +3727,8 @@ static int emulate_store_desc_ptr(struct x86_emulate_ctxt *ctxt, | |||
3685 | } | 3727 | } |
3686 | /* Disable writeback. */ | 3728 | /* Disable writeback. */ |
3687 | ctxt->dst.type = OP_NONE; | 3729 | ctxt->dst.type = OP_NONE; |
3688 | return segmented_write(ctxt, ctxt->dst.addr.mem, | 3730 | return segmented_write_std(ctxt, ctxt->dst.addr.mem, |
3689 | &desc_ptr, 2 + ctxt->op_bytes); | 3731 | &desc_ptr, 2 + ctxt->op_bytes); |
3690 | } | 3732 | } |
3691 | 3733 | ||
3692 | static int em_sgdt(struct x86_emulate_ctxt *ctxt) | 3734 | static int em_sgdt(struct x86_emulate_ctxt *ctxt) |
@@ -3932,7 +3974,7 @@ static int em_fxsave(struct x86_emulate_ctxt *ctxt) | |||
3932 | else | 3974 | else |
3933 | size = offsetof(struct fxregs_state, xmm_space[0]); | 3975 | size = offsetof(struct fxregs_state, xmm_space[0]); |
3934 | 3976 | ||
3935 | return segmented_write(ctxt, ctxt->memop.addr.mem, &fx_state, size); | 3977 | return segmented_write_std(ctxt, ctxt->memop.addr.mem, &fx_state, size); |
3936 | } | 3978 | } |
3937 | 3979 | ||
3938 | static int fxrstor_fixup(struct x86_emulate_ctxt *ctxt, | 3980 | static int fxrstor_fixup(struct x86_emulate_ctxt *ctxt, |
@@ -3974,7 +4016,7 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt) | |||
3974 | if (rc != X86EMUL_CONTINUE) | 4016 | if (rc != X86EMUL_CONTINUE) |
3975 | return rc; | 4017 | return rc; |
3976 | 4018 | ||
3977 | rc = segmented_read(ctxt, ctxt->memop.addr.mem, &fx_state, 512); | 4019 | rc = segmented_read_std(ctxt, ctxt->memop.addr.mem, &fx_state, 512); |
3978 | if (rc != X86EMUL_CONTINUE) | 4020 | if (rc != X86EMUL_CONTINUE) |
3979 | return rc; | 4021 | return rc; |
3980 | 4022 | ||
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 5fe290c1b7d8..2f6ef5121a4c 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -2426,3 +2426,9 @@ void kvm_lapic_init(void) | |||
2426 | jump_label_rate_limit(&apic_hw_disabled, HZ); | 2426 | jump_label_rate_limit(&apic_hw_disabled, HZ); |
2427 | jump_label_rate_limit(&apic_sw_disabled, HZ); | 2427 | jump_label_rate_limit(&apic_sw_disabled, HZ); |
2428 | } | 2428 | } |
2429 | |||
2430 | void kvm_lapic_exit(void) | ||
2431 | { | ||
2432 | static_key_deferred_flush(&apic_hw_disabled); | ||
2433 | static_key_deferred_flush(&apic_sw_disabled); | ||
2434 | } | ||
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index e0c80233b3e1..ff8039d61672 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -110,6 +110,7 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu) | |||
110 | 110 | ||
111 | int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); | 111 | int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); |
112 | void kvm_lapic_init(void); | 112 | void kvm_lapic_init(void); |
113 | void kvm_lapic_exit(void); | ||
113 | 114 | ||
114 | #define VEC_POS(v) ((v) & (32 - 1)) | 115 | #define VEC_POS(v) ((v) & (32 - 1)) |
115 | #define REG_POS(v) (((v) >> 5) << 4) | 116 | #define REG_POS(v) (((v) >> 5) << 4) |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2f22810a7e0c..57d8a856cdc5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -3342,6 +3342,8 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, | |||
3342 | 3342 | ||
3343 | switch (cap->cap) { | 3343 | switch (cap->cap) { |
3344 | case KVM_CAP_HYPERV_SYNIC: | 3344 | case KVM_CAP_HYPERV_SYNIC: |
3345 | if (!irqchip_in_kernel(vcpu->kvm)) | ||
3346 | return -EINVAL; | ||
3345 | return kvm_hv_activate_synic(vcpu); | 3347 | return kvm_hv_activate_synic(vcpu); |
3346 | default: | 3348 | default: |
3347 | return -EINVAL; | 3349 | return -EINVAL; |
@@ -6045,6 +6047,7 @@ out: | |||
6045 | 6047 | ||
6046 | void kvm_arch_exit(void) | 6048 | void kvm_arch_exit(void) |
6047 | { | 6049 | { |
6050 | kvm_lapic_exit(); | ||
6048 | perf_unregister_guest_info_callbacks(&kvm_guest_cbs); | 6051 | perf_unregister_guest_info_callbacks(&kvm_guest_cbs); |
6049 | 6052 | ||
6050 | if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) | 6053 | if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) |
diff --git a/include/linux/jump_label_ratelimit.h b/include/linux/jump_label_ratelimit.h index 089f70f83e97..23da3af459fe 100644 --- a/include/linux/jump_label_ratelimit.h +++ b/include/linux/jump_label_ratelimit.h | |||
@@ -14,6 +14,7 @@ struct static_key_deferred { | |||
14 | 14 | ||
15 | #ifdef HAVE_JUMP_LABEL | 15 | #ifdef HAVE_JUMP_LABEL |
16 | extern void static_key_slow_dec_deferred(struct static_key_deferred *key); | 16 | extern void static_key_slow_dec_deferred(struct static_key_deferred *key); |
17 | extern void static_key_deferred_flush(struct static_key_deferred *key); | ||
17 | extern void | 18 | extern void |
18 | jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl); | 19 | jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl); |
19 | 20 | ||
@@ -26,6 +27,10 @@ static inline void static_key_slow_dec_deferred(struct static_key_deferred *key) | |||
26 | STATIC_KEY_CHECK_USE(); | 27 | STATIC_KEY_CHECK_USE(); |
27 | static_key_slow_dec(&key->key); | 28 | static_key_slow_dec(&key->key); |
28 | } | 29 | } |
30 | static inline void static_key_deferred_flush(struct static_key_deferred *key) | ||
31 | { | ||
32 | STATIC_KEY_CHECK_USE(); | ||
33 | } | ||
29 | static inline void | 34 | static inline void |
30 | jump_label_rate_limit(struct static_key_deferred *key, | 35 | jump_label_rate_limit(struct static_key_deferred *key, |
31 | unsigned long rl) | 36 | unsigned long rl) |
diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 93ad6c1fb9b6..a9b8cf500591 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c | |||
@@ -182,6 +182,13 @@ void static_key_slow_dec_deferred(struct static_key_deferred *key) | |||
182 | } | 182 | } |
183 | EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred); | 183 | EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred); |
184 | 184 | ||
185 | void static_key_deferred_flush(struct static_key_deferred *key) | ||
186 | { | ||
187 | STATIC_KEY_CHECK_USE(); | ||
188 | flush_delayed_work(&key->work); | ||
189 | } | ||
190 | EXPORT_SYMBOL_GPL(static_key_deferred_flush); | ||
191 | |||
185 | void jump_label_rate_limit(struct static_key_deferred *key, | 192 | void jump_label_rate_limit(struct static_key_deferred *key, |
186 | unsigned long rl) | 193 | unsigned long rl) |
187 | { | 194 | { |
diff --git a/virt/lib/irqbypass.c b/virt/lib/irqbypass.c index 52abac4bb6a2..6d2fcd6fcb25 100644 --- a/virt/lib/irqbypass.c +++ b/virt/lib/irqbypass.c | |||
@@ -195,7 +195,7 @@ int irq_bypass_register_consumer(struct irq_bypass_consumer *consumer) | |||
195 | mutex_lock(&lock); | 195 | mutex_lock(&lock); |
196 | 196 | ||
197 | list_for_each_entry(tmp, &consumers, node) { | 197 | list_for_each_entry(tmp, &consumers, node) { |
198 | if (tmp->token == consumer->token) { | 198 | if (tmp->token == consumer->token || tmp == consumer) { |
199 | mutex_unlock(&lock); | 199 | mutex_unlock(&lock); |
200 | module_put(THIS_MODULE); | 200 | module_put(THIS_MODULE); |
201 | return -EBUSY; | 201 | return -EBUSY; |
@@ -245,7 +245,7 @@ void irq_bypass_unregister_consumer(struct irq_bypass_consumer *consumer) | |||
245 | mutex_lock(&lock); | 245 | mutex_lock(&lock); |
246 | 246 | ||
247 | list_for_each_entry(tmp, &consumers, node) { | 247 | list_for_each_entry(tmp, &consumers, node) { |
248 | if (tmp->token != consumer->token) | 248 | if (tmp != consumer) |
249 | continue; | 249 | continue; |
250 | 250 | ||
251 | list_for_each_entry(producer, &producers, node) { | 251 | list_for_each_entry(producer, &producers, node) { |