Commit 96971e9a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull kvm fixes from Paolo Bonzini:
 "This is a pretty large update.  I think it is roughly as big as what I
  usually had for the _whole_ rc period.

  There are a few bad bugs where the guest can OOPS or crash the host.
  We have also started looking at attack models for nested
  virtualization; bugs that usually result in the guest ring 0 crashing
  itself become more worrisome if you have nested virtualization,
  because the nested guest might bring down the non-nested guest as
  well.  For current uses of nested virtualization these do not really
  have a security impact, but you never know and bugs are bugs
  nevertheless.

  A lot of these bugs are in 3.17 too, resulting in a large number of
  stable@ Ccs.  I checked that all the patches apply there with no
  conflicts"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  kvm: vfio: fix unregister kvm_device_ops of vfio
  KVM: x86: Wrong assertion on paging_tmpl.h
  kvm: fix excessive pages un-pinning in kvm_iommu_map error path.
  KVM: x86: PREFETCH and HINT_NOP should have SrcMem flag
  KVM: x86: Emulator does not decode clflush well
  KVM: emulate: avoid accessing NULL ctxt->memopp
  KVM: x86: Decoding guest instructions which cross page boundary may fail
  kvm: x86: don't kill guest on unknown exit reason
  kvm: vmx: handle invvpid vm exit gracefully
  KVM: x86: Handle errors when RIP is set during far jumps
  KVM: x86: Emulator fixes for eip canonical checks on near branches
  KVM: x86: Fix wrong masking on relative jump/call
  KVM: x86: Improve thread safety in pit
  KVM: x86: Prevent host from panicking on shared MSR writes.
  KVM: x86: Check non-canonical addresses upon WRMSR
