]> granicus.if.org Git - strace/commitdiff
mips o32: fix 7th syscall argument with PTRACE_GET_SYSCALL_INFO API
authorDmitry V. Levin <ldv@altlinux.org>
Fri, 15 Feb 2019 21:22:30 +0000 (21:22 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Fri, 15 Feb 2019 21:22:30 +0000 (21:22 +0000)
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
syscall.c

index 522dbae92a0118a4f24d3462d7c6177ce21667fb..48cb103d9b45dbf313ba042fefe80138a0549b25 100644 (file)
@@ -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)
index 1f2fa7a2b2e73656b0913fdfb71ef5958f572bb1..d36b8433a91741e48cfa69627024dbfc3b7c5432 100644 (file)
--- 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;
        }