Skip to content

Commit 72674d4

Browse files
committed
Merge tag 'x86-urgent-2020-07-05' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 fixes from Thomas Gleixner: "A series of fixes for x86: - Reset MXCSR in kernel_fpu_begin() to prevent using a stale user space value. - Prevent writing MSR_TEST_CTRL on CPUs which are not explicitly whitelisted for split lock detection. Some CPUs which do not support it crash even when the MSR is written to 0 which is the default value. - Fix the XEN PV fallout of the entry code rework - Fix the 32bit fallout of the entry code rework - Add more selftests to ensure that these entry problems don't come back. - Disable 16 bit segments on XEN PV. It's not supported because XEN PV does not implement ESPFIX64" * tag 'x86-urgent-2020-07-05' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/ldt: Disable 16-bit segments on Xen PV x86/entry/32: Fix #MC and #DB wiring on x86_32 x86/entry/xen: Route #DB correctly on Xen PV x86/entry, selftests: Further improve user entry sanity checks x86/entry/compat: Clear RAX high bits on Xen PV SYSENTER selftests/x86: Consolidate and fix get/set_eflags() helpers selftests/x86/syscall_nt: Clear weird flags after each test selftests/x86/syscall_nt: Add more flag combinations x86/entry/64/compat: Fix Xen PV SYSENTER frame setup x86/entry: Move SYSENTER's regs->sp and regs->flags fixups into C x86/entry: Assert that syscalls are on the right stack x86/split_lock: Don't write MSR_TEST_CTRL on CPUs that aren't whitelisted x86/fpu: Reset MXCSR to default in kernel_fpu_begin()
2 parents f23dbe1 + cc80183 commit 72674d4

File tree

19 files changed

+274
-154
lines changed

19 files changed

+274
-154
lines changed

arch/x86/entry/common.c

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,32 @@
4545
#define CREATE_TRACE_POINTS
4646
#include <trace/events/syscalls.h>
4747

