diff options
| author | Po Lu | 2024-01-27 10:36:30 +0800 |
|---|---|---|
| committer | Po Lu | 2024-01-27 10:36:30 +0800 |
| commit | c37b50ad417c6cb340f54ffe218f5d889345451a (patch) | |
| tree | fc6b825b4e3489621d0d7738eb739fa74e56d059 /exec/trace.c | |
| parent | 55f0b3e561034a1ad4235770d1c0685439a64fe5 (diff) | |
| download | emacs-c37b50ad417c6cb340f54ffe218f5d889345451a.tar.gz emacs-c37b50ad417c6cb340f54ffe218f5d889345451a.zip | |
Intercept calls to `openat' under Android
* exec/configure.ac (OPEN_SYSCALL, OPENAT_SYSCALL): Define new
macros.
* exec/exec.h (struct exec_tracee): New field `sp'.
* exec/trace.c (handle_openat): New function.
(process_system_call): If handle_openat executes successfully,
save the unmodified stack pointer within the tracee structure to
be restored once the system call completes.
Diffstat (limited to 'exec/trace.c')
| -rw-r--r-- | exec/trace.c | 135 |
1 files changed, 134 insertions, 1 deletions
diff --git a/exec/trace.c b/exec/trace.c index 8e190c94f79..a7cbda54d68 100644 --- a/exec/trace.c +++ b/exec/trace.c | |||
| @@ -961,7 +961,7 @@ handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs, | |||
| 961 | return 0; | 961 | return 0; |
| 962 | 962 | ||
| 963 | /* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or | 963 | /* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or |
| 964 | size, whichever is less. */ | 964 | size, whichever is smaller. */ |
| 965 | 965 | ||
| 966 | length = strlen (tracee->exec_file); | 966 | length = strlen (tracee->exec_file); |
| 967 | length = MIN (size, MIN (PATH_MAX, length)); | 967 | length = MIN (size, MIN (PATH_MAX, length)); |
| @@ -979,6 +979,98 @@ handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs, | |||
| 979 | #endif /* REENTRANT */ | 979 | #endif /* REENTRANT */ |
| 980 | } | 980 | } |
| 981 | 981 | ||
| 982 | /* Handle an `open' or `openat' system call. | ||
| 983 | |||
| 984 | CALLNO is the system call number, and REGS are the current user | ||
| 985 | registers of the TRACEE. | ||
| 986 | |||
| 987 | If the file name specified in such system call is `/proc/self/exe', | ||
| 988 | replace the file name with the executable loaded into the process | ||
| 989 | issuing this system call. | ||
| 990 | |||
| 991 | Value is 0 upon success and 1 upon failure. */ | ||
| 992 | |||
| 993 | static int | ||
| 994 | handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs, | ||
| 995 | struct exec_tracee *tracee, USER_WORD *result) | ||
| 996 | { | ||
| 997 | #ifdef REENTRANT | ||
| 998 | /* readlinkat cannot be handled specially when the library is built | ||
| 999 | to be reentrant, as the file name information cannot be | ||
| 1000 | recorded. */ | ||
| 1001 | return 0; | ||
| 1002 | #else /* !REENTRANT */ | ||
| 1003 | char buffer[PATH_MAX + 1]; | ||
| 1004 | USER_WORD address; | ||
| 1005 | size_t length; | ||
| 1006 | USER_REGS_STRUCT original; | ||
| 1007 | |||
| 1008 | /* Read the file name. */ | ||
| 1009 | |||
| 1010 | #ifdef OPEN_SYSCALL | ||
| 1011 | if (callno == OPEN_SYSCALL) | ||
| 1012 | address = regs->SYSCALL_ARG_REG; | ||
| 1013 | else | ||
| 1014 | #endif /* OPEN_SYSCALL */ | ||
| 1015 | address = regs->SYSCALL_ARG1_REG; | ||
| 1016 | |||
| 1017 | /* Read the file name into the buffer and verify that it is NULL | ||
| 1018 | terminated. */ | ||
| 1019 | read_memory (tracee, buffer, PATH_MAX, address); | ||
| 1020 | |||
| 1021 | if (!memchr (buffer, '\0', PATH_MAX)) | ||
| 1022 | { | ||
| 1023 | errno = ENAMETOOLONG; | ||
| 1024 | return 1; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | /* Now check if the caller is looking for /proc/self/exe. | ||
| 1028 | |||
| 1029 | dirfd can be ignored, as for now only absolute file names are | ||
| 1030 | handled. FIXME. */ | ||
| 1031 | |||
| 1032 | if (strcmp (buffer, "/proc/self/exe") || !tracee->exec_file) | ||
| 1033 | return 0; | ||
| 1034 | |||
| 1035 | /* Copy over tracee->exec_file. This doesn't correctly handle the | ||
| 1036 | scenario where tracee->exec_file is longer than PATH_MAX, but | ||
| 1037 | that has yet to be encountered in practice. */ | ||
| 1038 | |||
| 1039 | original = *regs; | ||
| 1040 | length = strlen (tracee->exec_file); | ||
| 1041 | address = user_alloca (tracee, &original, regs, length + 1); | ||
| 1042 | |||
| 1043 | if (!address | ||
| 1044 | || user_copy (tracee, (unsigned char *) tracee->exec_file, | ||
| 1045 | address, length)) | ||
| 1046 | goto fail; | ||
| 1047 | |||
| 1048 | /* Replace the file name buffer with ADDRESS. */ | ||
| 1049 | |||
| 1050 | #ifdef OPEN_SYSCALL | ||
| 1051 | if (callno == OPEN_SYSCALL) | ||
| 1052 | regs->SYSCALL_ARG_REG = address; | ||
| 1053 | else | ||
| 1054 | #endif /* OPEN_SYSCALL */ | ||
| 1055 | regs->SYSCALL_ARG1_REG = address; | ||
| 1056 | |||
| 1057 | #ifdef __aarch64__ | ||
| 1058 | if (aarch64_set_regs (tracee->pid, regs, false)) | ||
| 1059 | goto fail; | ||
| 1060 | #else /* !__aarch64__ */ | ||
| 1061 | if (ptrace (PTRACE_SETREGS, tracee->pid, NULL, regs)) | ||
| 1062 | goto fail; | ||
| 1063 | #endif /* __aarch64__ */ | ||
| 1064 | |||
| 1065 | /* Resume the system call. */ | ||
| 1066 | return 0; | ||
| 1067 | |||
| 1068 | fail: | ||
| 1069 | errno = EIO; | ||
| 1070 | return 1; | ||
| 1071 | #endif /* REENTRANT */ | ||
| 1072 | } | ||
| 1073 | |||
| 982 | /* Process the system call at which TRACEE is stopped. If the system | 1074 | /* Process the system call at which TRACEE is stopped. If the system |
| 983 | call is not known or not exec, send TRACEE on its way. Otherwise, | 1075 | call is not known or not exec, send TRACEE on its way. Otherwise, |
| 984 | rewrite it to load the loader and perform an appropriate action. */ | 1076 | rewrite it to load the loader and perform an appropriate action. */ |
| @@ -1056,9 +1148,50 @@ process_system_call (struct exec_tracee *tracee) | |||
| 1056 | goto emulate_syscall; | 1148 | goto emulate_syscall; |
| 1057 | } | 1149 | } |
| 1058 | 1150 | ||
| 1151 | goto continue_syscall; | ||
| 1152 | |||
| 1153 | #ifdef OPEN_SYSCALL | ||
| 1154 | case OPEN_SYSCALL: | ||
| 1155 | #endif /* OPEN_SYSCALL */ | ||
| 1156 | case OPENAT_SYSCALL: | ||
| 1157 | |||
| 1158 | /* This system call is already in progress if | ||
| 1159 | TRACEE->waiting_for_syscall is true. */ | ||
| 1160 | |||
| 1161 | if (!tracee->waiting_for_syscall) | ||
| 1162 | { | ||
| 1163 | /* Handle this open system call. */ | ||
| 1164 | rc = handle_openat (callno, ®s, tracee, &result); | ||
| 1165 | |||
| 1166 | /* rc means the same as in `handle_exec', except that `open' | ||
| 1167 | is never emulated. */ | ||
| 1168 | |||
| 1169 | if (rc == 1) | ||
| 1170 | goto report_syscall_error; | ||
| 1171 | |||
| 1172 | /* The stack pointer must be restored after it was modified | ||
| 1173 | by `user_alloca'; record sp in TRACEE, which will be | ||
| 1174 | restored after this system call completes. */ | ||
| 1175 | tracee->sp = sp; | ||
| 1176 | } | ||
| 1177 | else | ||
| 1178 | { | ||
| 1179 | /* Restore that stack pointer. */ | ||
| 1180 | regs.STACK_POINTER = tracee->sp; | ||
| 1181 | |||
| 1182 | #ifdef __aarch64__ | ||
| 1183 | if (aarch64_set_regs (tracee->pid, ®s, true)) | ||
| 1184 | return; | ||
| 1185 | #else /* !__aarch64__ */ | ||
| 1186 | if (ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s)) | ||
| 1187 | return; | ||
| 1188 | #endif /* __aarch64__ */ | ||
| 1189 | } | ||
| 1190 | |||
| 1059 | /* Fallthrough. */ | 1191 | /* Fallthrough. */ |
| 1060 | 1192 | ||
| 1061 | default: | 1193 | default: |
| 1194 | continue_syscall: | ||
| 1062 | /* Don't wait for the system call to finish; instead, the system | 1195 | /* Don't wait for the system call to finish; instead, the system |
| 1063 | will DTRT upon the next call to PTRACE_SYSCALL after the | 1196 | will DTRT upon the next call to PTRACE_SYSCALL after the |
| 1064 | syscall-trap signal is delivered. */ | 1197 | syscall-trap signal is delivered. */ |