Skip to content

Commit 4f8a3cc

Browse files
committed
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()
2 parents 0785249 + e6f8b6c commit 4f8a3cc

File tree

4 files changed

+79
-9
lines changed

4 files changed

+79
-9
lines changed

arch/x86/include/asm/cpu.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,18 @@ unsigned int x86_stepping(unsigned int sig);
4444
extern void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c);
4545
extern void switch_to_sld(unsigned long tifn);
4646
extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
47+
extern bool handle_guest_split_lock(unsigned long ip);
4748
#else
4849
static inline void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) {}
4950
static inline void switch_to_sld(unsigned long tifn) {}
5051
static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
5152
{
5253
return false;
5354
}
55+
56+
static inline bool handle_guest_split_lock(unsigned long ip)
57+
{
58+
return false;
59+
}
5460
#endif
5561
#endif /* _ASM_X86_CPU_H */

arch/x86/kernel/cpu/intel.c

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <asm/elf.h>
2222
#include <asm/cpu_device_id.h>
2323
#include <asm/cmdline.h>
24+
#include <asm/traps.h>
2425

2526
#ifdef CONFIG_X86_64
2627
#include <linux/topology.h>
@@ -1066,13 +1067,10 @@ static void split_lock_init(void)
10661067
split_lock_verify_msr(sld_state != sld_off);
10671068
}
10681069

1069-
bool handle_user_split_lock(struct pt_regs *regs, long error_code)
1070+
static void split_lock_warn(unsigned long ip)
10701071
{
1071-
if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal)
1072-
return false;
1073-
10741072
pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n",
1075-
current->comm, current->pid, regs->ip);
1073+
current->comm, current->pid, ip);
10761074

10771075
/*
10781076
* Disable the split lock detection for this task so it can make
@@ -1081,6 +1079,31 @@ bool handle_user_split_lock(struct pt_regs *regs, long error_code)
10811079
*/
10821080
sld_update_msr(false);
10831081
set_tsk_thread_flag(current, TIF_SLD);
1082+
}
1083+
1084+
bool handle_guest_split_lock(unsigned long ip)
1085+
{
1086+
if (sld_state == sld_warn) {
1087+
split_lock_warn(ip);
1088+
return true;
1089+
}
1090+
1091+
pr_warn_once("#AC: %s/%d %s split_lock trap at address: 0x%lx\n",
1092+
current->comm, current->pid,
1093+
sld_state == sld_fatal ? "fatal" : "bogus", ip);
1094+
1095+
current->thread.error_code = 0;
1096+
current->thread.trap_nr = X86_TRAP_AC;
1097+
force_sig_fault(SIGBUS, BUS_ADRALN, NULL);
1098+
return false;
1099+
}
1100+
EXPORT_SYMBOL_GPL(handle_guest_split_lock);
1101+
1102+
bool handle_user_split_lock(struct pt_regs *regs, long error_code)
1103+
{
1104+
if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal)
1105+
return false;
1106+
split_lock_warn(regs->ip);
10841107
return true;
10851108
}
10861109

arch/x86/kvm/vmx/vmx.c

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4588,6 +4588,26 @@ static int handle_machine_check(struct kvm_vcpu *vcpu)
45884588
return 1;
45894589
}
45904590

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+
45914611
static int handle_exception_nmi(struct kvm_vcpu *vcpu)
45924612
{
45934613
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -4653,9 +4673,6 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
46534673
return handle_rmode_exception(vcpu, ex_no, error_code);
46544674

46554675
switch (ex_no) {
4656-
case AC_VECTOR:
4657-
kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
4658-
return 1;
46594676
case DB_VECTOR:
46604677
dr6 = vmcs_readl(EXIT_QUALIFICATION);
46614678
if (!(vcpu->guest_debug &
@@ -4684,6 +4701,20 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
46844701
kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
46854702
kvm_run->debug.arch.exception = ex_no;
46864703
break;
4704+
case AC_VECTOR:
4705+
if (guest_inject_ac(vcpu)) {
4706+
kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
4707+
return 1;
4708+
}
4709+
4710+
/*
4711+
* Handle split lock. Depending on detection mode this will
4712+
* either warn and disable split lock detection for this
4713+
* task or force SIGBUS on it.
4714+
*/
4715+
if (handle_guest_split_lock(kvm_rip_read(vcpu)))
4716+
return 1;
4717+
fallthrough;
46874718
default:
46884719
kvm_run->exit_reason = KVM_EXIT_EXCEPTION;
46894720
kvm_run->ex.exception = ex_no;

arch/x86/kvm/x86.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5839,6 +5839,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
58395839
{
58405840
struct kvm_host_map map;
58415841
struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
5842+
u64 page_line_mask;
58425843
gpa_t gpa;
58435844
char *kaddr;
58445845
bool exchanged;
@@ -5853,7 +5854,16 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
58535854
(gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
58545855
goto emul_write;
58555856

5856-
if (((gpa + bytes - 1) & PAGE_MASK) != (gpa & PAGE_MASK))
5857+
/*
5858+
* Emulate the atomic as a straight write to avoid #AC if SLD is
5859+
* enabled in the host and the access splits a cache line.
5860+
*/
5861+
if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
5862+
page_line_mask = ~(cache_line_size() - 1);
5863+
else
5864+
page_line_mask = PAGE_MASK;
5865+
5866+
if (((gpa + bytes - 1) & page_line_mask) != (gpa & page_line_mask))
58575867
goto emul_write;
58585868

58595869
if (kvm_vcpu_map(vcpu, gpa_to_gfn(gpa), &map))

0 commit comments

Comments
 (0)