emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android b9de6e35b79: Fix cwd relative process execution on Andro


From: Po Lu
Subject: feature/android b9de6e35b79: Fix cwd relative process execution on Android
Date: Mon, 1 May 2023 09:23:50 -0400 (EDT)

branch: feature/android
commit b9de6e35b79cbc10909a856df6b1caa770bd4ac4
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix cwd relative process execution on Android
    
    * exec/exec.c (format_pid): New function.
    (exec_0): Make cwd relative file names relative to
    /proc/pid/cwd.
    * exec/trace.c (handle_exec): Handle EINTR.
    (process_system_call): Report failure without clobbering x0.
---
 exec/exec.c  | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 exec/trace.c | 39 +++++++++++++++++++++++++--------------
 2 files changed, 78 insertions(+), 14 deletions(-)

diff --git a/exec/exec.c b/exec/exec.c
index 662c8bf69d2..c7a73f221f5 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -26,6 +26,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <assert.h>
 #include <string.h>
 #include <ctype.h>
+#include <stdlib.h>
 
 #include <sys/ptrace.h>
 #include <sys/param.h>
@@ -808,6 +809,35 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT 
*regs,
 
 
 
+/* Format PID, an unsigned process identifier, in base 10.  Place the
+   result in *IN, and return a pointer to the byte after the
+   result.  REM should be NULL.  */
+
+static char *
+format_pid (char *in, unsigned int pid)
+{
+  unsigned int digits[32], *fill;
+
+  fill = digits;
+
+  for (; pid != 0; pid = pid / 10)
+    *fill++ = pid % 10;
+
+  /* Insert 0 if the number would otherwise be empty.  */
+
+  if (fill == digits)
+    *fill++ = 0;
+
+  while (fill != digits)
+    {
+      --fill;
+      *in++ = '0' + *fill;
+    }
+
+  *in = '\0';
+  return in;
+}
+
 /* Return a sequence of actions required to load the executable under
    the file NAME for the given TRACEE.  First, see if the file starts
    with #!; in that case, find the program to open and use that
@@ -836,6 +866,29 @@ exec_0 (const char *name, struct exec_tracee *tracee,
 #if defined __mips__ && !defined MIPS_NABI
   int fpu_mode;
 #endif /* defined __mips__ && !defined MIPS_NABI */
+  char buffer[PATH_MAX + 80], *rewrite;
+  size_t remaining;
+
+  /* If name is not absolute, then make it relative to TRACEE's
+     cwd.  Use stpcpy, as sprintf is not reentrant.  */
+
+  if (name[0] && name[0] != '/')
+    {
+      /* Clear `buffer'.  */
+      memset (buffer, 0, sizeof buffer);
+
+      /* Copy over /proc, the PID, and /cwd/.  */
+      rewrite = stpcpy (buffer, "/proc/");
+      rewrite = format_pid (rewrite, tracee->pid);
+      rewrite = stpcpy (rewrite, "/cwd/");
+
+      /* Make sure there is enough free space.  */
+      remaining = buffer + sizeof buffer - rewrite - 1;
+      rewrite = stpncpy (rewrite, name, remaining);
+
+      /* Replace name with buffer.  */
+      name = buffer;
+    }
 
   fd = open (name, O_RDONLY);
   if (fd < 0)
diff --git a/exec/trace.c b/exec/trace.c
index df5deacd9bb..d9e8673ba71 100644
--- a/exec/trace.c
+++ b/exec/trace.c
@@ -457,10 +457,17 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT 
*regs)
   memcpy (&original, regs, sizeof *regs);
 
   /* Figure out what the loader needs to do.  */
+ again1:
   area = exec_0 (buffer, tracee, &size, regs);
 
   if (!area)
-    return 1;
+    {
+      /* Handle SIGINTR errors caused by IO.  */
+      if (errno == EINTR)
+       goto again1;
+
+      return 1;
+    }
 
   /* Rewrite the first argument to point to the loader.  */
 
@@ -516,10 +523,7 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT 
*regs)
     goto again;
 
   if (rc < 0)
-    {
-      errno = EIO;
-      return 1;
-    }
+    return 1;
 
   if (!WIFSTOPPED (wstatus))
     /* The process has been killed in response to a signal.
@@ -608,13 +612,14 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT 
*regs)
 
 #endif /* STACK_GROWS_DOWNWARDS */
 
- exec_failure:
-
   /* Continue.  */
   if (ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0))
     return 3;
 
   return 0;
+
+ exec_failure:
+  return 3;
 }
 
 /* Process the system call at which TRACEE is stopped.  If the system
@@ -625,10 +630,10 @@ static void
 process_system_call (struct exec_tracee *tracee)
 {
   USER_REGS_STRUCT regs;
-  int rc, wstatus;
+  int rc, wstatus, save_errno;
   USER_WORD callno, sp;
 #ifdef __aarch64__
-  USER_WORD old_w0, old_w1, old_w2;
+  USER_WORD old_w1, old_w2;
 #endif /* __aarch64__ */
 
 #ifdef __aarch64__
@@ -695,6 +700,9 @@ process_system_call (struct exec_tracee *tracee)
      Make sure that the stack pointer is restored to its original
      position upon exit, or bad things can happen.  */
 
+  /* First, save errno; system calls below will clobber it.  */
+  save_errno = errno;
+
 #ifndef __aarch64__
   regs.SYSCALL_NUM_REG = -1;
 #else /* __aarch64__ */
@@ -702,7 +710,6 @@ process_system_call (struct exec_tracee *tracee)
      can't find any unused system call, so use fcntl instead, with
      invalid arguments.  */
   regs.SYSCALL_NUM_REG = 72;
-  old_w0 = regs.regs[0];
   old_w1 = regs.regs[1];
   old_w2 = regs.regs[2];
   regs.regs[0] = -1;
@@ -739,6 +746,11 @@ process_system_call (struct exec_tracee *tracee)
   if (rc == -1 && errno == EINTR)
     goto again1;
 
+  /* Return if waitpid fails.  */
+
+  if (rc == -1)
+    return;
+
   if (!WIFSTOPPED (wstatus))
     /* The process has been killed in response to a signal.  In this
        case, simply unlink the tracee and return.  */
@@ -747,16 +759,15 @@ process_system_call (struct exec_tracee *tracee)
     {
 #ifdef __mips__
       /* MIPS systems place errno in v0 and set a3 to 1.  */
-      regs.gregs[2] = errno;
+      regs.gregs[2] = save_errno;
       regs.gregs[7] = 1;
 #else /* !__mips__ */
-      regs.SYSCALL_RET_REG = -errno;
+      regs.SYSCALL_RET_REG = -save_errno;
 #endif /* __mips__ */
 
       /* Report errno.  */
 #ifdef __aarch64__
-      /* Restore x0, x1 and x2.  */
-      regs.regs[0] = old_w0;
+      /* 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);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]