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:
Po Lu 2023-05-04 09:12:26 +08:00
parent 19210f8b77
commit 339cdef28e

View file

@ -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, &regs, false);
#else /* !__aarch64__ */
ptrace (PTRACE_SETREGS, tracee->pid, NULL, &regs);
@ -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, &regs, false);
#else /* !__aarch64__ */
ptrace (PTRACE_SETREGS, tracee->pid, NULL, &regs);