From 783cd9e6b80f42c9797bb026cd1893486642cb20 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 9 Feb 2025 12:06:52 +0800 Subject: [PATCH] Fix program execution on Android 15 QPR2 Beta * 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 | 87 +++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/exec/trace.c b/exec/trace.c index e222f0fc21a..cfc2d145cd1 100644 --- a/exec/trace.c +++ b/exec/trace.c @@ -45,6 +45,9 @@ along with GNU Emacs. If not, see . */ #ifdef HAVE_SYS_UIO_H #include /* for process_vm_readv */ +#ifndef HAVE_PROCESS_VM +#include +#endif /* !HAVE_PROCESS_VM */ #endif /* HAVE_SYS_UIO_H */ #ifndef SYS_SECCOMP @@ -80,14 +83,21 @@ along with GNU Emacs. If not, see . */ /* 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 */ } -- 2.39.5