Update Android port
* exec/trace.c (check_signal): New function. (handle_exec, process_system_call): Handle signal-delivery-stop while waiting synchronously for syscall completion.
This commit is contained in:
parent
19210f8b77
commit
339cdef28e
1 changed files with 97 additions and 21 deletions
118
exec/trace.c
118
exec/trace.c
|
@ -451,6 +451,8 @@ handle_clone (pid_t pid)
|
|||
/* File name of the loader binary. */
|
||||
static const char *loader_name;
|
||||
|
||||
|
||||
|
||||
/* Return whether or not the trap signal described by SIGNAL is
|
||||
generated by a system call being attempted by a tracee. */
|
||||
|
||||
|
@ -463,6 +465,79 @@ syscall_trap_p (siginfo_t *signal)
|
|||
|| 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Handle an `exec' system call from the given TRACEE. REGS are the
|
||||
tracee's current user-mode registers.
|
||||
|
||||
|
@ -591,6 +666,15 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
|
|||
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. */
|
||||
|
||||
|
@ -777,9 +861,6 @@ process_system_call (struct exec_tracee *tracee)
|
|||
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;
|
||||
|
||||
|
@ -876,19 +957,7 @@ process_system_call (struct exec_tracee *tracee)
|
|||
/* 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__
|
||||
|
@ -924,6 +993,19 @@ process_system_call (struct exec_tracee *tracee)
|
|||
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. */
|
||||
|
@ -940,9 +1022,6 @@ process_system_call (struct exec_tracee *tracee)
|
|||
|
||||
/* 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);
|
||||
|
@ -966,9 +1045,6 @@ process_system_call (struct exec_tracee *tracee)
|
|||
|
||||
/* 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);
|
||||
|
|
Loading…
Add table
Reference in a new issue