mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-06 06:20:55 -08:00
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.
This commit is contained in:
parent
55f0b3e561
commit
c37b50ad41
3 changed files with 150 additions and 2 deletions
|
|
@ -131,6 +131,8 @@ AH_TEMPLATE([CLONE_SYSCALL], [Define to number of the `clone' system call.])
|
||||||
AH_TEMPLATE([CLONE3_SYSCALL], [Define to number of the `clone3' system call.])
|
AH_TEMPLATE([CLONE3_SYSCALL], [Define to number of the `clone3' system call.])
|
||||||
AH_TEMPLATE([READLINK_SYSCALL], [Define to number of the `readlink' system call.])
|
AH_TEMPLATE([READLINK_SYSCALL], [Define to number of the `readlink' system call.])
|
||||||
AH_TEMPLATE([READLINKAT_SYSCALL], [Define to number of the `readlinkat' system call.])
|
AH_TEMPLATE([READLINKAT_SYSCALL], [Define to number of the `readlinkat' system call.])
|
||||||
|
AH_TEMPLATE([OPEN_SYSCALL], [Define to number of the `open' system call.])
|
||||||
|
AH_TEMPLATE([OPENAT_SYSCALL], [Define to number of the `openat' system call.])
|
||||||
AH_TEMPLATE([REENTRANT], [Define to 1 if the library is used within a signal handler.])
|
AH_TEMPLATE([REENTRANT], [Define to 1 if the library is used within a signal handler.])
|
||||||
|
|
||||||
AC_CANONICAL_HOST
|
AC_CANONICAL_HOST
|
||||||
|
|
@ -257,6 +259,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
||||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||||
|
AC_DEFINE([OPEN_SYSCALL], [__NR_open])
|
||||||
|
AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
|
||||||
exec_CHECK_LINUX_CLONE3
|
exec_CHECK_LINUX_CLONE3
|
||||||
# Make sure the loader doesn't conflict with other position
|
# Make sure the loader doesn't conflict with other position
|
||||||
# dependent code.
|
# dependent code.
|
||||||
|
|
@ -285,6 +289,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
||||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||||
|
AC_DEFINE([OPEN_SYSCALL], [__NR_open])
|
||||||
|
AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
|
||||||
exec_CHECK_LINUX_CLONE3
|
exec_CHECK_LINUX_CLONE3
|
||||||
# Make sure the loader doesn't conflict with other position
|
# Make sure the loader doesn't conflict with other position
|
||||||
# dependent code.
|
# dependent code.
|
||||||
|
|
@ -312,8 +318,9 @@ AS_CASE([$host], [x86_64-*linux*],
|
||||||
AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
|
AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
|
||||||
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
|
||||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||||
# Note that aarch64 has no `readlink'.
|
# Note that aarch64 has neither `readlink' nor `open'.
|
||||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||||
|
AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
|
||||||
exec_CHECK_LINUX_CLONE3
|
exec_CHECK_LINUX_CLONE3
|
||||||
# Make sure the loader doesn't conflict with other position
|
# Make sure the loader doesn't conflict with other position
|
||||||
# dependent code. ARM places rather significant restrictions on
|
# dependent code. ARM places rather significant restrictions on
|
||||||
|
|
@ -343,6 +350,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
||||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||||
|
AC_DEFINE([OPEN_SYSCALL], [__NR_open])
|
||||||
|
AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
|
||||||
exec_CHECK_LINUX_CLONE3
|
exec_CHECK_LINUX_CLONE3
|
||||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
||||||
exec_loader=loader-armeabi.s],
|
exec_loader=loader-armeabi.s],
|
||||||
|
|
@ -365,6 +374,8 @@ AS_CASE([$host], [x86_64-*linux*],
|
||||||
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
|
||||||
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
|
||||||
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
|
||||||
|
AC_DEFINE([OPEN_SYSCALL], [__NR_open])
|
||||||
|
AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
|
||||||
exec_CHECK_LINUX_CLONE3
|
exec_CHECK_LINUX_CLONE3
|
||||||
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
|
||||||
exec_loader=loader-armeabi.s],
|
exec_loader=loader-armeabi.s],
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,10 @@ struct exec_tracee
|
||||||
/* The next process being traced. */
|
/* The next process being traced. */
|
||||||
struct exec_tracee *next;
|
struct exec_tracee *next;
|
||||||
|
|
||||||
|
/* Address of any stack pointer to restore after system call
|
||||||
|
completion. */
|
||||||
|
USER_WORD sp;
|
||||||
|
|
||||||
/* The thread ID of this process. */
|
/* The thread ID of this process. */
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
|
|
||||||
135
exec/trace.c
135
exec/trace.c
|
|
@ -961,7 +961,7 @@ handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or
|
/* Copy over tracee->exec_file. Truncate it to PATH_MAX, length, or
|
||||||
size, whichever is less. */
|
size, whichever is smaller. */
|
||||||
|
|
||||||
length = strlen (tracee->exec_file);
|
length = strlen (tracee->exec_file);
|
||||||
length = MIN (size, MIN (PATH_MAX, length));
|
length = MIN (size, MIN (PATH_MAX, length));
|
||||||
|
|
@ -979,6 +979,98 @@ handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT *regs,
|
||||||
#endif /* REENTRANT */
|
#endif /* REENTRANT */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle an `open' or `openat' system call.
|
||||||
|
|
||||||
|
CALLNO is the system call number, and REGS are the current user
|
||||||
|
registers of the TRACEE.
|
||||||
|
|
||||||
|
If the file name specified in such system call is `/proc/self/exe',
|
||||||
|
replace the file name with the executable loaded into the process
|
||||||
|
issuing this system call.
|
||||||
|
|
||||||
|
Value is 0 upon success and 1 upon failure. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
handle_openat (USER_WORD callno, USER_REGS_STRUCT *regs,
|
||||||
|
struct exec_tracee *tracee, USER_WORD *result)
|
||||||
|
{
|
||||||
|
#ifdef REENTRANT
|
||||||
|
/* readlinkat cannot be handled specially when the library is built
|
||||||
|
to be reentrant, as the file name information cannot be
|
||||||
|
recorded. */
|
||||||
|
return 0;
|
||||||
|
#else /* !REENTRANT */
|
||||||
|
char buffer[PATH_MAX + 1];
|
||||||
|
USER_WORD address;
|
||||||
|
size_t length;
|
||||||
|
USER_REGS_STRUCT original;
|
||||||
|
|
||||||
|
/* Read the file name. */
|
||||||
|
|
||||||
|
#ifdef OPEN_SYSCALL
|
||||||
|
if (callno == OPEN_SYSCALL)
|
||||||
|
address = regs->SYSCALL_ARG_REG;
|
||||||
|
else
|
||||||
|
#endif /* OPEN_SYSCALL */
|
||||||
|
address = regs->SYSCALL_ARG1_REG;
|
||||||
|
|
||||||
|
/* Read the file name into the buffer and verify that it is NULL
|
||||||
|
terminated. */
|
||||||
|
read_memory (tracee, buffer, PATH_MAX, address);
|
||||||
|
|
||||||
|
if (!memchr (buffer, '\0', PATH_MAX))
|
||||||
|
{
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now check if the caller is looking for /proc/self/exe.
|
||||||
|
|
||||||
|
dirfd can be ignored, as for now only absolute file names are
|
||||||
|
handled. FIXME. */
|
||||||
|
|
||||||
|
if (strcmp (buffer, "/proc/self/exe") || !tracee->exec_file)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Copy over tracee->exec_file. This doesn't correctly handle the
|
||||||
|
scenario where tracee->exec_file is longer than PATH_MAX, but
|
||||||
|
that has yet to be encountered in practice. */
|
||||||
|
|
||||||
|
original = *regs;
|
||||||
|
length = strlen (tracee->exec_file);
|
||||||
|
address = user_alloca (tracee, &original, regs, length + 1);
|
||||||
|
|
||||||
|
if (!address
|
||||||
|
|| user_copy (tracee, (unsigned char *) tracee->exec_file,
|
||||||
|
address, length))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Replace the file name buffer with ADDRESS. */
|
||||||
|
|
||||||
|
#ifdef OPEN_SYSCALL
|
||||||
|
if (callno == OPEN_SYSCALL)
|
||||||
|
regs->SYSCALL_ARG_REG = address;
|
||||||
|
else
|
||||||
|
#endif /* OPEN_SYSCALL */
|
||||||
|
regs->SYSCALL_ARG1_REG = address;
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
if (aarch64_set_regs (tracee->pid, regs, false))
|
||||||
|
goto fail;
|
||||||
|
#else /* !__aarch64__ */
|
||||||
|
if (ptrace (PTRACE_SETREGS, tracee->pid, NULL, regs))
|
||||||
|
goto fail;
|
||||||
|
#endif /* __aarch64__ */
|
||||||
|
|
||||||
|
/* Resume the system call. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
errno = EIO;
|
||||||
|
return 1;
|
||||||
|
#endif /* REENTRANT */
|
||||||
|
}
|
||||||
|
|
||||||
/* Process the system call at which TRACEE is stopped. If the system
|
/* Process the system call at which TRACEE is stopped. If the system
|
||||||
call is not known or not exec, send TRACEE on its way. Otherwise,
|
call is not known or not exec, send TRACEE on its way. Otherwise,
|
||||||
rewrite it to load the loader and perform an appropriate action. */
|
rewrite it to load the loader and perform an appropriate action. */
|
||||||
|
|
@ -1056,9 +1148,50 @@ process_system_call (struct exec_tracee *tracee)
|
||||||
goto emulate_syscall;
|
goto emulate_syscall;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goto continue_syscall;
|
||||||
|
|
||||||
|
#ifdef OPEN_SYSCALL
|
||||||
|
case OPEN_SYSCALL:
|
||||||
|
#endif /* OPEN_SYSCALL */
|
||||||
|
case OPENAT_SYSCALL:
|
||||||
|
|
||||||
|
/* This system call is already in progress if
|
||||||
|
TRACEE->waiting_for_syscall is true. */
|
||||||
|
|
||||||
|
if (!tracee->waiting_for_syscall)
|
||||||
|
{
|
||||||
|
/* Handle this open system call. */
|
||||||
|
rc = handle_openat (callno, ®s, tracee, &result);
|
||||||
|
|
||||||
|
/* rc means the same as in `handle_exec', except that `open'
|
||||||
|
is never emulated. */
|
||||||
|
|
||||||
|
if (rc == 1)
|
||||||
|
goto report_syscall_error;
|
||||||
|
|
||||||
|
/* The stack pointer must be restored after it was modified
|
||||||
|
by `user_alloca'; record sp in TRACEE, which will be
|
||||||
|
restored after this system call completes. */
|
||||||
|
tracee->sp = sp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Restore that stack pointer. */
|
||||||
|
regs.STACK_POINTER = tracee->sp;
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
if (aarch64_set_regs (tracee->pid, ®s, true))
|
||||||
|
return;
|
||||||
|
#else /* !__aarch64__ */
|
||||||
|
if (ptrace (PTRACE_SETREGS, tracee->pid, NULL, ®s))
|
||||||
|
return;
|
||||||
|
#endif /* __aarch64__ */
|
||||||
|
}
|
||||||
|
|
||||||
/* Fallthrough. */
|
/* Fallthrough. */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
continue_syscall:
|
||||||
/* Don't wait for the system call to finish; instead, the system
|
/* Don't wait for the system call to finish; instead, the system
|
||||||
will DTRT upon the next call to PTRACE_SYSCALL after the
|
will DTRT upon the next call to PTRACE_SYSCALL after the
|
||||||
syscall-trap signal is delivered. */
|
syscall-trap signal is delivered. */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue