diff options
| author | Po Lu | 2025-02-09 12:06:52 +0800 |
|---|---|---|
| committer | Po Lu | 2025-02-09 12:06:52 +0800 |
| commit | 563efd6838c1b62c8962385911b5fd5c5637ab96 (patch) | |
| tree | ec0a6294ad51fcdd9b916241959115aade90759a /exec/trace.c | |
| parent | ed9dd4705c7299c12c18d566bd8db4183b1c57f3 (diff) | |
| download | emacs-563efd6838c1b62c8962385911b5fd5c5637ab96.tar.gz emacs-563efd6838c1b62c8962385911b5fd5c5637ab96.zip | |
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.
Diffstat (limited to 'exec/trace.c')
| -rw-r--r-- | exec/trace.c | 58 |
1 files changed, 44 insertions, 14 deletions
diff --git a/exec/trace.c b/exec/trace.c index 1b4297e08ab..ee163327313 100644 --- a/exec/trace.c +++ b/exec/trace.c | |||
| @@ -45,6 +45,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 45 | 45 | ||
| 46 | #ifdef HAVE_SYS_UIO_H | 46 | #ifdef HAVE_SYS_UIO_H |
| 47 | #include <sys/uio.h> /* for process_vm_readv */ | 47 | #include <sys/uio.h> /* for process_vm_readv */ |
| 48 | #ifndef HAVE_PROCESS_VM | ||
| 49 | #include <dlfcn.h> | ||
| 50 | #endif /* !HAVE_PROCESS_VM */ | ||
| 48 | #endif /* HAVE_SYS_UIO_H */ | 51 | #endif /* HAVE_SYS_UIO_H */ |
| 49 | 52 | ||
| 50 | #ifndef SYS_SECCOMP | 53 | #ifndef SYS_SECCOMP |
| @@ -70,6 +73,22 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 70 | /* Number of tracees children are allowed to create. */ | 73 | /* Number of tracees children are allowed to create. */ |
| 71 | #define MAX_TRACEES 4096 | 74 | #define MAX_TRACEES 4096 |
| 72 | 75 | ||
| 76 | #if defined HAVE_SYS_UIO_H && !defined HAVE_PROCESS_VM | ||
| 77 | |||
| 78 | /* Load have_process_vm dynamically if possible to avoid PTRACE_PEEKDATA | ||
| 79 | restrictions on Android 15 QPR2+. */ | ||
| 80 | |||
| 81 | static ssize_t (*process_vm_readv) (pid_t, const struct iovec *, | ||
| 82 | unsigned long, | ||
| 83 | const struct iovec *, | ||
| 84 | unsigned long, unsigned long); | ||
| 85 | static ssize_t (*process_vm_writev) (pid_t, const struct iovec *, | ||
| 86 | unsigned long, | ||
| 87 | const struct iovec *, | ||
| 88 | unsigned long, unsigned long); | ||
| 89 | |||
| 90 | #endif /* HAVE_SYS_UIO_H && !HAVE_PROCESS_VM */ | ||
| 91 | |||
| 73 | #ifdef __aarch64__ | 92 | #ifdef __aarch64__ |
| 74 | 93 | ||
| 75 | /* Place PID's registers into *REGS. Return 1 upon failure, else | 94 | /* Place PID's registers into *REGS. Return 1 upon failure, else |
| @@ -138,7 +157,7 @@ static struct exec_tracee *tracing_processes; | |||
| 138 | ADDRESS. Return its contents in BUFFER. | 157 | ADDRESS. Return its contents in BUFFER. |
| 139 | 158 | ||
| 140 | If there are unreadable pages within ADDRESS + N, the contents of | 159 | If there are unreadable pages within ADDRESS + N, the contents of |
| 141 | BUFFER after the first such page becomes undefined. */ | 160 | BUFFER after the first such page become undefined. */ |
| 142 | 161 | ||
| 143 | static void | 162 | static void |
| 144 | read_memory (struct exec_tracee *tracee, char *buffer, | 163 | read_memory (struct exec_tracee *tracee, char *buffer, |
| @@ -146,7 +165,7 @@ read_memory (struct exec_tracee *tracee, char *buffer, | |||
| 146 | { | 165 | { |
| 147 | USER_WORD word, n_words, n_bytes, i; | 166 | USER_WORD word, n_words, n_bytes, i; |
| 148 | long rc; | 167 | long rc; |
| 149 | #ifdef HAVE_PROCESS_VM | 168 | #ifdef HAVE_SYS_UIO_H |
| 150 | struct iovec iov, remote; | 169 | struct iovec iov, remote; |
| 151 | 170 | ||
| 152 | /* If `process_vm_readv' is available, use it instead. */ | 171 | /* If `process_vm_readv' is available, use it instead. */ |
| @@ -160,11 +179,14 @@ read_memory (struct exec_tracee *tracee, char *buffer, | |||
| 160 | read, consider the read to have been a success. */ | 179 | read, consider the read to have been a success. */ |
| 161 | 180 | ||
| 162 | if (n <= SSIZE_MAX | 181 | if (n <= SSIZE_MAX |
| 163 | && ((size_t) process_vm_readv (tracee->pid, &iov, 1, | 182 | #ifndef HAVE_PROCESS_VM |
| 164 | &remote, 1, 0) != -1)) | 183 | && process_vm_readv |
| 184 | #endif /* !HAVE_PROCESS_VM */ | ||
| 185 | && (process_vm_readv (tracee->pid, &iov, 1, | ||
| 186 | &remote, 1, 0) != -1)) | ||
| 165 | return; | 187 | return; |
| 166 | 188 | ||
| 167 | #endif /* HAVE_PROCESS_VM */ | 189 | #endif /* !HAVE_SYS_UIO_H */ |
| 168 | 190 | ||
| 169 | /* First, read entire words from the tracee. */ | 191 | /* First, read entire words from the tracee. */ |
| 170 | n_words = n & ~(sizeof (USER_WORD) - 1); | 192 | n_words = n & ~(sizeof (USER_WORD) - 1); |
| @@ -283,7 +305,7 @@ user_copy (struct exec_tracee *tracee, const unsigned char *buffer, | |||
| 283 | { | 305 | { |
| 284 | USER_WORD start, end, word; | 306 | USER_WORD start, end, word; |
| 285 | unsigned char *bytes; | 307 | unsigned char *bytes; |
| 286 | #ifdef HAVE_PROCESS_VM | 308 | #ifdef HAVE_SYS_UIO_H |
| 287 | struct iovec iov, remote; | 309 | struct iovec iov, remote; |
| 288 | 310 | ||
| 289 | /* Try to use `process_vm_writev' if possible, but fall back to | 311 | /* 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, | |||
| 295 | remote.iov_len = n; | 317 | remote.iov_len = n; |
| 296 | 318 | ||
| 297 | if (n <= SSIZE_MAX | 319 | if (n <= SSIZE_MAX |
| 298 | && ((size_t) process_vm_writev (tracee->pid, &iov, 1, | 320 | #ifndef HAVE_PROCESS_VM |
| 299 | &remote, 1, 0) == n)) | 321 | && process_vm_writev |
| 322 | #endif /* !HAVE_PROCESS_VM */ | ||
| 323 | && (process_vm_writev (tracee->pid, &iov, 1, | ||
| 324 | &remote, 1, 0) == n)) | ||
| 300 | return 0; | 325 | return 0; |
| 301 | #endif /* HAVE_PROCESS_VM */ | 326 | #endif /* HAVE_SYS_UIO_H */ |
| 302 | 327 | ||
| 303 | /* Calculate the start and end positions for the write. */ | 328 | /* Calculate the start and end positions for the write. */ |
| 304 | 329 | ||
| @@ -1149,10 +1174,7 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs, | |||
| 1149 | return 0; | 1174 | return 0; |
| 1150 | 1175 | ||
| 1151 | /* Now check if the caller is looking for /proc/self/exe or its | 1176 | /* Now check if the caller is looking for /proc/self/exe or its |
| 1152 | equivalent with the PID made explicit. | 1177 | equivalent with the PID made explicit. */ |
| 1153 | |||
| 1154 | dirfd can be ignored, as for now only absolute file names are | ||
| 1155 | handled. FIXME. */ | ||
| 1156 | 1178 | ||
| 1157 | p = stpcpy (proc_pid_exe, "/proc/"); | 1179 | p = stpcpy (proc_pid_exe, "/proc/"); |
| 1158 | p = format_pid (p, tracee->pid); | 1180 | p = format_pid (p, tracee->pid); |
| @@ -1173,7 +1195,7 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs, | |||
| 1173 | 1195 | ||
| 1174 | if (!address | 1196 | if (!address |
| 1175 | || user_copy (tracee, (unsigned char *) tracee->exec_file, | 1197 | || user_copy (tracee, (unsigned char *) tracee->exec_file, |
| 1176 | address, length)) | 1198 | address, length + 1)) |
| 1177 | goto fail; | 1199 | goto fail; |
| 1178 | 1200 | ||
| 1179 | /* Replace the file name buffer with ADDRESS. */ | 1201 | /* Replace the file name buffer with ADDRESS. */ |
| @@ -1699,4 +1721,12 @@ void | |||
| 1699 | exec_init (const char *loader) | 1721 | exec_init (const char *loader) |
| 1700 | { | 1722 | { |
| 1701 | loader_name = loader; | 1723 | loader_name = loader; |
| 1724 | #if defined HAVE_SYS_UIO_H && !defined HAVE_PROCESS_VM | ||
| 1725 | { | ||
| 1726 | *(void **) (&process_vm_readv) | ||
| 1727 | = dlsym (RTLD_DEFAULT, "process_vm_readv"); | ||
| 1728 | *(void **) (&process_vm_writev) | ||
| 1729 | = dlsym (RTLD_DEFAULT, "process_vm_writev"); | ||
| 1730 | } | ||
| 1731 | #endif /* HAVE_SYS_UIO_H && !HAVE_PROCESS_VM */ | ||
| 1702 | } | 1732 | } |