From 790ce3b40017bbd759a3d81e23c05d42b3d34b90 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 14 Jul 2020 16:01:52 +0200 Subject: x86/idtentry: Remove stale comment Stack switching for interrupt handlers happens in C now for both 64 and 32bit. Remove the stale comment which claims the contrary. Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/idtentry.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'arch/x86/include') diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 2293b443b193..50ea186b8108 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -191,11 +191,9 @@ __visible noinstr void func(struct pt_regs *regs, unsigned long error_code) * to the function as error_code argument which needs to be truncated * to an u8 because the push is sign extending. * - * On 64-bit idtentry_enter/exit() are invoked in the ASM entry code before - * and after switching to the interrupt stack. On 32-bit this happens in C. - * * irq_enter/exit_rcu() are invoked before the function body and the - * KVM L1D flush request is set. + * KVM L1D flush request is set. Stack switching to the interrupt stack + * has to be done in the function body if necessary. */ #define DEFINE_IDTENTRY_IRQ(func) \ static __always_inline void __##func(struct pt_regs *regs, u8 vector); \ -- cgit v1.2.3 From 0bf019ea59e330770883ede4499d7f711d8c3adf Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 23 Jul 2020 00:00:03 +0200 Subject: x86/ptrace: Provide pt_regs helper for entry/exit As a preparatory step for moving the syscall and interrupt entry/exit handling into generic code, provide a pt_regs helper which retrieves the interrupt state from pt_regs. This is required to check whether interrupts are reenabled by return from interrupt/exception. Signed-off-by: Thomas Gleixner Reviewed-by: Kees Cook Link: https://lkml.kernel.org/r/20200722220520.258511584@linutronix.de --- arch/x86/include/asm/ptrace.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/x86/include') diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h index 255b2dde2c1b..40aa69d04862 100644 --- a/arch/x86/include/asm/ptrace.h +++ b/arch/x86/include/asm/ptrace.h @@ -209,6 +209,11 @@ static inline void user_stack_pointer_set(struct pt_regs *regs, regs->sp = val; } +static __always_inline bool regs_irqs_disabled(struct pt_regs *regs) +{ + return !(regs->flags & X86_EFLAGS_IF); +} + /* Query offset/name of register from its name/offset */ extern int regs_query_register_offset(const char *name); extern const char *regs_query_register_name(unsigned int offset); -- cgit v1.2.3 From 27d6b4d14f5c3ab21c4aef87dd04055a2d7adf14 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 23 Jul 2020 00:00:04 +0200 Subject: x86/entry: Use generic syscall entry function Replace the syscall entry work handling with the generic version. Provide the necessary helper inlines to handle the real architecture specific parts, e.g. ptrace. Use a temporary define for idtentry_enter_user which will be cleaned up seperately. Signed-off-by: Thomas Gleixner Reviewed-by: Kees Cook Link: https://lkml.kernel.org/r/20200722220520.376213694@linutronix.de --- arch/x86/include/asm/entry-common.h | 32 ++++++++++++++++++++++++++++++++ arch/x86/include/asm/idtentry.h | 5 ++++- arch/x86/include/asm/thread_info.h | 5 ----- 3 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 arch/x86/include/asm/entry-common.h (limited to 'arch/x86/include') diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h new file mode 100644 index 000000000000..7070b90c8312 --- /dev/null +++ b/arch/x86/include/asm/entry-common.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _ASM_X86_ENTRY_COMMON_H +#define _ASM_X86_ENTRY_COMMON_H + +/* Check that the stack and regs on entry from user mode are sane. */ +static __always_inline void arch_check_user_regs(struct pt_regs *regs) +{ + if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) { + /* + * Make sure that the entry code gave us a sensible EFLAGS + * register. Native because we want to check the actual CPU + * 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)); + + /* We think we came from user mode. Make sure pt_regs agrees. */ + WARN_ON_ONCE(!user_mode(regs)); + + /* + * All entries from user mode (except #DF) should be on the + * normal thread stack and should have user pt_regs in the + * correct location. + */ + WARN_ON_ONCE(!on_thread_stack()); + WARN_ON_ONCE(regs != task_pt_regs(current)); + } +} +#define arch_check_user_regs arch_check_user_regs + +#endif diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 1bc6f878bd30..449910fd454b 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -6,11 +6,14 @@ #include #ifndef __ASSEMBLY__ +#include #include #include -void idtentry_enter_user(struct pt_regs *regs); +/* Temporary define */ +#define idtentry_enter_user irqentry_enter_from_user_mode + void idtentry_exit_user(struct pt_regs *regs); typedef struct idtentry_state { diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 8de8ceccb8bc..267701ae3d86 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -133,11 +133,6 @@ struct thread_info { #define _TIF_X32 (1 << TIF_X32) #define _TIF_FSCHECK (1 << TIF_FSCHECK) -/* Work to do before invoking the actual syscall. */ -#define _TIF_WORK_SYSCALL_ENTRY \ - (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \ - _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT) - /* flags to check in __switch_to() */ #define _TIF_WORK_CTXSW_BASE \ (_TIF_NOCPUID | _TIF_NOTSC | _TIF_BLOCKSTEP | \ -- cgit v1.2.3 From 167fd210ec0555d371a20435dac7c2c7052df7ed Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 23 Jul 2020 00:00:05 +0200 Subject: x86/entry: Use generic syscall exit functionality Replace the x86 variant with the generic version. Provide the relevant architecture specific helper functions and defines. Use a temporary define for idtentry_exit_user which will be cleaned up seperately. Signed-off-by: Thomas Gleixner Acked-by: Kees Cook Link: https://lkml.kernel.org/r/20200722220520.494648601@linutronix.de --- arch/x86/include/asm/entry-common.h | 44 +++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/idtentry.h | 3 +-- arch/x86/include/asm/signal.h | 1 - 3 files changed, 45 insertions(+), 3 deletions(-) (limited to 'arch/x86/include') diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h index 7070b90c8312..a8f9315b9eae 100644 --- a/arch/x86/include/asm/entry-common.h +++ b/arch/x86/include/asm/entry-common.h @@ -2,6 +2,12 @@ #ifndef _ASM_X86_ENTRY_COMMON_H #define _ASM_X86_ENTRY_COMMON_H +#include + +#include +#include +#include + /* Check that the stack and regs on entry from user mode are sane. */ static __always_inline void arch_check_user_regs(struct pt_regs *regs) { @@ -29,4 +35,42 @@ static __always_inline void arch_check_user_regs(struct pt_regs *regs) } #define arch_check_user_regs arch_check_user_regs +#define ARCH_SYSCALL_EXIT_WORK (_TIF_SINGLESTEP) + +static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs, + unsigned long ti_work) +{ + if (ti_work & _TIF_USER_RETURN_NOTIFY) + fire_user_return_notifiers(); + + if (unlikely(ti_work & _TIF_IO_BITMAP)) + tss_update_io_bitmap(); + + fpregs_assert_state_consistent(); + if (unlikely(ti_work & _TIF_NEED_FPU_LOAD)) + switch_fpu_return(); + +#ifdef CONFIG_COMPAT + /* + * Compat syscalls set TS_COMPAT. Make sure we clear it before + * returning to user mode. We need to clear it *after* signal + * handling, because syscall restart has a fixup for compat + * syscalls. The fixup is exercised by the ptrace_syscall_32 + * selftest. + * + * We also need to clear TS_REGS_POKED_I386: the 32-bit tracer + * special case only applies after poking regs and before the + * very next return to user mode. + */ + current_thread_info()->status &= ~(TS_COMPAT | TS_I386_REGS_POKED); +#endif +} +#define arch_exit_to_user_mode_prepare arch_exit_to_user_mode_prepare + +static __always_inline void arch_exit_to_user_mode(void) +{ + mds_user_clear_cpu_buffers(); +} +#define arch_exit_to_user_mode arch_exit_to_user_mode + #endif diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 449910fd454b..f7d48ea51ab3 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -13,8 +13,7 @@ /* Temporary define */ #define idtentry_enter_user irqentry_enter_from_user_mode - -void idtentry_exit_user(struct pt_regs *regs); +#define idtentry_exit_user irqentry_exit_to_user_mode typedef struct idtentry_state { bool exit_rcu; diff --git a/arch/x86/include/asm/signal.h b/arch/x86/include/asm/signal.h index 33d3c88a7225..6fd8410a3910 100644 --- a/arch/x86/include/asm/signal.h +++ b/arch/x86/include/asm/signal.h @@ -35,7 +35,6 @@ typedef sigset_t compat_sigset_t; #endif /* __ASSEMBLY__ */ #include #ifndef __ASSEMBLY__ -extern void do_signal(struct pt_regs *regs); #define __ARCH_HAS_SA_RESTORER -- cgit v1.2.3 From 517e499227bed34acc69166691e2db5df3dc859a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 23 Jul 2020 00:00:06 +0200 Subject: x86/entry: Cleanup idtentry_entry/exit_user Cleanup the temporary defines and use irqentry_ instead of idtentry_. Signed-off-by: Thomas Gleixner Reviewed-by: Kees Cook Link: https://lkml.kernel.org/r/20200722220520.602603691@linutronix.de --- arch/x86/include/asm/idtentry.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'arch/x86/include') diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index f7d48ea51ab3..bf59f72140cc 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -11,10 +11,6 @@ #include -/* Temporary define */ -#define idtentry_enter_user irqentry_enter_from_user_mode -#define idtentry_exit_user irqentry_exit_to_user_mode - typedef struct idtentry_state { bool exit_rcu; } idtentry_state_t; -- cgit v1.2.3 From bdcd178ada90d2413bcc9df4211dcdd511a47586 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 23 Jul 2020 00:00:07 +0200 Subject: x86/entry: Use generic interrupt entry/exit code Replace the x86 code with the generic variant. Use temporary defines for idtentry_* which will be cleaned up in the next step. Signed-off-by: Thomas Gleixner Link: https://lkml.kernel.org/r/20200722220520.711492752@linutronix.de --- arch/x86/include/asm/idtentry.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'arch/x86/include') diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index bf59f72140cc..621e25d08a3f 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -11,12 +11,10 @@ #include -typedef struct idtentry_state { - bool exit_rcu; -} idtentry_state_t; - -idtentry_state_t idtentry_enter(struct pt_regs *regs); -void idtentry_exit(struct pt_regs *regs, idtentry_state_t state); +/* Temporary defines */ +typedef irqentry_state_t idtentry_state_t; +#define idtentry_enter irqentry_enter +#define idtentry_exit irqentry_exit /** * DECLARE_IDTENTRY - Declare functions for simple IDT entry points -- cgit v1.2.3 From a27a0a55495cdde4b8d98f82460dc46eb44777fd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 23 Jul 2020 00:00:08 +0200 Subject: x86/entry: Cleanup idtentry_enter/exit Remove the temporary defines and fixup all references. Signed-off-by: Thomas Gleixner Reviewed-by: Kees Cook Link: https://lkml.kernel.org/r/20200722220520.855839271@linutronix.de --- arch/x86/include/asm/idtentry.h | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'arch/x86/include') diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h index 621e25d08a3f..73eb277e63ab 100644 --- a/arch/x86/include/asm/idtentry.h +++ b/arch/x86/include/asm/idtentry.h @@ -11,11 +11,6 @@ #include -/* Temporary defines */ -typedef irqentry_state_t idtentry_state_t; -#define idtentry_enter irqentry_enter -#define idtentry_exit irqentry_exit - /** * DECLARE_IDTENTRY - Declare functions for simple IDT entry points * No error code pushed by hardware @@ -45,8 +40,8 @@ typedef irqentry_state_t idtentry_state_t; * The macro is written so it acts as function definition. Append the * body with a pair of curly brackets. * - * idtentry_enter() contains common code which has to be invoked before - * arbitrary code in the body. idtentry_exit() contains common code + * irqentry_enter() contains common code which has to be invoked before + * arbitrary code in the body. irqentry_exit() contains common code * which has to run before returning to the low level assembly code. */ #define DEFINE_IDTENTRY(func) \ @@ -54,12 +49,12 @@ static __always_inline void __##func(struct pt_regs *regs); \ \ __visible noinstr void func(struct pt_regs *regs) \ { \ - idtentry_state_t state = idtentry_enter(regs); \ + irqentry_state_t state = irqentry_enter(regs); \ \ instrumentation_begin(); \ __##func (regs); \ instrumentation_end(); \ - idtentry_exit(regs, state); \ + irqentry_exit(regs, state); \ } \ \ static __always_inline void __##func(struct pt_regs *regs) @@ -101,12 +96,12 @@ static __always_inline void __##func(struct pt_regs *regs, \ __visible noinstr void func(struct pt_regs *regs, \ unsigned long error_code) \ { \ - idtentry_state_t state = idtentry_enter(regs); \ + irqentry_state_t state = irqentry_enter(regs); \ \ instrumentation_begin(); \ __##func (regs, error_code); \ instrumentation_end(); \ - idtentry_exit(regs, state); \ + irqentry_exit(regs, state); \ } \ \ static __always_inline void __##func(struct pt_regs *regs, \ @@ -161,7 +156,7 @@ __visible noinstr void func(struct pt_regs *regs) * body with a pair of curly brackets. * * Contrary to DEFINE_IDTENTRY_ERRORCODE() this does not invoke the - * idtentry_enter/exit() helpers before and after the body invocation. This + * irqentry_enter/exit() helpers before and after the body invocation. This * needs to be done in the body itself if applicable. Use if extra work * is required before the enter/exit() helpers are invoked. */ @@ -197,7 +192,7 @@ static __always_inline void __##func(struct pt_regs *regs, u8 vector); \ __visible noinstr void func(struct pt_regs *regs, \ unsigned long error_code) \ { \ - idtentry_state_t state = idtentry_enter(regs); \ + irqentry_state_t state = irqentry_enter(regs); \ \ instrumentation_begin(); \ irq_enter_rcu(); \ @@ -205,7 +200,7 @@ __visible noinstr void func(struct pt_regs *regs, \ __##func (regs, (u8)error_code); \ irq_exit_rcu(); \ instrumentation_end(); \ - idtentry_exit(regs, state); \ + irqentry_exit(regs, state); \ } \ \ static __always_inline void __##func(struct pt_regs *regs, u8 vector) @@ -229,7 +224,7 @@ static __always_inline void __##func(struct pt_regs *regs, u8 vector) * DEFINE_IDTENTRY_SYSVEC - Emit code for system vector IDT entry points * @func: Function name of the entry point * - * idtentry_enter/exit() and irq_enter/exit_rcu() are invoked before the + * irqentry_enter/exit() and irq_enter/exit_rcu() are invoked before the * function body. KVM L1D flush request is set. * * Runs the function on the interrupt stack if the entry hit kernel mode @@ -239,7 +234,7 @@ static void __##func(struct pt_regs *regs); \ \ __visible noinstr void func(struct pt_regs *regs) \ { \ - idtentry_state_t state = idtentry_enter(regs); \ + irqentry_state_t state = irqentry_enter(regs); \ \ instrumentation_begin(); \ irq_enter_rcu(); \ @@ -247,7 +242,7 @@ __visible noinstr void func(struct pt_regs *regs) \ run_on_irqstack_cond(__##func, regs, regs); \ irq_exit_rcu(); \ instrumentation_end(); \ - idtentry_exit(regs, state); \ + irqentry_exit(regs, state); \ } \ \ static noinline void __##func(struct pt_regs *regs) @@ -268,7 +263,7 @@ static __always_inline void __##func(struct pt_regs *regs); \ \ __visible noinstr void func(struct pt_regs *regs) \ { \ - idtentry_state_t state = idtentry_enter(regs); \ + irqentry_state_t state = irqentry_enter(regs); \ \ instrumentation_begin(); \ __irq_enter_raw(); \ @@ -276,7 +271,7 @@ __visible noinstr void func(struct pt_regs *regs) \ __##func (regs); \ __irq_exit_raw(); \ instrumentation_end(); \ - idtentry_exit(regs, state); \ + irqentry_exit(regs, state); \ } \ \ static __always_inline void __##func(struct pt_regs *regs) -- cgit v1.2.3