/* File name of the loader binary. */
static const char *loader_name;
+\f
+
/* Return whether or not the trap signal described by SIGNAL is
generated by a system call being attempted by a tracee. */
|| signal->si_code == (SIGTRAP | SI_KERNEL));
}
+/* Check if the wait status STATUS indicates a system call trap.
+ TRACEE is the process whose stop STATUS describes. If TRACEE exits
+ while this information is being determined, return -1; if STATUS
+ indicates some other kind of stop, return 1 after continuing
+ TRACEE. Value is 0 otherwise. */
+
+static int
+check_signal (struct exec_tracee *tracee, int status)
+{
+ siginfo_t siginfo;
+
+ switch ((status & 0xfff00) >> 8)
+ {
+ case SIGTRAP:
+ /* Now, use PTRACE_GETSIGINFO to determine whether or not the
+ signal was delivered in response to a system call. */
+
+ if (ptrace (PTRACE_GETSIGINFO, tracee->pid, 0, &siginfo))
+ return -1;
+
+ if (!syscall_trap_p (&siginfo))
+ {
+ if (siginfo.si_code < 0)
+ /* SIGTRAP delivered from userspace. Pass it on. */
+ ptrace (PTRACE_SYSCALL, tracee->pid, 0, SIGTRAP);
+ else
+ ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0);
+
+ return 1;
+ }
+
+ case SIGTRAP | 0x80: /* SIGTRAP | 0x80 specifically refers to
+ system call traps. */
+ break;
+
+#ifdef SIGSYS
+ case SIGSYS:
+ if (ptrace (PTRACE_GETSIGINFO, tracee->pid, 0, &siginfo))
+ return -1;
+
+ /* Continue the process until the next syscall, but don't
+ pass through the signal if an emulated syscall led to
+ it. */
+#ifdef HAVE_SIGINFO_T_SI_SYSCALL
+#ifndef __arm__
+ ptrace (PTRACE_SYSCALL, tracee->pid,
+ 0, ((siginfo.si_code == SYS_SECCOMP
+ && siginfo.si_syscall == -1)
+ ? 0 : status));
+#else /* __arm__ */
+ ptrace (PTRACE_SYSCALL, tracee->pid,
+ 0, ((siginfo.si_code == SYS_SECCOMP
+ && siginfo.si_syscall == 222)
+ ? 0 : status));
+#endif /* !__arm__ */
+#else /* !HAVE_SIGINFO_T_SI_SYSCALL */
+ /* Drop this signal, since what caused it is unknown. */
+ ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0);
+#endif /* HAVE_SIGINFO_T_SI_SYSCALL */
+ return 1;
+#endif /* SIGSYS */
+
+ default:
+ /* Continue the process until the next syscall. */
+ ptrace (PTRACE_SYSCALL, tracee->pid, 0, status);
+ return 1;
+ }
+
+ return 0;
+}
+
+\f
+
/* Handle an `exec' system call from the given TRACEE. REGS are the
tracee's current user-mode registers.
return 2;
else
{
+ /* Then, check if STATUS is not a syscall-stop, and try again if
+ it isn't. */
+ rc = check_signal (tracee, wstatus);
+
+ if (rc == -1)
+ return 2;
+ else if (rc)
+ goto again;
+
/* Retrieve the signal information and determine whether or not
the system call has completed. */
USER_REGS_STRUCT regs;
int rc, wstatus, save_errno;
USER_WORD callno, sp;
-#ifdef __aarch64__
- USER_WORD old_w1, old_w2;
-#endif /* __aarch64__ */
USER_WORD result;
bool reporting_error;
/* First, save errno; system calls below will clobber it. */
save_errno = errno;
-#ifndef __aarch64__
regs.SYSCALL_NUM_REG = -1;
-#else /* __aarch64__ */
- /* ARM also requires the system call number to be valid. However, I
- can't find any unused system call, so use fcntl instead, with
- invalid arguments. */
- regs.SYSCALL_NUM_REG = 72;
- old_w1 = regs.regs[1];
- old_w2 = regs.regs[2];
- regs.regs[0] = -1;
- regs.regs[1] = -1;
- regs.regs[2] = -1;
-#endif /* !__aarch64__ */
regs.STACK_POINTER = sp;
#ifdef __aarch64__
if (rc == -1)
return;
+ /* If the process received a signal, see if the signal is SIGSYS and
+ from seccomp. If so, discard it. */
+
+ if (WIFSTOPPED (wstatus))
+ {
+ rc = check_signal (tracee, wstatus);
+
+ if (rc == -1)
+ return;
+ else if (rc)
+ goto again1;
+ }
+
if (!WIFSTOPPED (wstatus))
/* The process has been killed in response to a signal. In this
case, simply unlink the tracee and return. */
/* Report errno. */
#ifdef __aarch64__
- /* Restore x1 and x2. x0 is clobbered by errno. */
- regs.regs[1] = old_w1;
- regs.regs[2] = old_w2;
aarch64_set_regs (tracee->pid, ®s, false);
#else /* !__aarch64__ */
ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s);
/* Report errno. */
#ifdef __aarch64__
- /* Restore x1 and x2. x0 is clobbered by errno. */
- regs.regs[1] = old_w1;
- regs.regs[2] = old_w2;
aarch64_set_regs (tracee->pid, ®s, false);
#else /* !__aarch64__ */
ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s);