From: Po Lu Date: Thu, 4 May 2023 01:12:26 +0000 (+0800) Subject: Update Android port X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=339cdef28e6c78e71b310ade3ffd22333cbb0089;p=emacs.git 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. --- diff --git a/exec/trace.c b/exec/trace.c index 579a62f6c5e..f9dd4d419f4 100644 --- a/exec/trace.c +++ b/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);