1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-07 06:50:23 -08:00

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.
This commit is contained in:
Po Lu 2025-02-09 12:06:52 +08:00
parent ed9dd4705c
commit 563efd6838

View file

@ -45,6 +45,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#ifdef HAVE_SYS_UIO_H #ifdef HAVE_SYS_UIO_H
#include <sys/uio.h> /* for process_vm_readv */ #include <sys/uio.h> /* for process_vm_readv */
#ifndef HAVE_PROCESS_VM
#include <dlfcn.h>
#endif /* !HAVE_PROCESS_VM */
#endif /* HAVE_SYS_UIO_H */ #endif /* HAVE_SYS_UIO_H */
#ifndef SYS_SECCOMP #ifndef SYS_SECCOMP
@ -70,6 +73,22 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
/* Number of tracees children are allowed to create. */ /* Number of tracees children are allowed to create. */
#define MAX_TRACEES 4096 #define MAX_TRACEES 4096
#if defined HAVE_SYS_UIO_H && !defined HAVE_PROCESS_VM
/* Load have_process_vm dynamically if possible to avoid PTRACE_PEEKDATA
restrictions on Android 15 QPR2+. */
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__ #ifdef __aarch64__
/* Place PID's registers into *REGS. Return 1 upon failure, else /* Place PID's registers into *REGS. Return 1 upon failure, else
@ -138,7 +157,7 @@ static struct exec_tracee *tracing_processes;
ADDRESS. Return its contents in BUFFER. ADDRESS. Return its contents in BUFFER.
If there are unreadable pages within ADDRESS + N, the contents of 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 static void
read_memory (struct exec_tracee *tracee, char *buffer, read_memory (struct exec_tracee *tracee, char *buffer,
@ -146,7 +165,7 @@ read_memory (struct exec_tracee *tracee, char *buffer,
{ {
USER_WORD word, n_words, n_bytes, i; USER_WORD word, n_words, n_bytes, i;
long rc; long rc;
#ifdef HAVE_PROCESS_VM #ifdef HAVE_SYS_UIO_H
struct iovec iov, remote; struct iovec iov, remote;
/* If `process_vm_readv' is available, use it instead. */ /* If `process_vm_readv' is available, use it instead. */
@ -160,11 +179,14 @@ read_memory (struct exec_tracee *tracee, char *buffer,
read, consider the read to have been a success. */ read, consider the read to have been a success. */
if (n <= SSIZE_MAX if (n <= SSIZE_MAX
&& ((size_t) process_vm_readv (tracee->pid, &iov, 1, #ifndef HAVE_PROCESS_VM
&remote, 1, 0) != -1)) && process_vm_readv
#endif /* !HAVE_PROCESS_VM */
&& (process_vm_readv (tracee->pid, &iov, 1,
&remote, 1, 0) != -1))
return; return;
#endif /* HAVE_PROCESS_VM */ #endif /* !HAVE_SYS_UIO_H */
/* First, read entire words from the tracee. */ /* First, read entire words from the tracee. */
n_words = n & ~(sizeof (USER_WORD) - 1); n_words = n & ~(sizeof (USER_WORD) - 1);
@ -283,7 +305,7 @@ user_copy (struct exec_tracee *tracee, const unsigned char *buffer,
{ {
USER_WORD start, end, word; USER_WORD start, end, word;
unsigned char *bytes; unsigned char *bytes;
#ifdef HAVE_PROCESS_VM #ifdef HAVE_SYS_UIO_H
struct iovec iov, remote; struct iovec iov, remote;
/* Try to use `process_vm_writev' if possible, but fall back to /* Try to use `process_vm_writev' if possible, but fall back to
@ -295,10 +317,13 @@ user_copy (struct exec_tracee *tracee, const unsigned char *buffer,
remote.iov_len = n; remote.iov_len = n;
if (n <= SSIZE_MAX if (n <= SSIZE_MAX
&& ((size_t) process_vm_writev (tracee->pid, &iov, 1, #ifndef HAVE_PROCESS_VM
&remote, 1, 0) == n)) && process_vm_writev
#endif /* !HAVE_PROCESS_VM */
&& (process_vm_writev (tracee->pid, &iov, 1,
&remote, 1, 0) == n))
return 0; return 0;
#endif /* HAVE_PROCESS_VM */ #endif /* HAVE_SYS_UIO_H */
/* Calculate the start and end positions for the write. */ /* Calculate the start and end positions for the write. */
@ -1149,10 +1174,7 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs,
return 0; return 0;
/* Now check if the caller is looking for /proc/self/exe or its /* Now check if the caller is looking for /proc/self/exe or its
equivalent with the PID made explicit. equivalent with the PID made explicit. */
dirfd can be ignored, as for now only absolute file names are
handled. FIXME. */
p = stpcpy (proc_pid_exe, "/proc/"); p = stpcpy (proc_pid_exe, "/proc/");
p = format_pid (p, tracee->pid); p = format_pid (p, tracee->pid);
@ -1173,7 +1195,7 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs,
if (!address if (!address
|| user_copy (tracee, (unsigned char *) tracee->exec_file, || user_copy (tracee, (unsigned char *) tracee->exec_file,
address, length)) address, length + 1))
goto fail; goto fail;
/* Replace the file name buffer with ADDRESS. */ /* Replace the file name buffer with ADDRESS. */
@ -1699,4 +1721,12 @@ void
exec_init (const char *loader) exec_init (const char *loader)
{ {
loader_name = loader; loader_name = loader;
#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 */
} }