diff options
Diffstat (limited to 'arch/x86/entry/common.c')
| -rw-r--r-- | arch/x86/entry/common.c | 112 | 
1 files changed, 23 insertions, 89 deletions
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index ec138e538c44..a1e71d431fed 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -40,10 +40,10 @@ static struct thread_info *pt_regs_to_thread_info(struct pt_regs *regs)  #ifdef CONFIG_CONTEXT_TRACKING  /* Called on entry from user mode with IRQs off. */ -__visible void enter_from_user_mode(void) +__visible inline void enter_from_user_mode(void)  {  	CT_WARN_ON(ct_state() != CONTEXT_USER); -	user_exit(); +	user_exit_irqoff();  }  #else  static inline void enter_from_user_mode(void) {} @@ -64,22 +64,16 @@ static void do_audit_syscall_entry(struct pt_regs *regs, u32 arch)  }  /* - * We can return 0 to resume the syscall or anything else to go to phase - * 2.  If we resume the syscall, we need to put something appropriate in - * regs->orig_ax. - * - * NB: We don't have full pt_regs here, but regs->orig_ax and regs->ax - * are fully functional. - * - * For phase 2's benefit, our return value is: - * 0:			resume the syscall - * 1:			go to phase 2; no seccomp phase 2 needed - * anything else:	go to phase 2; pass return value to seccomp + * Returns the syscall nr to run (which should match regs->orig_ax) or -1 + * to skip the syscall.   */ -unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch) +static long syscall_trace_enter(struct pt_regs *regs)  { +	u32 arch = in_ia32_syscall() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; +  	struct thread_info *ti = pt_regs_to_thread_info(regs);  	unsigned long ret = 0; +	bool emulated = false;  	u32 work;  	if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) @@ -87,11 +81,19 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)  	work = ACCESS_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY; +	if (unlikely(work & _TIF_SYSCALL_EMU)) +		emulated = true; + +	if ((emulated || (work & _TIF_SYSCALL_TRACE)) && +	    tracehook_report_syscall_entry(regs)) +		return -1L; + +	if (emulated) +		return -1L; +  #ifdef CONFIG_SECCOMP  	/* -	 * Do seccomp first -- it should minimize exposure of other -	 * code, and keeping seccomp fast is probably more valuable -	 * than the rest of this. +	 * Do seccomp after ptrace, to catch any tracer changes.  	 */  	if (work & _TIF_SECCOMP) {  		struct seccomp_data sd; @@ -118,69 +120,12 @@ unsigned long syscall_trace_enter_phase1(struct pt_regs *regs, u32 arch)  			sd.args[5] = regs->bp;  		} -		BUILD_BUG_ON(SECCOMP_PHASE1_OK != 0); -		BUILD_BUG_ON(SECCOMP_PHASE1_SKIP != 1); - -		ret = seccomp_phase1(&sd); -		if (ret == SECCOMP_PHASE1_SKIP) { -			regs->orig_ax = -1; -			ret = 0; -		} else if (ret != SECCOMP_PHASE1_OK) { -			return ret;  /* Go directly to phase 2 */ -		} - -		work &= ~_TIF_SECCOMP; -	} -#endif - -	/* Do our best to finish without phase 2. */ -	if (work == 0) -		return ret;  /* seccomp and/or nohz only (ret == 0 here) */ - -#ifdef CONFIG_AUDITSYSCALL -	if (work == _TIF_SYSCALL_AUDIT) { -		/* -		 * If there is no more work to be done except auditing, -		 * then audit in phase 1.  Phase 2 always audits, so, if -		 * we audit here, then we can't go on to phase 2. -		 */ -		do_audit_syscall_entry(regs, arch); -		return 0; +		ret = __secure_computing(&sd); +		if (ret == -1) +			return ret;  	}  #endif -	return 1;  /* Something is enabled that we can't handle in phase 1 */ -} - -/* Returns the syscall nr to run (which should match regs->orig_ax). */ -long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch, -				unsigned long phase1_result) -{ -	struct thread_info *ti = pt_regs_to_thread_info(regs); -	long ret = 0; -	u32 work = ACCESS_ONCE(ti->flags) & _TIF_WORK_SYSCALL_ENTRY; - -	if (IS_ENABLED(CONFIG_DEBUG_ENTRY)) -		BUG_ON(regs != task_pt_regs(current)); - -#ifdef CONFIG_SECCOMP -	/* -	 * Call seccomp_phase2 before running the other hooks so that -	 * they can see any changes made by a seccomp tracer. -	 */ -	if (phase1_result > 1 && seccomp_phase2(phase1_result)) { -		/* seccomp failures shouldn't expose any additional code. */ -		return -1; -	} -#endif - -	if (unlikely(work & _TIF_SYSCALL_EMU)) -		ret = -1L; - -	if ((ret || test_thread_flag(TIF_SYSCALL_TRACE)) && -	    tracehook_report_syscall_entry(regs)) -		ret = -1L; -  	if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))  		trace_sys_enter(regs, regs->orig_ax); @@ -189,17 +134,6 @@ long syscall_trace_enter_phase2(struct pt_regs *regs, u32 arch,  	return ret ?: regs->orig_ax;  } -long syscall_trace_enter(struct pt_regs *regs) -{ -	u32 arch = in_ia32_syscall() ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64; -	unsigned long phase1_result = syscall_trace_enter_phase1(regs, arch); - -	if (phase1_result == 0) -		return regs->orig_ax; -	else -		return syscall_trace_enter_phase2(regs, arch, phase1_result); -} -  #define EXIT_TO_USERMODE_LOOP_FLAGS				\  	(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_UPROBE |	\  	 _TIF_NEED_RESCHED | _TIF_USER_RETURN_NOTIFY) @@ -274,7 +208,7 @@ __visible inline void prepare_exit_to_usermode(struct pt_regs *regs)  	ti->status &= ~TS_COMPAT;  #endif -	user_enter(); +	user_enter_irqoff();  }  #define SYSCALL_EXIT_WORK_FLAGS				\  |