Skip to contentSkip to conversation

x86 fixes

GIT PULL Merged Ingo Molnar 2 participants 2 messages Sep 6, 2020

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

Linus,

Please pull the latest x86/urgent git tree from:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-urgent-2020-09-06

# HEAD: 4facb95b7adaf77e2da73aafb9ba60996fe42a12 x86/entry: Unbreak 32bit fast syscall

Misc fixes:

- Fix more generic entry code ABI fallout
- Fix debug register handling bugs
- Fix vmalloc mappings on 32-bit kernels
- Fix kprobes instrumentation output on 32-bit kernels
- Fix over-eager WARN_ON_ONCE() on !SMAP hardware
- Fix NUMA debugging
- Fix Clang related crash on !RETPOLINE kernels

The most complex fixes are only a few days old and some haven't seen -next yet, but I didn't think we should delay them.

out-of-topic modifications in x86-urgent-2020-09-06:
------------------------------------------------------
include/linux/entry-common.h # 4facb95b7ada: x86/entry: Unbreak 32bit fas
kernel/entry/common.c # 4facb95b7ada: x86/entry: Unbreak 32bit fas

Thanks,

Ingo

------------------>
Andy Lutomirski (1):
x86/debug: Allow a single level of #DB recursion

Arvind Sankar (1):
x86/cmdline: Disable jump tables for cmdline.c

Huang Ying (1):
x86, fakenuma: Fix invalid starting node ID

Joerg Roedel (1):
x86/mm/32: Bring back vmalloc faulting on x86_32

Peter Zijlstra (1):
x86/entry: Fix AC assertion

Thomas Gleixner (1):
x86/entry: Unbreak 32bit fast syscall

Vamshi K Sthambamkadi (1):
tracing/kprobes, x86/ptrace: Fix regs argument order for i386

 arch/x86/entry/common.c             | 29 +++++++++-----
 arch/x86/include/asm/entry-common.h | 12 +++++-
 arch/x86/include/asm/ptrace.h       |  2 +-
 arch/x86/kernel/traps.c             | 65 +++++++++++++++----------------
 arch/x86/lib/Makefile               |  2 +-
 arch/x86/mm/fault.c                 | 78 +++++++++++++++++++++++++++++++++++++
 arch/x86/mm/numa_emulation.c        |  2 +-
 include/linux/entry-common.h        | 51 +++++++++++++++++++-----
 kernel/entry/common.c               | 35 ++++++++++++++---
 9 files changed, 213 insertions(+), 63 deletions(-)
