From: Dmitry V. Levin Date: Sun, 17 Feb 2019 00:10:26 +0000 (+0000) Subject: hppa: workaround kernel bug in syscall number tampering X-Git-Tag: v5.0~55 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ce494f63d2a4de22a08b5ed807e6195ece8b9632;p=strace hppa: workaround kernel bug in syscall number tampering Linux kernel commit v4.6-rc2~20^2 introduced a regression: when tracer changes syscall number to -1, the kernel fails to initialize %r28 with -ENOSYS and subsequently fails to return the error code of the failed syscall to userspace. Workaround this by initializing %r28 ourselves. * linux/arch_defs_.h (ARCH_NEEDS_SET_ERROR_FOR_SCNO_TAMPERING): Define to 0. * linux/hppa/arch_defs_.h (ARCH_NEEDS_SET_ERROR_FOR_SCNO_TAMPERING): Define to 1. * syscall.c (tamper_with_syscall_entering) [ARCH_NEEDS_SET_ERROR_FOR_SCNO_TAMPERING]: When changing syscall number to -1, set the return value as well. --- diff --git a/linux/arch_defs_.h b/linux/arch_defs_.h index f4b3a7f7..5a7bb4d9 100644 --- a/linux/arch_defs_.h +++ b/linux/arch_defs_.h @@ -42,3 +42,7 @@ #ifndef CAN_ARCH_BE_COMPAT_ON_64BIT_KERNEL # define CAN_ARCH_BE_COMPAT_ON_64BIT_KERNEL 0 #endif + +#ifndef ARCH_NEEDS_SET_ERROR_FOR_SCNO_TAMPERING +# define ARCH_NEEDS_SET_ERROR_FOR_SCNO_TAMPERING 0 +#endif diff --git a/linux/hppa/arch_defs_.h b/linux/hppa/arch_defs_.h index a237049e..db674682 100644 --- a/linux/hppa/arch_defs_.h +++ b/linux/hppa/arch_defs_.h @@ -6,3 +6,11 @@ */ #define HAVE_ARCH_SA_RESTORER 0 +/* + * Linux kernel commit v4.6-rc2~20^2 introduced a regression: + * when tracer changes syscall number to -1, the kernel fails + * to initialize %r28 with -ENOSYS and subsequently fails + * to return the error code of the failed syscall to userspace. + * Workaround this by initializing %r28 ourselves. + */ +#define ARCH_NEEDS_SET_ERROR_FOR_SCNO_TAMPERING 1 diff --git a/syscall.c b/syscall.c index d36b8433..552f0826 100644 --- a/syscall.c +++ b/syscall.c @@ -496,6 +496,20 @@ tamper_with_syscall_entering(struct tcb *tcp, unsigned int *signo) tcp->flags |= TCB_TAMPERED; if (scno != -1) tcp->flags |= TCB_TAMPERED_NO_FAIL; +#if ARCH_NEEDS_SET_ERROR_FOR_SCNO_TAMPERING + /* + * So far it's just a workaround for hppa, + * but let's pretend it could be used elsewhere. + */ + else { + kernel_long_t rval = + (opts->data.flags & INJECT_F_RETVAL) ? + ENOSYS : retval_get(opts->data.rval_idx); + + tcp->u_error = 0; /* force reset */ + set_error(tcp, rval); + } +#endif } } if (opts->data.flags & INJECT_F_DELAY_ENTER)