Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'x86-urgent-2020-04-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Thomas Gleixner:
"A set of three patches to fix the fallout of the newly added split
lock detection feature.

It addressed the case where a KVM guest triggers a split lock #AC and
KVM reinjects it into the guest which is not prepared to handle it.

Add proper sanity checks which prevent the unconditional injection
into the guest and handles the #AC on the host side in the same way as
user space detections are handled. Depending on the detection mode it
either warns and disables detection for the task or kills the task if
the mode is set to fatal"

* tag 'x86-urgent-2020-04-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
KVM: VMX: Extend VMXs #AC interceptor to handle split lock #AC in guest
KVM: x86: Emulate split-lock access as a write in emulator
x86/split_lock: Provide handle_guest_split_lock()

+79 -9
+6
arch/x86/include/asm/cpu.h
··· 44 44 extern void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c); 45 45 extern void switch_to_sld(unsigned long tifn); 46 46 extern bool handle_user_split_lock(struct pt_regs *regs, long error_code); 47 + extern bool handle_guest_split_lock(unsigned long ip); 47 48 #else 48 49 static inline void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) {} 49 50 static inline void switch_to_sld(unsigned long tifn) {} 50 51 static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code) 52 + { 53 + return false; 54 + } 55 + 56 + static inline bool handle_guest_split_lock(unsigned long ip) 51 57 { 52 58 return false; 53 59 }
+28 -5
arch/x86/kernel/cpu/intel.c
··· 21 21 #include <asm/elf.h> 22 22 #include <asm/cpu_device_id.h> 23 23 #include <asm/cmdline.h> 24 + #include <asm/traps.h> 24 25 25 26 #ifdef CONFIG_X86_64 26 27 #include <linux/topology.h> ··· 1067 1066 split_lock_verify_msr(sld_state != sld_off); 1068 1067 } 1069 1068 1070 - bool handle_user_split_lock(struct pt_regs *regs, long error_code) 1069 + static void split_lock_warn(unsigned long ip) 1071 1070 { 1072 - if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal) 1073 - return false; 1074 - 1075 1071 pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n", 1076 - current->comm, current->pid, regs->ip); 1072 + current->comm, current->pid, ip); 1077 1073 1078 1074 /* 1079 1075 * Disable the split lock detection for this task so it can make ··· 1079 1081 */ 1080 1082 sld_update_msr(false); 1081 1083 set_tsk_thread_flag(current, TIF_SLD); 1084 + } 1085 + 1086 + bool handle_guest_split_lock(unsigned long ip) 1087 + { 1088 + if (sld_state == sld_warn) { 1089 + split_lock_warn(ip); 1090 + return true; 1091 + } 1092 + 1093 + pr_warn_once("#AC: %s/%d %s split_lock trap at address: 0x%lx\n", 1094 + current->comm, current->pid, 1095 + sld_state == sld_fatal ? "fatal" : "bogus", ip); 1096 + 1097 + current->thread.error_code = 0; 1098 + current->thread.trap_nr = X86_TRAP_AC; 1099 + force_sig_fault(SIGBUS, BUS_ADRALN, NULL); 1100 + return false; 1101 + } 1102 + EXPORT_SYMBOL_GPL(handle_guest_split_lock); 1103 + 1104 + bool handle_user_split_lock(struct pt_regs *regs, long error_code) 1105 + { 1106 + if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal) 1107 + return false; 1108 + split_lock_warn(regs->ip); 1082 1109 return true; 1083 1110 } 1084 1111
+34 -3
arch/x86/kvm/vmx/vmx.c
··· 4588 4588 return 1; 4589 4589 } 4590 4590 4591 + /* 4592 + * If the host has split lock detection disabled, then #AC is 4593 + * unconditionally injected into the guest, which is the pre split lock 4594 + * detection behaviour. 4595 + * 4596 + * If the host has split lock detection enabled then #AC is 4597 + * only injected into the guest when: 4598 + * - Guest CPL == 3 (user mode) 4599 + * - Guest has #AC detection enabled in CR0 4600 + * - Guest EFLAGS has AC bit set 4601 + */ 4602 + static inline bool guest_inject_ac(struct kvm_vcpu *vcpu) 4603 + { 4604 + if (!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) 4605 + return true; 4606 + 4607 + return vmx_get_cpl(vcpu) == 3 && kvm_read_cr0_bits(vcpu, X86_CR0_AM) && 4608 + (kvm_get_rflags(vcpu) & X86_EFLAGS_AC); 4609 + } 4610 + 4591 4611 static int handle_exception_nmi(struct kvm_vcpu *vcpu) 4592 4612 { 4593 4613 struct vcpu_vmx *vmx = to_vmx(vcpu); ··· 4673 4653 return handle_rmode_exception(vcpu, ex_no, error_code); 4674 4654 4675 4655 switch (ex_no) { 4676 - case AC_VECTOR: 4677 - kvm_queue_exception_e(vcpu, AC_VECTOR, error_code); 4678 - return 1; 4679 4656 case DB_VECTOR: 4680 4657 dr6 = vmcs_readl(EXIT_QUALIFICATION); 4681 4658 if (!(vcpu->guest_debug & ··· 4701 4684 kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip; 4702 4685 kvm_run->debug.arch.exception = ex_no; 4703 4686 break; 4687 + case AC_VECTOR: 4688 + if (guest_inject_ac(vcpu)) { 4689 + kvm_queue_exception_e(vcpu, AC_VECTOR, error_code); 4690 + return 1; 4691 + } 4692 + 4693 + /* 4694 + * Handle split lock. Depending on detection mode this will 4695 + * either warn and disable split lock detection for this 4696 + * task or force SIGBUS on it. 4697 + */ 4698 + if (handle_guest_split_lock(kvm_rip_read(vcpu))) 4699 + return 1; 4700 + fallthrough; 4704 4701 default: 4705 4702 kvm_run->exit_reason = KVM_EXIT_EXCEPTION; 4706 4703 kvm_run->ex.exception = ex_no;
+11 -1
arch/x86/kvm/x86.c
··· 5839 5839 { 5840 5840 struct kvm_host_map map; 5841 5841 struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); 5842 + u64 page_line_mask; 5842 5843 gpa_t gpa; 5843 5844 char *kaddr; 5844 5845 bool exchanged; ··· 5854 5853 (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) 5855 5854 goto emul_write; 5856 5855 5857 - if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK)) 5856 + /* 5857 + * Emulate the atomic as a straight write to avoid #AC if SLD is 5858 + * enabled in the host and the access splits a cache line. 5859 + */ 5860 + if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) 5861 + page_line_mask = ~(cache_line_size() - 1); 5862 + else 5863 + page_line_mask = PAGE_MASK; 5864 + 5865 + if (((gpa + bytes - 1) & page_line_mask) != (gpa & page_line_mask)) 5858 5866 goto emul_write; 5859 5867 5860 5868 if (kvm_vcpu_map(vcpu, gpa_to_gfn(gpa), &map))