[PATCH] ARM: pass syscall return value to sys_exit tracepoint

Mark Rutland mark.rutland at arm.com
Fri Dec 7 05:45:40 EST 2012


On Tue, Dec 04, 2012 at 11:55:26AM +0000, Will Deacon wrote:
> On Tue, Dec 04, 2012 at 10:40:38AM +0000, Will Deacon wrote:
> > On Tue, Dec 04, 2012 at 10:38:09AM +0000, Russell King - ARM Linux wrote:
> > > On Tue, Dec 04, 2012 at 09:48:28AM +0000, Gabbasov, Andrew wrote:
> > > > The other registers in "regs" structure are not saved around ptrace_syscall_trace,
> > > > and both audit_syscall_exit and trace_sys_exit get the register values, potentially
> > > > changed by a debugger. Does it make sense to save the isolated return value
> > > > for trace_sys_exit call only and not to save other registers, passed, for example,
> > > > to audit_syscall_exit function that takes the return value from regs structure?
> > > > Isn't it a reasonable assumption that a debugger will preserve important
> > > > register values (or intentionally change them for some purpose) in case
> > > > of syscall_exit, as we rely on this for syscall_enter case?
> > > 
> > > Actually, why are we doing things in a different order to x86?  If we
> > > assume that x86 has this stuff correctly ordered, then shouldn't we
> > > be following the sequence presented there?
> > > 
> > > x86 on entry does:
> > > - secure_computing
> > > - tracehook_report_syscall_entry
> > > - trace_sys_enter
> > > - audit_syscall_entry
> > > and on exit:
> > > - audit_syscall_exit
> > > - trace_sys_exit
> > > - tracehook_report_syscall_exit
> > > 
> > > We appear to be doing the _exact_ reverse ordering in our syscall exit
> > > path - why is that?
> > 
> > 
> > I've just been looking at that and the problem stems around having ->syscall
> > set for the current thread before calling the sys_exit tracepoint. The audit
> > code should definitely be moved earlier.
> > 
> > Working on a patch...
> 
> Ok, how about something like the following?
> 
> Will
> 
> --->8
> 
> commit 0109b339755b29f92733c1f257911615fc231727
> Author: Will Deacon <will.deacon at arm.com>
> Date:   Tue Dec 4 11:47:14 2012 +0000
> 
>     ARM: syscall: rework ordering in syscall_trace_exit
>     
>     syscall_trace_exit is currently doing things back-to-front; invoking
>     the audit hook *after* signalling the debugger, which presents an
>     opportunity for the registers to be re-written by userspace in order to
>     bypass auditing constaints.
>     
>     This patch fixes the ordering by moving the audit code first and the
>     tracehook code last. On the face of it, it looks like
>     current_thread_info()->syscall may be incorrect for the sys_exit
>     tracepoint, but that's actually not an issue because it will have been
>     set during syscall entry and cannot have changed since then.
>     
>     Reported-by: Andrew Gabbasov <Andrew_Gabbasov at mentor.com>
>     Signed-off-by: Will Deacon <will.deacon at arm.com>

My board locks up upon entering userspace with this applied.

> diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
> index 8355d4b..1dd5122 100644
> --- a/arch/arm/kernel/entry-common.S
> +++ b/arch/arm/kernel/entry-common.S
> @@ -452,7 +452,6 @@ __sys_trace:
>  
>  __sys_trace_return:
>  	str	r0, [sp, #S_R0 + S_OFF]!	@ save returned r0
> -	mov	r1, scno
>  	mov	r0, sp
>  	bl	syscall_trace_exit
>  	b	ret_slow_syscall
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index 518536d..0e9c779 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -957,17 +957,22 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs, int scno)
>  	return scno;
>  }
>  
> -asmlinkage int syscall_trace_exit(struct pt_regs *regs, int scno)
> +asmlinkage void syscall_trace_exit(struct pt_regs *regs)
>  {
> -	current_thread_info()->syscall = scno;
> -
> -	if (test_thread_flag(TIF_SYSCALL_TRACE))
> -		scno = tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);

I see here we used to test TIF_SYSCALL_TRACE...

> +	/*
> +	 * Audit the syscall before anything else, as a debugger may
> +	 * come in and change the current registers.
> +	 */
> +	audit_syscall_exit(regs);
>  
> +	/*
> +	 * 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, scno);
> +		trace_sys_exit(regs, regs_return_value(regs));
>  
> -	audit_syscall_exit(regs);
> -
> -	return scno;
> +	tracehook_report_syscall(regs, PTRACE_SYSCALL_EXIT);

And here we don't. Restoring the test makes boot complete, and audit and
tracing seem to be happy afterwards.

With the test restored,
Tested-by: Mark Rutland <mark.rutland at arm.com>

Thanks,
Mark.




More information about the linux-arm-kernel mailing list