summaryrefslogtreecommitdiff
path: root/exec
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2023-05-04 09:12:26 +0800
committerPo Lu <luangruo@yahoo.com>2023-05-04 09:12:26 +0800
commit339cdef28e6c78e71b310ade3ffd22333cbb0089 (patch)
tree913505b2a1091ca9e5ecf792f558876c859f5750 /exec
parent19210f8b771947ad10fdaaf27c4f2a177ece3631 (diff)
downloademacs-339cdef28e6c78e71b310ade3ffd22333cbb0089.tar.gz
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.
Diffstat (limited to 'exec')
-rw-r--r--exec/trace.c118
1 files changed, 97 insertions, 21 deletions
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, &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);