[PATCH v2 2/3] arm64: syscall.h: Add sign extension handling in syscall_get_return_value for compat

Mark Rutland mark.rutland at arm.com
Wed May 5 10:30:14 PDT 2021


Hi,

On Fri, Apr 23, 2021 at 06:35:32PM +0800, He Zhe wrote:
> Add sign extension handling in syscall_get_return_value so that it can
> handle 32-bit compatible case and can be used by for example audit, just
> like what syscall_get_error does.
> 
> Suggested-by: Mark Rutland <mark.rutland at arm.com>
> Signed-off-by: He Zhe <zhe.he at windriver.com>
> ---
> v1 to v2: Improve error code check suggested by Mark
> 
>  arch/arm64/include/asm/syscall.h | 15 ++++++++++++++-
>  1 file changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
> index cfc0672013f6..c3b5fca82ff4 100644
> --- a/arch/arm64/include/asm/syscall.h
> +++ b/arch/arm64/include/asm/syscall.h
> @@ -44,7 +44,20 @@ static inline long syscall_get_error(struct task_struct *task,
>  static inline long syscall_get_return_value(struct task_struct *task,
>  					    struct pt_regs *regs)
>  {
> -	return regs->regs[0];
> +	long val = regs->regs[0];
> +	long error = val;
> +
> +	if (compat_user_mode(regs))
> +		error = sign_extend64(error, 31);
> +
> +	/*
> +	 * Return codes with bit 31 set may or may not be an error code.
> +	 * For example, mmap may return a legal 32 bit address with bit 31 set
> +	 * for 32 bit thread, in which case the untouched val should be
> +	 * returned. Otherwise, the sign-extended error should be returned if
> +	 * it still falls in error number range.
> +	 */
> +	return IS_ERR_VALUE(error) ? error : val;

I'm afraid I have misled you here.

I wrote up a test that uses PTRACE_GET_SYSCALL_INFO, and I found that on
a 32-bit arm (v5.12) kernel, *all* syscall return values get
sign-extended after all. For example, if (on a 32-bit kernel) I use
MAP_FIXED to mmap() at address 0x8bad0000, the return value reported in
ptrace_syscall_info::exit::rval is 0xffffffff8bad0000.

So for that we shoudn't have the IS_ERR_VALUE() check after all, but I'm
not currently sure whether there are other cases where 32-bit arm
wouldn't sign-extend, and I think we'll need to dig into this some more.

Thanks,
Mark.



More information about the linux-arm-kernel mailing list