diff options
Diffstat (limited to 'arch/arm/kernel/ptrace.c')
| -rw-r--r-- | arch/arm/kernel/ptrace.c | 43 | 
1 files changed, 30 insertions, 13 deletions
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 739db3a1b2d..03deeffd9f6 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -916,16 +916,11 @@ enum ptrace_syscall_dir {  	PTRACE_SYSCALL_EXIT,  }; -static int ptrace_syscall_trace(struct pt_regs *regs, int scno, -				enum ptrace_syscall_dir dir) +static int tracehook_report_syscall(struct pt_regs *regs, +				    enum ptrace_syscall_dir dir)  {  	unsigned long ip; -	current_thread_info()->syscall = scno; - -	if (!test_thread_flag(TIF_SYSCALL_TRACE)) -		return scno; -  	/*  	 * IP is used to denote syscall entry/exit:  	 * IP = 0 -> entry, =1 -> exit @@ -944,19 +939,41 @@ static int ptrace_syscall_trace(struct pt_regs *regs, int scno,  asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)  { -	scno = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_ENTER); +	current_thread_info()->syscall = scno; + +	/* Do the secure computing check first; failures should be fast. */ +	if (secure_computing(scno) == -1) +		return -1; + +	if (test_thread_flag(TIF_SYSCALL_TRACE)) +		scno = tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER); +  	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))  		trace_sys_enter(regs, scno); +  	audit_syscall_entry(AUDIT_ARCH_ARM, scno, regs->ARM_r0, regs->ARM_r1,  			    regs->ARM_r2, regs->ARM_r3); +  	return scno;  } -asmlinkage int syscall_trace_exit(struct pt_regs *regs, int scno) +asmlinkage void syscall_trace_exit(struct pt_regs *regs)  { -	scno = ptrace_syscall_trace(regs, scno, PTRACE_SYSCALL_EXIT); -	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) -		trace_sys_exit(regs, scno); +	/* +	 * Audit the syscall before anything else, as a debugger may +	 * come in and change the current registers. +	 */  	audit_syscall_exit(regs); -	return scno; + +	/* +	 * Note that we haven't updated the ->syscall field for the +	 * current thread. This isn't a problem because it will have +	 * been set on syscall entry and there hasn't been an opportunity +	 * for a PTRACE_SET_SYSCALL since then. +	 */ +	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) +		trace_sys_exit(regs, regs_return_value(regs)); + +	if (test_thread_flag(TIF_SYSCALL_TRACE)) +		tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);  }  |