From 7a6dbfedfd7ee12b7159f87d0e5294d0b2cfc275 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Fri, 15 Feb 2019 21:22:30 +0000 Subject: [PATCH] mips o32: fix 7th syscall argument with PTRACE_GET_SYSCALL_INFO API As PTRACE_GET_SYSCALL_INFO API supports 6 syscall arguments, all architectures that have syscalls with more than 6 arguments (i.e. mips o32) have to fetch extra arguments manually when using PTRACE_GET_SYSCALL_INFO API. * linux/mips/get_syscall_args.c [LINUX_MIPSO32] (arch_get_syscall_args_extra): New function. * syscall.c (get_syscall_args) [MAX_ARGS > 6]: Use it. Fixes: v4.26~49 "Introduce PTRACE_GET_SYSCALL_INFO support" --- linux/mips/get_syscall_args.c | 19 +++++++++++++++++++ syscall.c | 17 +++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/linux/mips/get_syscall_args.c b/linux/mips/get_syscall_args.c index 522dbae9..48cb103d 100644 --- a/linux/mips/get_syscall_args.c +++ b/linux/mips/get_syscall_args.c @@ -38,6 +38,25 @@ arch_get_syscall_args(struct tcb *tcp) return 1; } +#ifdef LINUX_MIPSO32 +static void +arch_get_syscall_args_extra(struct tcb *tcp, const unsigned int n) +{ + /* This assumes n >= 4. */ + if (n_args(tcp) > n + && umoven(tcp, mips_REG_SP + n * sizeof(tcp->u_arg[0]), + (n_args(tcp) - n) * sizeof(tcp->u_arg[0]), + &tcp->u_arg[n]) < 0) { + /* + * Let's proceed with the first n arguments + * instead of reporting the failure. + */ + memset(&tcp->u_arg[n], 0, + (n_args(tcp) - n) * sizeof(tcp->u_arg[0])); + } +} +#endif + #ifdef SYS_syscall_subcall static void decode_syscall_subcall(struct tcb *tcp) diff --git a/syscall.c b/syscall.c index 1f2fa7a2..d36b8433 100644 --- a/syscall.c +++ b/syscall.c @@ -446,6 +446,9 @@ static int arch_get_syscall_args(struct tcb *); static void arch_get_error(struct tcb *, bool); static int arch_set_error(struct tcb *); static int arch_set_success(struct tcb *); +#if MAX_ARGS > 6 +static void arch_get_syscall_args_extra(struct tcb *, unsigned int); +#endif struct inject_opts *inject_vec[SUPPORTED_PERSONALITIES]; @@ -1313,13 +1316,23 @@ static int get_syscall_args(struct tcb *tcp) { if (ptrace_syscall_info_is_valid()) { - for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i) + const unsigned int n = + MIN(ARRAY_SIZE(tcp->u_arg), + ARRAY_SIZE(ptrace_sci.entry.args)); + for (unsigned int i = 0; i < n; ++i) tcp->u_arg[i] = ptrace_sci.entry.args[i]; #if SUPPORTED_PERSONALITIES > 1 if (tcp_sysent(tcp)->sys_flags & COMPAT_SYSCALL_TYPES) { - for (unsigned int i = 0; i < ARRAY_SIZE(tcp->u_arg); ++i) + for (unsigned int i = 0; i < n; ++i) tcp->u_arg[i] = (uint32_t) tcp->u_arg[i]; } +#endif + /* + * So far it's just a workaround for mips o32, + * but let's pretend it could be used elsewhere. + */ +#if MAX_ARGS > 6 + arch_get_syscall_args_extra(tcp, n); #endif return 1; } -- 2.40.0