aboutsummaryrefslogtreecommitdiffstats
path: root/exec
diff options
context:
space:
mode:
authorPo Lu2024-03-14 13:45:48 +0800
committerPo Lu2024-03-14 13:45:48 +0800
commit30bc867aecc59265b6e315acf459f8d79c423bca (patch)
tree501c2c810e57464d20cf55d7e693d5f2f3ae2ef0 /exec
parentdb5c8bda638468f8798c974f4ef4ab3905dbddd3 (diff)
downloademacs-30bc867aecc59265b6e315acf459f8d79c423bca.tar.gz
emacs-30bc867aecc59265b6e315acf459f8d79c423bca.zip
Improve /proc/self/exe substitution on Android
* exec/configure.ac (USER_SWORD): New macro. * exec/exec.c (format_pid): Export this function. * exec/exec.h: * exec/trace.c (canon_path): New function. (handle_readlinkat, handle_openat): Test complete file name against /proc/self/exe, and further check for /proc/pid/exe.
Diffstat (limited to 'exec')
-rw-r--r--exec/configure.ac8
-rw-r--r--exec/exec.c2
-rw-r--r--exec/exec.h1
-rw-r--r--exec/trace.c121
4 files changed, 121 insertions, 11 deletions
diff --git a/exec/configure.ac b/exec/configure.ac
index 317250332cb..a473a1dc633 100644
--- a/exec/configure.ac
+++ b/exec/configure.ac
@@ -122,6 +122,7 @@ AH_TEMPLATE([SYSCALL_RET_REG], [Define to register holding value of system calls
122AH_TEMPLATE([STACK_POINTER], [Define to register holding the stack pointer.]) 122AH_TEMPLATE([STACK_POINTER], [Define to register holding the stack pointer.])
123AH_TEMPLATE([EXEC_SYSCALL], [Define to number of the `exec' system call.]) 123AH_TEMPLATE([EXEC_SYSCALL], [Define to number of the `exec' system call.])
124AH_TEMPLATE([USER_WORD], [Define to word type used by tracees.]) 124AH_TEMPLATE([USER_WORD], [Define to word type used by tracees.])
125AH_TEMPLATE([USER_SWORD], [Define to signed word type used by tracees.])
125AH_TEMPLATE([EXEC_64], [Define to 1 if the system utilizes 64-bit ELF.]) 126AH_TEMPLATE([EXEC_64], [Define to 1 if the system utilizes 64-bit ELF.])
126AH_TEMPLATE([STACK_GROWS_DOWNWARDS], [Define to 1 if the stack grows downwards.]) 127AH_TEMPLATE([STACK_GROWS_DOWNWARDS], [Define to 1 if the stack grows downwards.])
127AH_TEMPLATE([ABI_RED_ZONE], [Define to number of reserved bytes past the stack frame.]) 128AH_TEMPLATE([ABI_RED_ZONE], [Define to number of reserved bytes past the stack frame.])
@@ -251,6 +252,7 @@ AS_CASE([$host], [x86_64-*linux*],
251 AC_DEFINE([STACK_POINTER], [rsp]) 252 AC_DEFINE([STACK_POINTER], [rsp])
252 AC_DEFINE([EXEC_SYSCALL], [__NR_execve]) 253 AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
253 AC_DEFINE([USER_WORD], [uintptr_t]) 254 AC_DEFINE([USER_WORD], [uintptr_t])
255 AC_DEFINE([USER_SWORD], [intptr_t])
254 AC_DEFINE([EXEC_64], [1]) 256 AC_DEFINE([EXEC_64], [1])
255 AC_DEFINE([ABI_RED_ZONE], [128]) 257 AC_DEFINE([ABI_RED_ZONE], [128])
256 AC_DEFINE([EXECUTABLE_BASE], [0x555555554000]) 258 AC_DEFINE([EXECUTABLE_BASE], [0x555555554000])
@@ -283,6 +285,7 @@ AS_CASE([$host], [x86_64-*linux*],
283 AC_DEFINE([STACK_POINTER], [esp]) 285 AC_DEFINE([STACK_POINTER], [esp])
284 AC_DEFINE([EXEC_SYSCALL], [__NR_execve]) 286 AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
285 AC_DEFINE([USER_WORD], [uintptr_t]) 287 AC_DEFINE([USER_WORD], [uintptr_t])
288 AC_DEFINE([USER_SWORD], [intptr_t])
286 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000]) 289 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
287 AC_DEFINE([INTERPRETER_BASE], [0xaf000000]) 290 AC_DEFINE([INTERPRETER_BASE], [0xaf000000])
288 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1]) 291 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
@@ -313,6 +316,7 @@ AS_CASE([$host], [x86_64-*linux*],
313 AC_DEFINE([STACK_POINTER], [sp]) 316 AC_DEFINE([STACK_POINTER], [sp])
314 AC_DEFINE([EXEC_SYSCALL], [__NR_execve]) 317 AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
315 AC_DEFINE([USER_WORD], [uintptr_t]) 318 AC_DEFINE([USER_WORD], [uintptr_t])
319 AC_DEFINE([USER_SWORD], [intptr_t])
316 AC_DEFINE([EXEC_64], [1]) 320 AC_DEFINE([EXEC_64], [1])
317 AC_DEFINE([EXECUTABLE_BASE], [0x3000000000]) 321 AC_DEFINE([EXECUTABLE_BASE], [0x3000000000])
318 AC_DEFINE([INTERPRETER_BASE], [0x3f00000000]) 322 AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
@@ -344,6 +348,7 @@ AS_CASE([$host], [x86_64-*linux*],
344 AC_DEFINE([STACK_POINTER], [[uregs[13]]]) 348 AC_DEFINE([STACK_POINTER], [[uregs[13]]])
345 AC_DEFINE([EXEC_SYSCALL], [__NR_execve]) 349 AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
346 AC_DEFINE([USER_WORD], [uintptr_t]) 350 AC_DEFINE([USER_WORD], [uintptr_t])
351 AC_DEFINE([USER_SWORD], [intptr_t])
347 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000]) 352 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
348 AC_DEFINE([INTERPRETER_BASE], [0x1f000000]) 353 AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
349 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1]) 354 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
@@ -368,6 +373,7 @@ AS_CASE([$host], [x86_64-*linux*],
368 AC_DEFINE([STACK_POINTER], [[uregs[13]]]) 373 AC_DEFINE([STACK_POINTER], [[uregs[13]]])
369 AC_DEFINE([EXEC_SYSCALL], [__NR_execve]) 374 AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
370 AC_DEFINE([USER_WORD], [uintptr_t]) 375 AC_DEFINE([USER_WORD], [uintptr_t])
376 AC_DEFINE([USER_SWORD], [intptr_t])
371 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000]) 377 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
372 AC_DEFINE([INTERPRETER_BASE], [0x1f000000]) 378 AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
373 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1]) 379 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
@@ -398,6 +404,7 @@ AS_CASE([$host], [x86_64-*linux*],
398 AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp 404 AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
399 AC_DEFINE([EXEC_SYSCALL], [__NR_execve]) 405 AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
400 AC_DEFINE([USER_WORD], [uintptr_t]) 406 AC_DEFINE([USER_WORD], [uintptr_t])
407 AC_DEFINE([USER_SWORD], [intptr_t])
401 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000]) 408 AC_DEFINE([EXECUTABLE_BASE], [0x0f000000])
402 AC_DEFINE([INTERPRETER_BASE], [0x1f000000]) 409 AC_DEFINE([INTERPRETER_BASE], [0x1f000000])
403 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1]) 410 AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
@@ -427,6 +434,7 @@ AS_CASE([$host], [x86_64-*linux*],
427 AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp 434 AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
428 AC_DEFINE([EXEC_SYSCALL], [__NR_execve]) 435 AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
429 AC_DEFINE([USER_WORD], [uintptr_t]) 436 AC_DEFINE([USER_WORD], [uintptr_t])
437 AC_DEFINE([USER_SWORD], [intptr_t])
430 AC_DEFINE([EXEC_64], [1]) 438 AC_DEFINE([EXEC_64], [1])
431 AC_DEFINE([EXECUTABLE_BASE], [0x400000]) 439 AC_DEFINE([EXECUTABLE_BASE], [0x400000])
432 AC_DEFINE([INTERPRETER_BASE], [0x3f00000000]) 440 AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
diff --git a/exec/exec.c b/exec/exec.c
index 254a983f25f..cbe22d4f18c 100644
--- a/exec/exec.c
+++ b/exec/exec.c
@@ -865,7 +865,7 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs,
865 result in *IN, and return a pointer to the byte after the 865 result in *IN, and return a pointer to the byte after the
866 result. REM should be NULL. */ 866 result. REM should be NULL. */
867 867
868static char * 868char *
869format_pid (char *in, unsigned int pid) 869format_pid (char *in, unsigned int pid)
870{ 870{
871 unsigned int digits[32], *fill; 871 unsigned int digits[32], *fill;
diff --git a/exec/exec.h b/exec/exec.h
index ad1b50276c8..3ce06c35311 100644
--- a/exec/exec.h
+++ b/exec/exec.h
@@ -180,6 +180,7 @@ extern int aarch64_set_regs (pid_t, USER_REGS_STRUCT *, bool);
180 180
181 181
182 182
183extern char *format_pid (char *, unsigned int);
183extern USER_WORD user_alloca (struct exec_tracee *, USER_REGS_STRUCT *, 184extern USER_WORD user_alloca (struct exec_tracee *, USER_REGS_STRUCT *,
184 USER_REGS_STRUCT *, USER_WORD); 185 USER_REGS_STRUCT *, USER_WORD);
185extern int user_copy (struct exec_tracee *, const unsigned char *, 186extern int user_copy (struct exec_tracee *, const unsigned char *,
diff --git a/exec/trace.c b/exec/trace.c
index a7cbda54d68..64dadc092c2 100644
--- a/exec/trace.c
+++ b/exec/trace.c
@@ -31,6 +31,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
31#include <unistd.h> 31#include <unistd.h>
32#include <stdlib.h> 32#include <stdlib.h>
33#include <errno.h> 33#include <errno.h>
34#include <fcntl.h>
34 35
35#include "exec.h" 36#include "exec.h"
36 37
@@ -894,6 +895,68 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
894 return 3; 895 return 3;
895} 896}
896 897
898/* Modify BUFFER, of size SIZE, so that it holds the absolute name of
899 the file identified by BUFFER, relative to the current working
900 directory of TRACEE if FD be AT_FDCWD, or the file referenced by FD
901 otherwise.
902
903 Value is 1 if this information is unavailable (of which there are
904 variety of causes), and 0 on success. */
905
906static int
907canon_path (struct exec_tracee *tracee, int fd, char *buffer,
908 ptrdiff_t size)
909{
910 char link[sizeof "/proc//fd/" + 48], *p; /* Or /proc/pid/cwd. */
911 char target[PATH_MAX];
912 ssize_t rc, length;
913
914 if (buffer[0] == '/')
915 /* Absolute file name; return immediately. */
916 return 0;
917 else if (fd == AT_FDCWD)
918 {
919 p = stpcpy (link, "/proc/");
920 p = format_pid (p, tracee->pid);
921 stpcpy (p, "/cwd");
922 }
923 else if (fd < 0)
924 /* Invalid file descriptor. */
925 return 1;
926 else
927 {
928 p = stpcpy (link, "/proc/");
929 p = format_pid (p, tracee->pid);
930 p = stpcpy (p, "/fd/");
931 format_pid (p, fd);
932 }
933
934 /* Read LINK's target, and should it be oversized, punt. */
935 rc = readlink (link, target, PATH_MAX);
936 if (rc < 0 || rc >= PATH_MAX)
937 return 1;
938
939 /* Consider the amount by which BUFFER's existing contents should be
940 displaced. */
941
942 length = strlen (buffer) + 1;
943 if ((length + rc + (target[rc - 1] != '/')) > size)
944 /* Punt if this would overflow. */
945 return 1;
946
947 memmove ((buffer + rc + (target[rc - 1] != '/')),
948 buffer, length);
949
950 /* Copy the new file name into BUFFER. */
951 memcpy (buffer, target, rc);
952
953 /* Insert separator in between if need be. */
954 if (target[rc - 1] != '/')
955 buffer[rc] = '/';
956
957 return 0;
958}
959
897/* Handle a `readlink' or `readlinkat' system call. 960/* Handle a `readlink' or `readlinkat' system call.
898 961
899 CALLNO is the system call number, and REGS are the current user 962 CALLNO is the system call number, and REGS are the current user
@@ -924,22 +987,26 @@ handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs,
924 char buffer[PATH_MAX + 1]; 987 char buffer[PATH_MAX + 1];
925 USER_WORD address, return_buffer, size; 988 USER_WORD address, return_buffer, size;
926 size_t length; 989 size_t length;
990 char proc_pid_exe[sizeof "/proc//exe" + 24], *p;
991 int dirfd;
927 992
928 /* Read the file name. */ 993 /* Read the file name. */
929 994
930#ifdef READLINK_SYSCALL 995#ifdef READLINK_SYSCALL
931 if (callno == READLINK_SYSCALL) 996 if (callno == READLINK_SYSCALL)
932 { 997 {
933 address = regs->SYSCALL_ARG_REG; 998 dirfd = AT_FDCWD;
999 address = regs->SYSCALL_ARG_REG;
934 return_buffer = regs->SYSCALL_ARG1_REG; 1000 return_buffer = regs->SYSCALL_ARG1_REG;
935 size = regs->SYSCALL_ARG2_REG; 1001 size = regs->SYSCALL_ARG2_REG;
936 } 1002 }
937 else 1003 else
938#endif /* READLINK_SYSCALL */ 1004#endif /* READLINK_SYSCALL */
939 { 1005 {
940 address = regs->SYSCALL_ARG1_REG; 1006 dirfd = (USER_SWORD) regs->SYSCALL_ARG_REG;
1007 address = regs->SYSCALL_ARG1_REG;
941 return_buffer = regs->SYSCALL_ARG2_REG; 1008 return_buffer = regs->SYSCALL_ARG2_REG;
942 size = regs->SYSCALL_ARG3_REG; 1009 size = regs->SYSCALL_ARG3_REG;
943 } 1010 }
944 1011
945 read_memory (tracee, buffer, PATH_MAX, address); 1012 read_memory (tracee, buffer, PATH_MAX, address);
@@ -952,12 +1019,25 @@ handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs,
952 return 1; 1019 return 1;
953 } 1020 }
954 1021
955 /* Now check if the caller is looking for /proc/self/exe. 1022 /* Expand BUFFER into an absolute file name. TODO:
1023 AT_SYMLINK_FOLLOW? */
1024
1025 if (canon_path (tracee, dirfd, buffer, sizeof buffer))
1026 return 0;
1027
1028 /* Now check if the caller is looking for /proc/self/exe or its
1029 equivalent with the PID made explicit.
956 1030
957 dirfd can be ignored, as for now only absolute file names are 1031 dirfd can be ignored, as for now only absolute file names are
958 handled. FIXME. */ 1032 handled. FIXME. */
959 1033
960 if (strcmp (buffer, "/proc/self/exe") || !tracee->exec_file) 1034 p = stpcpy (proc_pid_exe, "/proc/");
1035 p = format_pid (p, tracee->pid);
1036 stpcpy (p, "/exe");
1037
1038 if ((strcmp (buffer, "/proc/self/exe")
1039 && strcmp (buffer, proc_pid_exe))
1040 || !tracee->exec_file)
961 return 0; 1041 return 0;
962 1042
963 /* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or 1043 /* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or
@@ -1004,15 +1084,23 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs,
1004 USER_WORD address; 1084 USER_WORD address;
1005 size_t length; 1085 size_t length;
1006 USER_REGS_STRUCT original; 1086 USER_REGS_STRUCT original;
1087 char proc_pid_exe[sizeof "/proc//exe" + 24], *p;
1088 int dirfd;
1007 1089
1008 /* Read the file name. */ 1090 /* Read the file name. */
1009 1091
1010#ifdef OPEN_SYSCALL 1092#ifdef OPEN_SYSCALL
1011 if (callno == OPEN_SYSCALL) 1093 if (callno == OPEN_SYSCALL)
1012 address = regs->SYSCALL_ARG_REG; 1094 {
1095 dirfd = AT_FDCWD;
1096 address = regs->SYSCALL_ARG_REG;
1097 }
1013 else 1098 else
1014#endif /* OPEN_SYSCALL */ 1099#endif /* OPEN_SYSCALL */
1015 address = regs->SYSCALL_ARG1_REG; 1100 {
1101 dirfd = (USER_SWORD) regs->SYSCALL_ARG_REG;
1102 address = regs->SYSCALL_ARG1_REG;
1103 }
1016 1104
1017 /* Read the file name into the buffer and verify that it is NULL 1105 /* Read the file name into the buffer and verify that it is NULL
1018 terminated. */ 1106 terminated. */
@@ -1024,12 +1112,25 @@ handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs,
1024 return 1; 1112 return 1;
1025 } 1113 }
1026 1114
1027 /* Now check if the caller is looking for /proc/self/exe. 1115 /* Expand BUFFER into an absolute file name. TODO:
1116 AT_SYMLINK_FOLLOW? */
1117
1118 if (canon_path (tracee, dirfd, buffer, sizeof buffer))
1119 return 0;
1120
1121 /* Now check if the caller is looking for /proc/self/exe or its
1122 equivalent with the PID made explicit.
1028 1123
1029 dirfd can be ignored, as for now only absolute file names are 1124 dirfd can be ignored, as for now only absolute file names are
1030 handled. FIXME. */ 1125 handled. FIXME. */
1031 1126
1032 if (strcmp (buffer, "/proc/self/exe") || !tracee->exec_file) 1127 p = stpcpy (proc_pid_exe, "/proc/");
1128 p = format_pid (p, tracee->pid);
1129 stpcpy (p, "/exe");
1130
1131 if ((strcmp (buffer, "/proc/self/exe")
1132 && strcmp (buffer, proc_pid_exe))
1133 || !tracee->exec_file)
1033 return 0; 1134 return 0;
1034 1135
1035 /* Copy over tracee->exec_file. This doesn't correctly handle the 1136 /* Copy over tracee->exec_file. This doesn't correctly handle the