arch/x86/entry/common.c +20 -9
index 48512c7944e7..2f84c7ca74ea 100644
@@ -60,16 +60,10 @@ __visible noinstr void do_syscall_64(unsigned long nr, struct pt_regs *regs)
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
 static __always_inline unsigned int syscall_32_enter(struct pt_regs *regs)
 {
-	unsigned int nr = (unsigned int)regs->orig_ax;
-
 	if (IS_ENABLED(CONFIG_IA32_EMULATION))
 		current_thread_info()->status |= TS_COMPAT;
-	/*
-	 * Subtlety here: if ptrace pokes something larger than 2^32-1 into
-	 * orig_ax, the unsigned int return value truncates it.  This may
-	 * or may not be necessary, but it matches the old asm behavior.
-	 */
-	return (unsigned int)syscall_enter_from_user_mode(regs, nr);
+
+	return (unsigned int)regs->orig_ax;
 }
 
 /*
@@ -91,15 +85,29 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
 	unsigned int nr = syscall_32_enter(regs);
 
+	/*
+	 * Subtlety here: if ptrace pokes something larger than 2^32-1 into
+	 * orig_ax, the unsigned int return value truncates it.  This may
+	 * or may not be necessary, but it matches the old asm behavior.
+	 */
+	nr = (unsigned int)syscall_enter_from_user_mode(regs, nr);
+
 	do_syscall_32_irqs_on(regs, nr);
 	syscall_exit_to_user_mode(regs);
 }
 
 static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 {
-	unsigned int nr	= syscall_32_enter(regs);
+	unsigned int nr = syscall_32_enter(regs);
 	int res;
 
+	/*
+	 * This cannot use syscall_enter_from_user_mode() as it has to
+	 * fetch EBP before invoking any of the syscall entry work
+	 * functions.
+	 */
+	syscall_enter_from_user_mode_prepare(regs);
+
 	instrumentation_begin();
 	/* Fetch EBP from where the vDSO stashed it. */
 	if (IS_ENABLED(CONFIG_X86_64)) {
@@ -122,6 +130,9 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 		return false;
 	}
 
+	/* The case truncates any ptrace induced syscall nr > 2^32 -1 */
+	nr = (unsigned int)syscall_enter_from_user_mode_work(regs, nr);
+
 	/* Now this is just like a normal syscall. */
 	do_syscall_32_irqs_on(regs, nr);
 	syscall_exit_to_user_mode(regs);
arch/x86/include/asm/entry-common.h +10 -2
index a8f9315b9eae..6fe54b2813c1 100644
@@ -18,8 +18,16 @@ static __always_inline void arch_check_user_regs(struct pt_regs *regs)
 		 * state, not the interrupt state as imagined by Xen.
 		 */
 		unsigned long flags = native_save_fl();
-		WARN_ON_ONCE(flags & (X86_EFLAGS_AC | X86_EFLAGS_DF |
-				      X86_EFLAGS_NT));
+		unsigned long mask = X86_EFLAGS_DF | X86_EFLAGS_NT;
+
+		/*
+		 * For !SMAP hardware we patch out CLAC on entry.
+		 */
+		if (boot_cpu_has(X86_FEATURE_SMAP) ||
+		    (IS_ENABLED(CONFIG_64_BIT) && boot_cpu_has(X86_FEATURE_XENPV)))
+			mask |= X86_EFLAGS_AC;
+
+		WARN_ON_ONCE(flags & mask);
 
 		/* We think we came from user mode. Make sure pt_regs agrees. */
 		WARN_ON_ONCE(!user_mode(regs));
arch/x86/include/asm/ptrace.h +1 -1
index 40aa69d04862..d8324a236696 100644
@@ -327,8 +327,8 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
 	static const unsigned int argument_offs[] = {
 #ifdef __i386__
 		offsetof(struct pt_regs, ax),
-		offsetof(struct pt_regs, cx),
 		offsetof(struct pt_regs, dx),
+		offsetof(struct pt_regs, cx),
 #define NR_REG_ARGUMENTS 3
 #else
 		offsetof(struct pt_regs, di),
arch/x86/kernel/traps.c +31 -34

120 lines not on this page · raw message

arch/x86/lib/Makefile +1 -1
index d46fff11f06f..aa067859a70b 100644
@@ -24,7 +24,7 @@ ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_cmdline.o = -pg
 endif
 
-CFLAGS_cmdline.o := -fno-stack-protector
+CFLAGS_cmdline.o := -fno-stack-protector -fno-jump-tables
 endif
 
 inat_tables_script = $(srctree)/arch/x86/tools/gen-insn-attr-x86.awk
arch/x86/mm/fault.c +78 -0

90 lines not on this page · raw message

arch/x86/mm/numa_emulation.c +1 -1
index c5174b4e318b..683cd12f4793 100644
@@ -321,7 +321,7 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei,
 					      u64 addr, u64 max_addr, u64 size)
 {
 	return split_nodes_size_interleave_uniform(ei, pi, addr, max_addr, size,
-			0, NULL, NUMA_NO_NODE);
+			0, NULL, 0);
 }
 
 static int __init setup_emu2phys_nid(int *dfl_phys_nid)
include/linux/entry-common.h +42 -9

69 lines not on this page · raw message

kernel/entry/common.c +29 -6
index fcae019158ca..18683598edbc 100644
@@ -69,22 +69,45 @@ static long syscall_trace_enter(struct pt_regs *regs, long syscall,
 	return ret ? : syscall_get_nr(current, regs);
 }
 
-noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
+static __always_inline long
+__syscall_enter_from_user_work(struct pt_regs *regs, long syscall)
 {
 	unsigned long ti_work;
 
-	enter_from_user_mode(regs);
-	instrumentation_begin();
-
-	local_irq_enable();
 	ti_work = READ_ONCE(current_thread_info()->flags);
 	if (ti_work & SYSCALL_ENTER_WORK)
 		syscall = syscall_trace_enter(regs, syscall, ti_work);
-	instrumentation_end();
 
 	return syscall;
 }
 
+long syscall_enter_from_user_mode_work(struct pt_regs *regs, long syscall)
+{
+	return __syscall_enter_from_user_work(regs, syscall);
+}
+
+noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
+{
+	long ret;
+
+	enter_from_user_mode(regs);
+
+	instrumentation_begin();
+	local_irq_enable();
+	ret = __syscall_enter_from_user_work(regs, syscall);
+	instrumentation_end();
+
+	return ret;
+}
+
+noinstr void syscall_enter_from_user_mode_prepare(struct pt_regs *regs)
+{
+	enter_from_user_mode(regs);
+	instrumentation_begin();
+	local_irq_enable();
+	instrumentation_end();
+}
+
 /**
  * exit_to_user_mode - Fixup state when exiting to user mode
  *