aboutsummaryrefslogtreecommitdiffstats
path: root/exec/trace.c
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/trace.c
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/trace.c')
-rw-r--r--exec/trace.c121
1 files changed, 111 insertions, 10 deletions
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