48+
/* Check that the stack and regs on entry from user mode are sane. */
49+
static void check_user_regs(struct pt_regs *regs)
50+
{
51+
if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) {
52+
/*
53+
* Make sure that the entry code gave us a sensible EFLAGS
54+
* register. Native because we want to check the actual CPU
55+
* state, not the interrupt state as imagined by Xen.
56+
*/
57+
unsigned long flags = native_save_fl();
58+
WARN_ON_ONCE(flags & (X86_EFLAGS_AC | X86_EFLAGS_DF |
59+
X86_EFLAGS_NT));
60+
61+
/* We think we came from user mode. Make sure pt_regs agrees. */
62+
WARN_ON_ONCE(!user_mode(regs));
63+
64+
/*
65+
* All entries from user mode (except #DF) should be on the
66+
* normal thread stack and should have user pt_regs in the
67+
* correct location.
68+
*/
69+
WARN_ON_ONCE(!on_thread_stack());
70+
WARN_ON_ONCE(regs != task_pt_regs(current));
71+
}
72+
}
73+
4874
#ifdef CONFIG_CONTEXT_TRACKING
4975
/**
5076
* enter_from_user_mode - Establish state when coming from user mode
@@ -127,9 +153,6 @@ static long syscall_trace_enter(struct pt_regs *regs)
127153
unsigned long ret = 0;
128154
u32 work;
129155

130-
if (IS_ENABLED(CONFIG_DEBUG_ENTRY))
131-
BUG_ON(regs != task_pt_regs(current));
132-
133156
work = READ_ONCE(ti->flags);
134157

135158
if (work & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU)) {
@@ -346,6 +369,8 @@ __visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs)
346369
{
347370
struct thread_info *ti;
348371

372+
check_user_regs(regs);
373+
349374
enter_from_user_mode();
350375
instrumentation_begin();
351376

@@ -409,6 +434,8 @@ static void do_syscall_32_irqs_on(struct pt_regs *regs)
409434
/* Handles int $0x80 */
410435
__visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
411436
{
437+
check_user_regs(regs);
438+
412439
enter_from_user_mode();
413440
instrumentation_begin();
414441

@@ -460,6 +487,8 @@ __visible noinstr long do_fast_syscall_32(struct pt_regs *regs)
460487
vdso_image_32.sym_int80_landing_pad;
461488
bool success;
462489

490+
check_user_regs(regs);
491+
463492
/*
464493
* SYSENTER loses EIP, and even SYSCALL32 needs us to skip forward
465494
* so that 'regs->ip -= 2' lands back on an int $0x80 instruction.
@@ -510,6 +539,18 @@ __visible noinstr long do_fast_syscall_32(struct pt_regs *regs)
510539
(regs->flags & (X86_EFLAGS_RF | X86_EFLAGS_TF | X86_EFLAGS_VM)) == 0;
511540
#endif
512541
}
542+
543+
/* Returns 0 to return using IRET or 1 to return using SYSEXIT/SYSRETL. */
544+
__visible noinstr long do_SYSENTER_32(struct pt_regs *regs)
545+
{
546+
/* SYSENTER loses RSP, but the vDSO saved it in RBP. */
547+
regs->sp = regs->bp;
548+
549+
/* SYSENTER clobbers EFLAGS.IF. Assume it was set in usermode. */
550+
regs->flags |= X86_EFLAGS_IF;
551+
552+
return do_fast_syscall_32(regs);
553+
}
513554
#endif
514555

515556
SYSCALL_DEFINE0(ni_syscall)
@@ -553,6 +594,7 @@ SYSCALL_DEFINE0(ni_syscall)
553594
bool noinstr idtentry_enter_cond_rcu(struct pt_regs *regs)
554595
{
555596
if (user_mode(regs)) {
597+
check_user_regs(regs);
556598
enter_from_user_mode();
557599
return false;
558600
}
@@ -686,6 +728,7 @@ void noinstr idtentry_exit_cond_rcu(struct pt_regs *regs, bool rcu_exit)
686728
*/
687729
void noinstr idtentry_enter_user(struct pt_regs *regs)
688730
{
731+
check_user_regs(regs);
689732
enter_from_user_mode();
690733
}
691734

arch/x86/entry/entry_32.S

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -933,9 +933,8 @@ SYM_FUNC_START(entry_SYSENTER_32)
933933

934934
.Lsysenter_past_esp:
935935
pushl $__USER_DS /* pt_regs->ss */
936-
pushl %ebp /* pt_regs->sp (stashed in bp) */
936+
pushl $0 /* pt_regs->sp (placeholder) */
937937
pushfl /* pt_regs->flags (except IF = 0) */
938-
orl $X86_EFLAGS_IF, (%esp) /* Fix IF */
939938
pushl $__USER_CS /* pt_regs->cs */
940939
pushl $0 /* pt_regs->ip = 0 (placeholder) */
941940
pushl %eax /* pt_regs->orig_ax */
@@ -965,7 +964,7 @@ SYM_FUNC_START(entry_SYSENTER_32)
965964
.Lsysenter_flags_fixed:
966965

967966
movl %esp, %eax
968-
call do_fast_syscall_32
967+
call do_SYSENTER_32
969968
/* XEN PV guests always use IRET path */
970969
ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
971970
"jmp .Lsyscall_32_done", X86_FEATURE_XENPV

arch/x86/entry/entry_64_compat.S

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,29 +57,30 @@ SYM_CODE_START(entry_SYSENTER_compat)
5757

5858
movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
5959

60-
/*
61-
* User tracing code (ptrace or signal handlers) might assume that
62-
* the saved RAX contains a 32-bit number when we're invoking a 32-bit
63-
* syscall. Just in case the high bits are nonzero, zero-extend
64-
* the syscall number. (This could almost certainly be deleted
65-
* with no ill effects.)
66-
*/
67-
movl %eax, %eax
68-
6960
/* Construct struct pt_regs on stack */
7061
pushq $__USER32_DS /* pt_regs->ss */
71-
pushq %rbp /* pt_regs->sp (stashed in bp) */
62+
pushq $0 /* pt_regs->sp = 0 (placeholder) */
7263

7364
/*
7465
* Push flags. This is nasty. First, interrupts are currently
75-
* off, but we need pt_regs->flags to have IF set. Second, even
76-
* if TF was set when SYSENTER started, it's clear by now. We fix
77-
* that later using TIF_SINGLESTEP.
66+
* off, but we need pt_regs->flags to have IF set. Second, if TS
67+
* was set in usermode, it's still set, and we're singlestepping
68+
* through this code. do_SYSENTER_32() will fix up IF.
7869
*/
7970
pushfq /* pt_regs->flags (except IF = 0) */
80-
orl $X86_EFLAGS_IF, (%rsp) /* Fix saved flags */
8171
pushq $__USER32_CS /* pt_regs->cs */
8272
pushq $0 /* pt_regs->ip = 0 (placeholder) */
73+
SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
74+
75+
/*
76+
* User tracing code (ptrace or signal handlers) might assume that
77+
* the saved RAX contains a 32-bit number when we're invoking a 32-bit
78+
* syscall. Just in case the high bits are nonzero, zero-extend
79+
* the syscall number. (This could almost certainly be deleted
80+
* with no ill effects.)
81+
*/
82+
movl %eax, %eax
83+
8384
pushq %rax /* pt_regs->orig_ax */
8485
pushq %rdi /* pt_regs->di */
8586
pushq %rsi /* pt_regs->si */
@@ -135,7 +136,7 @@ SYM_CODE_START(entry_SYSENTER_compat)
135136
.Lsysenter_flags_fixed:
136137

137138
movq %rsp, %rdi
138-
call do_fast_syscall_32
139+
call do_SYSENTER_32
139140
/* XEN PV guests always use IRET path */
140141
ALTERNATIVE "testl %eax, %eax; jz swapgs_restore_regs_and_return_to_usermode", \
141142
"jmp swapgs_restore_regs_and_return_to_usermode", X86_FEATURE_XENPV

arch/x86/include/asm/fpu/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,11 @@ static inline void switch_fpu_finish(struct fpu *new_fpu)
623623
* MXCSR and XCR definitions:
624624
*/
625625

626+
static inline void ldmxcsr(u32 mxcsr)
627+
{
628+
asm volatile("ldmxcsr %0" :: "m" (mxcsr));
629+
}
630+
626631
extern unsigned int mxcsr_feature_mask;
627632

628633
#define XCR_XFEATURE_ENABLED_MASK 0x00000000

arch/x86/include/asm/idtentry.h

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,6 @@ static __always_inline void __##func(struct pt_regs *regs)
353353

354354
#else /* CONFIG_X86_64 */
355355

356-
/* Maps to a regular IDTENTRY on 32bit for now */
357-
# define DECLARE_IDTENTRY_IST DECLARE_IDTENTRY
358-
# define DEFINE_IDTENTRY_IST DEFINE_IDTENTRY
359-
360356
/**
361357
* DECLARE_IDTENTRY_DF - Declare functions for double fault 32bit variant
362358
* @vector: Vector number (ignored for C)
@@ -387,28 +383,18 @@ __visible noinstr void func(struct pt_regs *regs, \
387383
#endif /* !CONFIG_X86_64 */
388384

389385
/* C-Code mapping */
386+
#define DECLARE_IDTENTRY_NMI DECLARE_IDTENTRY_RAW
387+
#define DEFINE_IDTENTRY_NMI DEFINE_IDTENTRY_RAW
388+
389+
#ifdef CONFIG_X86_64
390390
#define DECLARE_IDTENTRY_MCE DECLARE_IDTENTRY_IST
391391
#define DEFINE_IDTENTRY_MCE DEFINE_IDTENTRY_IST
392392
#define DEFINE_IDTENTRY_MCE_USER DEFINE_IDTENTRY_NOIST
393393

394-
#define DECLARE_IDTENTRY_NMI DECLARE_IDTENTRY_RAW
395-
#define DEFINE_IDTENTRY_NMI DEFINE_IDTENTRY_RAW
396-
397394
#define DECLARE_IDTENTRY_DEBUG DECLARE_IDTENTRY_IST
398395
#define DEFINE_IDTENTRY_DEBUG DEFINE_IDTENTRY_IST
399396
#define DEFINE_IDTENTRY_DEBUG_USER DEFINE_IDTENTRY_NOIST
400-
401-
/**
402-
* DECLARE_IDTENTRY_XEN - Declare functions for XEN redirect IDT entry points
403-
* @vector: Vector number (ignored for C)
404-
* @func: Function name of the entry point
405-
*
406-
* Used for xennmi and xendebug redirections. No DEFINE as this is all ASM
407-
* indirection magic.
408-
*/
409-
#define DECLARE_IDTENTRY_XEN(vector, func) \
410-
asmlinkage void xen_asm_exc_xen##func(void); \
411-
asmlinkage void asm_exc_xen##func(void)
397+
#endif
412398

413399
#else /* !__ASSEMBLY__ */
414400

@@ -455,9 +441,6 @@ __visible noinstr void func(struct pt_regs *regs, \
455441
# define DECLARE_IDTENTRY_MCE(vector, func) \
456442
DECLARE_IDTENTRY(vector, func)
457443

458-
# define DECLARE_IDTENTRY_DEBUG(vector, func) \
459-
DECLARE_IDTENTRY(vector, func)
460-
461444
/* No ASM emitted for DF as this goes through a C shim */
462445
# define DECLARE_IDTENTRY_DF(vector, func)
463446

@@ -469,10 +452,6 @@ __visible noinstr void func(struct pt_regs *regs, \
469452
/* No ASM code emitted for NMI */
470453
#define DECLARE_IDTENTRY_NMI(vector, func)
471454

472-
/* XEN NMI and DB wrapper */
473-
#define DECLARE_IDTENTRY_XEN(vector, func) \
474-
idtentry vector asm_exc_xen##func exc_##func has_error_code=0
475-
476455
/*
477456
* ASM code to emit the common vector entry stubs where each stub is
478457
* packed into 8 bytes.
@@ -565,16 +544,28 @@ DECLARE_IDTENTRY_RAW(X86_TRAP_BP, exc_int3);
565544
DECLARE_IDTENTRY_RAW_ERRORCODE(X86_TRAP_PF, exc_page_fault);
566545

567546
#ifdef CONFIG_X86_MCE
547+
#ifdef CONFIG_X86_64
568548
DECLARE_IDTENTRY_MCE(X86_TRAP_MC, exc_machine_check);
549+
#else
550+
DECLARE_IDTENTRY_RAW(X86_TRAP_MC, exc_machine_check);
551+
#endif
569552
#endif
570553

571554
/* NMI */
572555
DECLARE_IDTENTRY_NMI(X86_TRAP_NMI, exc_nmi);
573-
DECLARE_IDTENTRY_XEN(X86_TRAP_NMI, nmi);
556+
#ifdef CONFIG_XEN_PV
557+
DECLARE_IDTENTRY_RAW(X86_TRAP_NMI, xenpv_exc_nmi);
558+
#endif
574559

575560
/* #DB */
561+
#ifdef CONFIG_X86_64
576562
DECLARE_IDTENTRY_DEBUG(X86_TRAP_DB, exc_debug);
577-
DECLARE_IDTENTRY_XEN(X86_TRAP_DB, debug);
563+
#else
564+
DECLARE_IDTENTRY_RAW(X86_TRAP_DB, exc_debug);
565+
#endif
566+
#ifdef CONFIG_XEN_PV
567+
DECLARE_IDTENTRY_RAW(X86_TRAP_DB, xenpv_exc_debug);
568+
#endif
578569

579570
/* #DF */
580571
DECLARE_IDTENTRY_DF(X86_TRAP_DF, exc_double_fault);

arch/x86/kernel/cpu/intel.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ enum split_lock_detect_state {
4949
static enum split_lock_detect_state sld_state __ro_after_init = sld_off;
5050
static u64 msr_test_ctrl_cache __ro_after_init;
5151

52+
/*
53+
* With a name like MSR_TEST_CTL it should go without saying, but don't touch
54+
* MSR_TEST_CTL unless the CPU is one of the whitelisted models. Writing it
55+
* on CPUs that do not support SLD can cause fireworks, even when writing '0'.
56+
*/
57+
static bool cpu_model_supports_sld __ro_after_init;
58+
5259
/*
5360
* Processors which have self-snooping capability can handle conflicting
5461
* memory type across CPUs by snooping its own cache. However, there exists
@@ -1071,7 +1078,8 @@ static void sld_update_msr(bool on)
10711078

10721079
static void split_lock_init(void)
10731080
{
1074-
split_lock_verify_msr(sld_state != sld_off);
1081+
if (cpu_model_supports_sld)
1082+
split_lock_verify_msr(sld_state != sld_off);
10751083
}
10761084

10771085
static void split_lock_warn(unsigned long ip)
@@ -1177,5 +1185,6 @@ void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c)
11771185
return;
11781186
}
11791187

1188+
cpu_model_supports_sld = true;
11801189
split_lock_setup();
11811190
}

arch/x86/kernel/cpu/mce/core.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1901,6 +1901,8 @@ void (*machine_check_vector)(struct pt_regs *) = unexpected_machine_check;
19011901

19021902
static __always_inline void exc_machine_check_kernel(struct pt_regs *regs)
19031903
{
1904+
WARN_ON_ONCE(user_mode(regs));
1905+
19041906
/*
19051907
* Only required when from kernel mode. See
19061908
* mce_check_crashing_cpu() for details.
@@ -1954,7 +1956,7 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check)
19541956
}
19551957
#else
19561958
/* 32bit unified entry point */
1957-
DEFINE_IDTENTRY_MCE(exc_machine_check)
1959+
DEFINE_IDTENTRY_RAW(exc_machine_check)
19581960
{
19591961
unsigned long dr7;
19601962

arch/x86/kernel/fpu/core.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ void kernel_fpu_begin(void)
101101
copy_fpregs_to_fpstate(&current->thread.fpu);
102102
}
103103
__cpu_invalidate_fpregs_state();
104+
105+
if (boot_cpu_has(X86_FEATURE_XMM))
106+
ldmxcsr(MXCSR_DEFAULT);
107+
108+
if (boot_cpu_has(X86_FEATURE_FPU))
109+
asm volatile ("fninit");
104110
}
105111
EXPORT_SYMBOL_GPL(kernel_fpu_begin);
106112

0 commit comments

Comments
 (0)