parents 20ca57cd 571ee1b6
...@@ -989,6 +989,20 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code) ...@@ -989,6 +989,20 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code)
kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
} }
static inline u64 get_canonical(u64 la)
{
return ((int64_t)la << 16) >> 16;
}
static inline bool is_noncanonical_address(u64 la)
{
#ifdef CONFIG_X86_64
return get_canonical(la) != la;
#else
return false;
#endif
}
#define TSS_IOPB_BASE_OFFSET 0x66 #define TSS_IOPB_BASE_OFFSET 0x66
#define TSS_BASE_SIZE 0x68 #define TSS_BASE_SIZE 0x68
#define TSS_IOPB_SIZE (65536 / 8) #define TSS_IOPB_SIZE (65536 / 8)
...@@ -1050,7 +1064,7 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm, ...@@ -1050,7 +1064,7 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
unsigned long address); unsigned long address);
void kvm_define_shared_msr(unsigned index, u32 msr); void kvm_define_shared_msr(unsigned index, u32 msr);
void kvm_set_shared_msr(unsigned index, u64 val, u64 mask); int kvm_set_shared_msr(unsigned index, u64 val, u64 mask);
bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip); bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip);
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#define EXIT_REASON_EPT_MISCONFIG 49 #define EXIT_REASON_EPT_MISCONFIG 49
#define EXIT_REASON_INVEPT 50 #define EXIT_REASON_INVEPT 50
#define EXIT_REASON_PREEMPTION_TIMER 52 #define EXIT_REASON_PREEMPTION_TIMER 52
#define EXIT_REASON_INVVPID 53
#define EXIT_REASON_WBINVD 54 #define EXIT_REASON_WBINVD 54
#define EXIT_REASON_XSETBV 55 #define EXIT_REASON_XSETBV 55
#define EXIT_REASON_APIC_WRITE 56 #define EXIT_REASON_APIC_WRITE 56
...@@ -114,6 +115,7 @@ ...@@ -114,6 +115,7 @@
{ EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \ { EXIT_REASON_EOI_INDUCED, "EOI_INDUCED" }, \
{ EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \ { EXIT_REASON_INVALID_STATE, "INVALID_STATE" }, \
{ EXIT_REASON_INVD, "INVD" }, \ { EXIT_REASON_INVD, "INVD" }, \
{ EXIT_REASON_INVVPID, "INVVPID" }, \
{ EXIT_REASON_INVPCID, "INVPCID" } { EXIT_REASON_INVPCID, "INVPCID" }
#endif /* _UAPIVMX_H */ #endif /* _UAPIVMX_H */
This diff is collapsed.
...@@ -262,8 +262,10 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) ...@@ -262,8 +262,10 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
return; return;
timer = &pit->pit_state.timer; timer = &pit->pit_state.timer;
mutex_lock(&pit->pit_state.lock);
if (hrtimer_cancel(timer)) if (hrtimer_cancel(timer))
hrtimer_start_expires(timer, HRTIMER_MODE_ABS); hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
mutex_unlock(&pit->pit_state.lock);
} }
static void destroy_pit_timer(struct kvm_pit *pit) static void destroy_pit_timer(struct kvm_pit *pit)
......
...@@ -298,7 +298,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, ...@@ -298,7 +298,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
} }
#endif #endif
walker->max_level = walker->level; walker->max_level = walker->level;
ASSERT(!is_long_mode(vcpu) && is_pae(vcpu)); ASSERT(!(is_long_mode(vcpu) && !is_pae(vcpu)));
accessed_dirty = PT_GUEST_ACCESSED_MASK; accessed_dirty = PT_GUEST_ACCESSED_MASK;
pt_access = pte_access = ACC_ALL; pt_access = pte_access = ACC_ALL;
......
...@@ -3251,7 +3251,7 @@ static int wrmsr_interception(struct vcpu_svm *svm) ...@@ -3251,7 +3251,7 @@ static int wrmsr_interception(struct vcpu_svm *svm)
msr.host_initiated = false; msr.host_initiated = false;
svm->next_rip = kvm_rip_read(&svm->vcpu) + 2; svm->next_rip = kvm_rip_read(&svm->vcpu) + 2;
if (svm_set_msr(&svm->vcpu, &msr)) { if (kvm_set_msr(&svm->vcpu, &msr)) {
trace_kvm_msr_write_ex(ecx, data); trace_kvm_msr_write_ex(ecx, data);
kvm_inject_gp(&svm->vcpu, 0); kvm_inject_gp(&svm->vcpu, 0);
} else { } else {
...@@ -3551,9 +3551,9 @@ static int handle_exit(struct kvm_vcpu *vcpu) ...@@ -3551,9 +3551,9 @@ static int handle_exit(struct kvm_vcpu *vcpu)
if (exit_code >= ARRAY_SIZE(svm_exit_handlers) if (exit_code >= ARRAY_SIZE(svm_exit_handlers)
|| !svm_exit_handlers[exit_code]) { || !svm_exit_handlers[exit_code]) {
kvm_run->exit_reason = KVM_EXIT_UNKNOWN; WARN_ONCE(1, "vmx: unexpected exit reason 0x%x\n", exit_code);
kvm_run->hw.hardware_exit_reason = exit_code; kvm_queue_exception(vcpu, UD_VECTOR);
return 0; return 1;
} }
return svm_exit_handlers[exit_code](svm); return svm_exit_handlers[exit_code](svm);
......
...@@ -2659,12 +2659,15 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) ...@@ -2659,12 +2659,15 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
default: default:
msr = find_msr_entry(vmx, msr_index); msr = find_msr_entry(vmx, msr_index);
if (msr) { if (msr) {
u64 old_msr_data = msr->data;
msr->data = data; msr->data = data;
if (msr - vmx->guest_msrs < vmx->save_nmsrs) { if (msr - vmx->guest_msrs < vmx->save_nmsrs) {
preempt_disable(); preempt_disable();
kvm_set_shared_msr(msr->index, msr->data, ret = kvm_set_shared_msr(msr->index, msr->data,
msr->mask); msr->mask);
preempt_enable(); preempt_enable();
if (ret)
msr->data = old_msr_data;
} }
break; break;
} }
...@@ -5291,7 +5294,7 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu) ...@@ -5291,7 +5294,7 @@ static int handle_wrmsr(struct kvm_vcpu *vcpu)
msr.data = data; msr.data = data;
msr.index = ecx; msr.index = ecx;
msr.host_initiated = false; msr.host_initiated = false;
if (vmx_set_msr(vcpu, &msr) != 0) { if (kvm_set_msr(vcpu, &msr) != 0) {
trace_kvm_msr_write_ex(ecx, data); trace_kvm_msr_write_ex(ecx, data);
kvm_inject_gp(vcpu, 0); kvm_inject_gp(vcpu, 0);
return 1; return 1;
...@@ -6743,6 +6746,12 @@ static int handle_invept(struct kvm_vcpu *vcpu) ...@@ -6743,6 +6746,12 @@ static int handle_invept(struct kvm_vcpu *vcpu)
return 1; return 1;
} }
static int handle_invvpid(struct kvm_vcpu *vcpu)
{
kvm_queue_exception(vcpu, UD_VECTOR);
return 1;
}
/* /*
* The exit handlers return 1 if the exit was handled fully and guest execution * The exit handlers return 1 if the exit was handled fully and guest execution
* may resume. Otherwise they set the kvm_run parameter to indicate what needs * may resume. Otherwise they set the kvm_run parameter to indicate what needs
...@@ -6788,6 +6797,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { ...@@ -6788,6 +6797,7 @@ static int (*const kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_MWAIT_INSTRUCTION] = handle_mwait, [EXIT_REASON_MWAIT_INSTRUCTION] = handle_mwait,
[EXIT_REASON_MONITOR_INSTRUCTION] = handle_monitor, [EXIT_REASON_MONITOR_INSTRUCTION] = handle_monitor,
[EXIT_REASON_INVEPT] = handle_invept, [EXIT_REASON_INVEPT] = handle_invept,
[EXIT_REASON_INVVPID] = handle_invvpid,
}; };
static const int kvm_vmx_max_exit_handlers = static const int kvm_vmx_max_exit_handlers =
...@@ -7023,7 +7033,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu) ...@@ -7023,7 +7033,7 @@ static bool nested_vmx_exit_handled(struct kvm_vcpu *vcpu)
case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD: case EXIT_REASON_VMPTRST: case EXIT_REASON_VMREAD:
case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE: case EXIT_REASON_VMRESUME: case EXIT_REASON_VMWRITE:
case EXIT_REASON_VMOFF: case EXIT_REASON_VMON: case EXIT_REASON_VMOFF: case EXIT_REASON_VMON:
case EXIT_REASON_INVEPT: case EXIT_REASON_INVEPT: case EXIT_REASON_INVVPID:
/* /*
* VMX instructions trap unconditionally. This allows L1 to * VMX instructions trap unconditionally. This allows L1 to
* emulate them for its L2 guest, i.e., allows 3-level nesting! * emulate them for its L2 guest, i.e., allows 3-level nesting!
...@@ -7164,10 +7174,10 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu) ...@@ -7164,10 +7174,10 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
&& kvm_vmx_exit_handlers[exit_reason]) && kvm_vmx_exit_handlers[exit_reason])
return kvm_vmx_exit_handlers[exit_reason](vcpu); return kvm_vmx_exit_handlers[exit_reason](vcpu);
else { else {
vcpu->run->exit_reason = KVM_EXIT_UNKNOWN; WARN_ONCE(1, "vmx: unexpected exit reason 0x%x\n", exit_reason);
vcpu->run->hw.hardware_exit_reason = exit_reason; kvm_queue_exception(vcpu, UD_VECTOR);
return 1;
} }
return 0;
} }
static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr) static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
......
...@@ -229,20 +229,25 @@ static void kvm_shared_msr_cpu_online(void) ...@@ -229,20 +229,25 @@ static void kvm_shared_msr_cpu_online(void)
shared_msr_update(i, shared_msrs_global.msrs[i]); shared_msr_update(i, shared_msrs_global.msrs[i]);
} }
void kvm_set_shared_msr(unsigned slot, u64 value, u64 mask) int kvm_set_shared_msr(unsigned slot, u64 value, u64 mask)
{ {
unsigned int cpu = smp_processor_id(); unsigned int cpu = smp_processor_id();
struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu); struct kvm_shared_msrs *smsr = per_cpu_ptr(shared_msrs, cpu);
int err;
if (((value ^ smsr->values[slot].curr) & mask) == 0) if (((value ^ smsr->values[slot].curr) & mask) == 0)
return; return 0;
smsr->values[slot].curr = value; smsr->values[slot].curr = value;
wrmsrl(shared_msrs_global.msrs[slot], value); err = wrmsrl_safe(shared_msrs_global.msrs[slot], value);
if (err)
return 1;
if (!smsr->registered) { if (!smsr->registered) {
smsr->urn.on_user_return = kvm_on_user_return; smsr->urn.on_user_return = kvm_on_user_return;
user_return_notifier_register(&smsr->urn); user_return_notifier_register(&smsr->urn);
smsr->registered = true; smsr->registered = true;
} }
return 0;
} }
EXPORT_SYMBOL_GPL(kvm_set_shared_msr); EXPORT_SYMBOL_GPL(kvm_set_shared_msr);
...@@ -987,7 +992,6 @@ void kvm_enable_efer_bits(u64 mask) ...@@ -987,7 +992,6 @@ void kvm_enable_efer_bits(u64 mask)
} }
EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); EXPORT_SYMBOL_GPL(kvm_enable_efer_bits);
/* /*
* Writes msr value into into the appropriate "register". * Writes msr value into into the appropriate "register".
* Returns 0 on success, non-0 otherwise. * Returns 0 on success, non-0 otherwise.
...@@ -995,8 +999,34 @@ EXPORT_SYMBOL_GPL(kvm_enable_efer_bits); ...@@ -995,8 +999,34 @@ EXPORT_SYMBOL_GPL(kvm_enable_efer_bits);
*/ */
int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr) int kvm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
{ {
switch (msr->index) {
case MSR_FS_BASE:
case MSR_GS_BASE:
case MSR_KERNEL_GS_BASE:
case MSR_CSTAR:
case MSR_LSTAR:
if (is_noncanonical_address(msr->data))
return 1;
break;
case MSR_IA32_SYSENTER_EIP:
case MSR_IA32_SYSENTER_ESP:
/*
* IA32_SYSENTER_ESP and IA32_SYSENTER_EIP cause #GP if
* non-canonical address is written on Intel but not on
* AMD (which ignores the top 32-bits, because it does
* not implement 64-bit SYSENTER).
*
* 64-bit code should hence be able to write a non-canonical
* value on AMD. Making the address canonical ensures that
* vmentry does not fail on Intel after writing a non-canonical
* value, and that something deterministic happens if the guest
* invokes 64-bit SYSENTER.
*/
msr->data = get_canonical(msr->data);
}
return kvm_x86_ops->set_msr(vcpu, msr); return kvm_x86_ops->set_msr(vcpu, msr);
} }
EXPORT_SYMBOL_GPL(kvm_set_msr);
/* /*
* Adapt set_msr() to msr_io()'s calling convention * Adapt set_msr() to msr_io()'s calling convention
......
...@@ -1080,6 +1080,7 @@ void kvm_device_get(struct kvm_device *dev); ...@@ -1080,6 +1080,7 @@ void kvm_device_get(struct kvm_device *dev);
void kvm_device_put(struct kvm_device *dev); void kvm_device_put(struct kvm_device *dev);
struct kvm_device *kvm_device_from_filp(struct file *filp); struct kvm_device *kvm_device_from_filp(struct file *filp);
int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type); int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type);
void kvm_unregister_device_ops(u32 type);
extern struct kvm_device_ops kvm_mpic_ops; extern struct kvm_device_ops kvm_mpic_ops;
extern struct kvm_device_ops kvm_xics_ops; extern struct kvm_device_ops kvm_xics_ops;
......
...@@ -43,13 +43,13 @@ static void kvm_iommu_put_pages(struct kvm *kvm, ...@@ -43,13 +43,13 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
gfn_t base_gfn, unsigned long npages); gfn_t base_gfn, unsigned long npages);
static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn, static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
unsigned long size) unsigned long npages)
{ {
gfn_t end_gfn; gfn_t end_gfn;
pfn_t pfn; pfn_t pfn;
pfn = gfn_to_pfn_memslot(slot, gfn); pfn = gfn_to_pfn_memslot(slot, gfn);
end_gfn = gfn + (size >> PAGE_SHIFT); end_gfn = gfn + npages;
gfn += 1; gfn += 1;
if (is_error_noslot_pfn(pfn)) if (is_error_noslot_pfn(pfn))
...@@ -119,7 +119,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) ...@@ -119,7 +119,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
* Pin all pages we are about to map in memory. This is * Pin all pages we are about to map in memory. This is
* important because we unmap and unpin in 4kb steps later. * important because we unmap and unpin in 4kb steps later.
*/ */
pfn = kvm_pin_pages(slot, gfn, page_size); pfn = kvm_pin_pages(slot, gfn, page_size >> PAGE_SHIFT);
if (is_error_noslot_pfn(pfn)) { if (is_error_noslot_pfn(pfn)) {
gfn += 1; gfn += 1;
continue; continue;
...@@ -131,7 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot) ...@@ -131,7 +131,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
if (r) { if (r) {
printk(KERN_ERR "kvm_iommu_map_address:" printk(KERN_ERR "kvm_iommu_map_address:"
"iommu failed to map pfn=%llx\n", pfn); "iommu failed to map pfn=%llx\n", pfn);
kvm_unpin_pages(kvm, pfn, page_size); kvm_unpin_pages(kvm, pfn, page_size >> PAGE_SHIFT);
goto unmap_pages; goto unmap_pages;
} }
......
...@@ -2354,6 +2354,12 @@ int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type) ...@@ -2354,6 +2354,12 @@ int kvm_register_device_ops(struct kvm_device_ops *ops, u32 type)
return 0; return 0;
} }
void kvm_unregister_device_ops(u32 type)
{
if (kvm_device_ops_table[type] != NULL)
kvm_device_ops_table[type] = NULL;
}
static int kvm_ioctl_create_device(struct kvm *kvm, static int kvm_ioctl_create_device(struct kvm *kvm,
struct kvm_create_device *cd) struct kvm_create_device *cd)
{ {
...@@ -3328,5 +3334,6 @@ void kvm_exit(void) ...@@ -3328,5 +3334,6 @@ void kvm_exit(void)
kvm_arch_exit(); kvm_arch_exit();
kvm_irqfd_exit(); kvm_irqfd_exit();
free_cpumask_var(cpus_hardware_enabled); free_cpumask_var(cpus_hardware_enabled);
kvm_vfio_ops_exit();
} }
EXPORT_SYMBOL_GPL(kvm_exit); EXPORT_SYMBOL_GPL(kvm_exit);
...@@ -283,3 +283,8 @@ int kvm_vfio_ops_init(void) ...@@ -283,3 +283,8 @@ int kvm_vfio_ops_init(void)
{ {
return kvm_register_device_ops(&kvm_vfio_ops, KVM_DEV_TYPE_VFIO); return kvm_register_device_ops(&kvm_vfio_ops, KVM_DEV_TYPE_VFIO);
} }
void kvm_vfio_ops_exit(void)
{
kvm_unregister_device_ops(KVM_DEV_TYPE_VFIO);
}
...@@ -3,11 +3,15 @@ ...@@ -3,11 +3,15 @@
#ifdef CONFIG_KVM_VFIO #ifdef CONFIG_KVM_VFIO
int kvm_vfio_ops_init(void); int kvm_vfio_ops_init(void);
void kvm_vfio_ops_exit(void);
#else #else
static inline int kvm_vfio_ops_init(void) static inline int kvm_vfio_ops_init(void)
{ {
return 0; return 0;
} }
static inline void kvm_vfio_ops_exit(void)
{
}
#endif #endif
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment