1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-26 07:33:47 +00:00

Fix cwd relative process execution on Android

* exec/exec.c (format_pid): New function.
(exec_0): Make cwd relative file names relative to
/proc/pid/cwd.
* exec/trace.c (handle_exec): Handle EINTR.
(process_system_call): Report failure without clobbering x0.
This commit is contained in:
Po Lu 2023-05-01 21:23:12 +08:00
parent da6f0d9c6f
commit b9de6e35b7
2 changed files with 78 additions and 14 deletions

View File

@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <stdlib.h>
#include <sys/ptrace.h> #include <sys/ptrace.h>
#include <sys/param.h> #include <sys/param.h>
@ -808,6 +809,35 @@ insert_args (struct exec_tracee *tracee, USER_REGS_STRUCT *regs,
/* Format PID, an unsigned process identifier, in base 10. Place the
result in *IN, and return a pointer to the byte after the
result. REM should be NULL. */
static char *
format_pid (char *in, unsigned int pid)
{
unsigned int digits[32], *fill;
fill = digits;
for (; pid != 0; pid = pid / 10)
*fill++ = pid % 10;
/* Insert 0 if the number would otherwise be empty. */
if (fill == digits)
*fill++ = 0;
while (fill != digits)
{
--fill;
*in++ = '0' + *fill;
}
*in = '\0';
return in;
}
/* Return a sequence of actions required to load the executable under /* Return a sequence of actions required to load the executable under
the file NAME for the given TRACEE. First, see if the file starts the file NAME for the given TRACEE. First, see if the file starts
with #!; in that case, find the program to open and use that with #!; in that case, find the program to open and use that
@ -836,6 +866,29 @@ exec_0 (const char *name, struct exec_tracee *tracee,
#if defined __mips__ && !defined MIPS_NABI #if defined __mips__ && !defined MIPS_NABI
int fpu_mode; int fpu_mode;
#endif /* defined __mips__ && !defined MIPS_NABI */ #endif /* defined __mips__ && !defined MIPS_NABI */
char buffer[PATH_MAX + 80], *rewrite;
size_t remaining;
/* If name is not absolute, then make it relative to TRACEE's
cwd. Use stpcpy, as sprintf is not reentrant. */
if (name[0] && name[0] != '/')
{
/* Clear `buffer'. */
memset (buffer, 0, sizeof buffer);
/* Copy over /proc, the PID, and /cwd/. */
rewrite = stpcpy (buffer, "/proc/");
rewrite = format_pid (rewrite, tracee->pid);
rewrite = stpcpy (rewrite, "/cwd/");
/* Make sure there is enough free space. */
remaining = buffer + sizeof buffer - rewrite - 1;
rewrite = stpncpy (rewrite, name, remaining);
/* Replace name with buffer. */
name = buffer;
}
fd = open (name, O_RDONLY); fd = open (name, O_RDONLY);
if (fd < 0) if (fd < 0)

View File

@ -457,10 +457,17 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
memcpy (&original, regs, sizeof *regs); memcpy (&original, regs, sizeof *regs);
/* Figure out what the loader needs to do. */ /* Figure out what the loader needs to do. */
again1:
area = exec_0 (buffer, tracee, &size, regs); area = exec_0 (buffer, tracee, &size, regs);
if (!area) if (!area)
return 1; {
/* Handle SIGINTR errors caused by IO. */
if (errno == EINTR)
goto again1;
return 1;
}
/* Rewrite the first argument to point to the loader. */ /* Rewrite the first argument to point to the loader. */
@ -516,10 +523,7 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
goto again; goto again;
if (rc < 0) if (rc < 0)
{ return 1;
errno = EIO;
return 1;
}
if (!WIFSTOPPED (wstatus)) if (!WIFSTOPPED (wstatus))
/* The process has been killed in response to a signal. /* The process has been killed in response to a signal.
@ -608,13 +612,14 @@ handle_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs)
#endif /* STACK_GROWS_DOWNWARDS */ #endif /* STACK_GROWS_DOWNWARDS */
exec_failure:
/* Continue. */ /* Continue. */
if (ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0)) if (ptrace (PTRACE_SYSCALL, tracee->pid, 0, 0))
return 3; return 3;
return 0; return 0;
exec_failure:
return 3;
} }
/* Process the system call at which TRACEE is stopped. If the system /* Process the system call at which TRACEE is stopped. If the system
@ -625,10 +630,10 @@ static void
process_system_call (struct exec_tracee *tracee) process_system_call (struct exec_tracee *tracee)
{ {
USER_REGS_STRUCT regs; USER_REGS_STRUCT regs;
int rc, wstatus; int rc, wstatus, save_errno;
USER_WORD callno, sp; USER_WORD callno, sp;
#ifdef __aarch64__ #ifdef __aarch64__
USER_WORD old_w0, old_w1, old_w2; USER_WORD old_w1, old_w2;
#endif /* __aarch64__ */ #endif /* __aarch64__ */
#ifdef __aarch64__ #ifdef __aarch64__
@ -695,6 +700,9 @@ process_system_call (struct exec_tracee *tracee)
Make sure that the stack pointer is restored to its original Make sure that the stack pointer is restored to its original
position upon exit, or bad things can happen. */ position upon exit, or bad things can happen. */
/* First, save errno; system calls below will clobber it. */
save_errno = errno;
#ifndef __aarch64__ #ifndef __aarch64__
regs.SYSCALL_NUM_REG = -1; regs.SYSCALL_NUM_REG = -1;
#else /* __aarch64__ */ #else /* __aarch64__ */
@ -702,7 +710,6 @@ process_system_call (struct exec_tracee *tracee)
can't find any unused system call, so use fcntl instead, with can't find any unused system call, so use fcntl instead, with
invalid arguments. */ invalid arguments. */
regs.SYSCALL_NUM_REG = 72; regs.SYSCALL_NUM_REG = 72;
old_w0 = regs.regs[0];
old_w1 = regs.regs[1]; old_w1 = regs.regs[1];
old_w2 = regs.regs[2]; old_w2 = regs.regs[2];
regs.regs[0] = -1; regs.regs[0] = -1;
@ -739,6 +746,11 @@ process_system_call (struct exec_tracee *tracee)
if (rc == -1 && errno == EINTR) if (rc == -1 && errno == EINTR)
goto again1; goto again1;
/* Return if waitpid fails. */
if (rc == -1)
return;
if (!WIFSTOPPED (wstatus)) if (!WIFSTOPPED (wstatus))
/* The process has been killed in response to a signal. In this /* The process has been killed in response to a signal. In this
case, simply unlink the tracee and return. */ case, simply unlink the tracee and return. */
@ -747,16 +759,15 @@ process_system_call (struct exec_tracee *tracee)
{ {
#ifdef __mips__ #ifdef __mips__
/* MIPS systems place errno in v0 and set a3 to 1. */ /* MIPS systems place errno in v0 and set a3 to 1. */
regs.gregs[2] = errno; regs.gregs[2] = save_errno;
regs.gregs[7] = 1; regs.gregs[7] = 1;
#else /* !__mips__ */ #else /* !__mips__ */
regs.SYSCALL_RET_REG = -errno; regs.SYSCALL_RET_REG = -save_errno;
#endif /* __mips__ */ #endif /* __mips__ */
/* Report errno. */ /* Report errno. */
#ifdef __aarch64__ #ifdef __aarch64__
/* Restore x0, x1 and x2. */ /* Restore x1 and x2. x0 is clobbered by errno. */
regs.regs[0] = old_w0;
regs.regs[1] = old_w1; regs.regs[1] = old_w1;
regs.regs[2] = old_w2; regs.regs[2] = old_w2;
aarch64_set_regs (tracee->pid, &regs, false); aarch64_set_regs (tracee->pid, &regs, false);