]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix program execution on Android 15 QPR2 Beta
authorPo Lu <luangruo@yahoo.com>
Sun, 9 Feb 2025 04:06:52 +0000 (12:06 +0800)
committerEshel Yaron <me@eshelyaron.com>
Sun, 9 Feb 2025 08:47:47 +0000 (09:47 +0100)
* exec/trace.c (process_vm_readv, process_vm_writev): New
function pointers.  Attempt to load them on recent Android
systems when `exec' was not linked with a sufficiently
up-to-date libc.
(read_memory, user_copy): Always use process_vm_readv and
process_vm_writev if available.
(handle_openat): Write trailing NULL byte of filename to user
buffer.
(exec_init): Attempt to dlsym process_vm_readv and
process_vm_writev.

(cherry picked from commit 563efd6838c1b62c8962385911b5fd5c5637ab96)

exec/trace.c

index e222f0fc21a790f94a0cb1457829de3fa25de65d..cfc2d145cd1c0ec08740d4a21f80dd9de8821193 100644 (file)
@@ -45,6 +45,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_SYS_UIO_H
 #include <sys/uio.h> /* for process_vm_readv */
+#ifndef HAVE_PROCESS_VM
+#include <dlfcn.h>
+#endif /* !HAVE_PROCESS_VM */
 #endif /* HAVE_SYS_UIO_H */
 
 #ifndef SYS_SECCOMP
@@ -80,14 +83,21 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 /* Number of tracees children are allowed to create.  */
 #define MAX_TRACEES 4096
 
-#ifdef HAVE_SECCOMP
+#if defined HAVE_SYS_UIO_H && !defined HAVE_PROCESS_VM
 
-/* Whether to enable seccomp acceleration.  */
-static bool use_seccomp_p;
+/* Load have_process_vm dynamically if possible to avoid PTRACE_PEEKDATA
+   restrictions on Android 15 QPR2+.  */
 
-#else /* !HAVE_SECCOMP */
-#define use_seccomp_p (false)
-#endif /* HAVE_SECCOMP */
+static ssize_t (*process_vm_readv) (pid_t, const struct iovec *,
+                                   unsigned long,
+                                   const struct iovec *,
+                                   unsigned long, unsigned long);
+static ssize_t (*process_vm_writev) (pid_t, const struct iovec *,
+                                    unsigned long,
+                                    const struct iovec *,
+                                    unsigned long, unsigned long);
+
+#endif /* HAVE_SYS_UIO_H && !HAVE_PROCESS_VM */
 
 #ifdef __aarch64__
 
@@ -156,7 +166,7 @@ static struct exec_tracee *tracing_processes;
    ADDRESS.  Return its contents in BUFFER.
 
    If there are unreadable pages within ADDRESS + N, the contents of
-   BUFFER after the first such page becomes undefined.  */
+   BUFFER after the first such page become undefined.  */
 
 static void
 read_memory (struct exec_tracee *tracee, char *buffer,
@@ -164,7 +174,7 @@ read_memory (struct exec_tracee *tracee, char *buffer,
 {
   USER_WORD word, n_words, n_bytes, i;
   long rc;
-#ifdef HAVE_PROCESS_VM
+#ifdef HAVE_SYS_UIO_H
   struct iovec iov, remote;
 
   /* If `process_vm_readv' is available, use it instead.  */
@@ -178,11 +188,14 @@ read_memory (struct exec_tracee *tracee, char *buffer,
      read, consider the read to have been a success.  */
 
   if (n <= SSIZE_MAX
-      && ((size_t) process_vm_readv (tracee->pid, &iov, 1,
-                                    &remote, 1, 0) != -1))
+#ifndef HAVE_PROCESS_VM
+      && process_vm_readv
+#endif /* !HAVE_PROCESS_VM */
+      && (process_vm_readv (tracee->pid, &iov, 1,
+                           &remote, 1, 0) != -1))
     return;
 
-#endif /* HAVE_PROCESS_VM */
+#endif /* !HAVE_SYS_UIO_H */
 
   /* First, read entire words from the tracee.  */
   n_words = n & ~(sizeof (USER_WORD) - 1);
@@ -301,7 +314,7 @@ user_copy (struct exec_tracee *tracee, const unsigned char *buffer,
 {
   USER_WORD start, end, word;
   unsigned char *bytes;
-#ifdef HAVE_PROCESS_VM
+#ifdef HAVE_SYS_UIO_H
   struct iovec iov, remote;
 
   /* Try to use `process_vm_writev' if possible, but fall back to
@@ -313,10 +326,13 @@ user_copy (struct exec_tracee *tracee, const unsigned char *buffer,
   remote.iov_len = n;
 
   if (n <= SSIZE_MAX
-      && ((size_t) process_vm_writev (tracee->pid, &iov, 1,
-                                     &remote, 1, 0) == n))
+#ifndef HAVE_PROCESS_VM
+      && process_vm_writev
+#endif /* !HAVE_PROCESS_VM */
+      && (process_vm_writev (tracee->pid, &iov, 1,
+                            &remote, 1, 0) == n))
     return 0;
-#endif /* HAVE_PROCESS_VM */
+#endif /* HAVE_SYS_UIO_H */
 
   /* Calculate the start and end positions for the write.  */
 
@@ -1129,10 +1145,7 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs,
     return 0;
 
   /* Now check if the caller is looking for /proc/self/exe or its
-     equivalent with the PID made explicit.
-
-     dirfd can be ignored, as for now only absolute file names are
-     handled.  FIXME.  */
+     equivalent with the PID made explicit.  */
 
   p = stpcpy (proc_pid_exe, "/proc/");
   p = format_pid (p, tracee->pid);
@@ -1153,7 +1166,7 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs,
 
   if (!address
       || user_copy (tracee, (unsigned char *) tracee->exec_file,
-                   address, length))
+                   address, length + 1))
     goto fail;
 
   /* Replace the file name buffer with ADDRESS.  */
@@ -2177,30 +2190,12 @@ exec_init (const char *loader)
 #endif /* HAVE_SECCOMP */
 
   loader_name = loader;
-#ifdef HAVE_SECCOMP
-  errno = 0;
-  prctl (PR_GET_SECCOMP);
-
-  /* PR_GET_SECCOMP should not set errno if the kernel was configured
-     with support for seccomp.  */
-  if (!errno)
-    use_seccomp_p = true;
-  else
-    return;
-
-  /* Establish whether the kernel is 4.7.x or older.  */
-  uname (&u);
-  if ((sscanf (u.release, "%d.%d", &major, &minor) == 2))
-    {
-      /* Certain required ptrace features were introduced in kernel
-        3.5.  */
-      if (major < 3 || (major == 3 && minor < 5))
-       use_seccomp_p = false;
-      else
-       {
-         if (major < 4 || (major == 4 && minor <= 7))
-           kernel_4_7_or_earlier = true;
-       }
-    }
-#endif /* HAVE_SECCOMP */
+#if defined HAVE_SYS_UIO_H && !defined HAVE_PROCESS_VM
+  {
+    *(void **) (&process_vm_readv)
+      = dlsym (RTLD_DEFAULT, "process_vm_readv");
+    *(void **) (&process_vm_writev)
+      = dlsym (RTLD_DEFAULT, "process_vm_writev");
+  }
+#endif /* HAVE_SYS_UIO_H && !HAVE_PROCESS_VM */
 }