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

From: Mark Rutland
Date: Wed May 05 2021 - 13:32:36 EST


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@xxxxxxx>
> Signed-off-by: He Zhe <zhe.he@xxxxxxxxxxxxx>
> ---
> 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.