Optimize process execution on Android

* exec/configure.ac (REENTRANT): Remove option for reentrancy.
(PROGRAM_COUNTER, HAVE_SECCOMP): Define register providing the
program counter and enable seccomp if its headers are available.

* exec/exec.c (write_load_command): Avoid defining unused
variable.
(exec_0): Remove code specific to REENTRANT configurations.

* exec/exec.h (struct exec_tracee) <exec_data, data_size>: New
fields for loader instructions and their size.

* exec/exec1.c (main): Call exec_init before forking.

* exec/mipsel-user.h (ELF_NGREG): Delete definition.
(struct mipsel_regs): Reduce number of gregs to 32, but
introduce separate fields for special registers.

* exec/trace.c (use_seccomp_p): New variable; defile to false if
!HAVE_SECCOMP.
(remove_tracee): Cease providing for non-reentrant
configurations.  Release executable data if present.
(handle_clone_prepare): Likewise.  Resume process with
PTRACE_CONT if seccomp-based interception is enabled.
(handle_clone, check_signal): Resume processes as above.
(handle_exec): Divide into two functions, with only rewriting
the system call and generating instructions for the loader
remaining in the first, and copying such instructions into the
loader's stack removed into a new function, `finish_exec'.
(finish_exec): New function.
(handle_readlinkat, handle_openat): Abolish non-REENTRANT
configurations.
(process_system_call): Divide exec system calls into two phases,
disambiguated by the value of tracee->waiting_for_syscall.  Typo
fixes.  Accommodate syscall-exit-stops where the signal was
initially intercepted by `seccomp_system_call'.
(interesting_syscalls): New array.
(ARRAYELTS): New macro.
(seccomp_system_call, establish_seccomp_filter): New function.
(tracing_execve) [HAVE_SECCOMP]: Establish a seccomp filter if
this is to be enabled.
(after_fork): Provide PTRACE_O_TRACESECCOMP.  Resume process
with PTRACE_CONT if seccomp-based interception is enabled.
(exec_waitpid): Resume process with PTRACE_CONT if seccomp-based
interception is enabled.  Dispatch stops identifying as
PTRACE_EVENT_SECCOMP to `seccomp_system_call'.
(exec_init): Establish whether it is possible to enable seccomp.
This commit is contained in:
Po Lu 2024-07-01 18:11:58 +08:00
parent 7c8d4e96ba
commit ebf5bcb9f0
6 changed files with 666 additions and 219 deletions

View file

@ -42,11 +42,6 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */])
AC_ARG_WITH([reentrancy],
[AS_HELP_STRING([--with-reentrancy],
[Generate library which can be used within a signal handler.])],
[AC_DEFINE([REENTRANT], [1])])
AC_USE_SYSTEM_EXTENSIONS
AC_PROG_CC
AC_PROG_CPP
@ -74,9 +69,9 @@ AC_CHECK_FUNC([process_vm_readv],
]])])])
AC_CHECK_HEADERS([sys/param.h sys/uio.h])
AC_CHECK_MEMBERS([siginfo_t.si_syscall], [], [],
[[
[[
#include <signal.h>
]])
]])
AH_BOTTOM([
#ifdef HAVE_STDBOOL_H
@ -120,6 +115,7 @@ AH_TEMPLATE([SYSCALL_ARG2_REG], [Define to register holding arg2 to system calls
AH_TEMPLATE([SYSCALL_ARG3_REG], [Define to register holding arg3 to system calls.])
AH_TEMPLATE([SYSCALL_RET_REG], [Define to register holding value of system calls.])
AH_TEMPLATE([STACK_POINTER], [Define to register holding the stack pointer.])
AH_TEMPLATE([PROGRAM_COUNTER], [Define to register holding the program counter.])
AH_TEMPLATE([EXEC_SYSCALL], [Define to number of the `exec' system call.])
AH_TEMPLATE([USER_WORD], [Define to word type used by tracees.])
AH_TEMPLATE([USER_SWORD], [Define to signed word type used by tracees.])
@ -134,7 +130,8 @@ 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([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([HAVE_SECCOMP], [Define to 1 if secure computing filters are available
to accelerate interception of system calls.])
AC_CANONICAL_HOST
@ -250,6 +247,7 @@ AS_CASE([$host], [x86_64-*linux*],
AC_DEFINE([SYSCALL_ARG2_REG], [rdx])
AC_DEFINE([SYSCALL_ARG3_REG], [r10])
AC_DEFINE([STACK_POINTER], [rsp])
AC_DEFINE([PROGRAM_COUNTER], [rip])
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
AC_DEFINE([USER_WORD], [uintptr_t])
AC_DEFINE([USER_SWORD], [intptr_t])
@ -283,6 +281,7 @@ AS_CASE([$host], [x86_64-*linux*],
AC_DEFINE([SYSCALL_ARG2_REG], [edx])
AC_DEFINE([SYSCALL_ARG3_REG], [esi])
AC_DEFINE([STACK_POINTER], [esp])
AC_DEFINE([PROGRAM_COUNTER], [eip])
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
AC_DEFINE([USER_WORD], [uintptr_t])
AC_DEFINE([USER_SWORD], [intptr_t])
@ -314,6 +313,7 @@ AS_CASE([$host], [x86_64-*linux*],
AC_DEFINE([SYSCALL_ARG2_REG], [[regs[2]]])
AC_DEFINE([SYSCALL_ARG3_REG], [[regs[3]]])
AC_DEFINE([STACK_POINTER], [sp])
AC_DEFINE([PROGRAM_COUNTER], [pc])
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
AC_DEFINE([USER_WORD], [uintptr_t])
AC_DEFINE([USER_SWORD], [intptr_t])
@ -346,6 +346,7 @@ AS_CASE([$host], [x86_64-*linux*],
AC_DEFINE([SYSCALL_ARG2_REG], [[uregs[2]]])
AC_DEFINE([SYSCALL_ARG3_REG], [[uregs[3]]])
AC_DEFINE([STACK_POINTER], [[uregs[13]]])
AC_DEFINE([PROGRAM_COUNTER], [[uregs[15]]])
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
AC_DEFINE([USER_WORD], [uintptr_t])
AC_DEFINE([USER_SWORD], [intptr_t])
@ -371,6 +372,7 @@ AS_CASE([$host], [x86_64-*linux*],
AC_DEFINE([SYSCALL_ARG2_REG], [[uregs[2]]])
AC_DEFINE([SYSCALL_ARG3_REG], [[uregs[3]]])
AC_DEFINE([STACK_POINTER], [[uregs[13]]])
AC_DEFINE([STACK_POINTER], [[uregs[15]]])
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
AC_DEFINE([USER_WORD], [uintptr_t])
AC_DEFINE([USER_SWORD], [intptr_t])
@ -402,6 +404,7 @@ AS_CASE([$host], [x86_64-*linux*],
AC_DEFINE([SYSCALL_ARG2_REG], [[gregs[4]]]) # a2
AC_DEFINE([SYSCALL_ARG3_REG], [[gregs[5]]]) # a3
AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
AC_DEFINE([PROGRAM_COUNTER], [[cp0_epc]]) # pc
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
AC_DEFINE([USER_WORD], [uintptr_t])
AC_DEFINE([USER_SWORD], [intptr_t])
@ -432,6 +435,7 @@ AS_CASE([$host], [x86_64-*linux*],
AC_DEFINE([SYSCALL_ARG2_REG], [[gregs[4]]]) # a2
AC_DEFINE([SYSCALL_ARG3_REG], [[gregs[5]]]) # a3
AC_DEFINE([STACK_POINTER], [[gregs[29]]]) # sp
AC_DEFINE([PROGRAM_COUNTER], [[cp0_epc]]) # pc
AC_DEFINE([EXEC_SYSCALL], [__NR_execve])
AC_DEFINE([USER_WORD], [uintptr_t])
AC_DEFINE([USER_SWORD], [intptr_t])
@ -480,6 +484,12 @@ AC_ARG_VAR([LOADERFLAGS], [Flags used to link the loader.])
AC_ARG_VAR([ARFLAGS], [Flags for the archiver.])
AC_ARG_VAR([ASFLAGS], [Flags for the assembler.])
# Search for seccomp headers and declarations.
AC_CHECK_HEADERS([linux/seccomp.h linux/filter.h],
[AC_CHECK_DECLS([SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, SECCOMP_RET_TRACE],
[AC_DEFINE([HAVE_SECCOMP], [1])], [],
[[#include <linux/seccomp.h>]])])
# Make the assembler optimize for code size. Don't do this on MIPS,
# as the assembler code manages branch delays manually.

View file

@ -292,7 +292,9 @@ write_load_command (program_header *header, bool use_alternate,
struct exec_map_command command1;
USER_WORD start, end;
bool need_command1;
#ifndef PAGE_MASK
static long pagesize;
#endif /* !PAGE_MASK */
/* First, write the commands necessary to map the specified segment
itself.
@ -306,14 +308,14 @@ write_load_command (program_header *header, bool use_alternate,
#ifdef HAVE_GETPAGESIZE
if (!pagesize)
pagesize = getpagesize ();
#else /* HAVE_GETPAGESIZE */
#else /* !HAVE_GETPAGESIZE */
if (!pagesize)
pagesize = sysconf (_SC_PAGESIZE);
#endif /* HAVE_GETPAGESIZE */
#endif /* !HAVE_GETPAGESIZE */
#define PAGE_MASK (~(pagesize - 1))
#define PAGE_SIZE (pagesize)
#endif /* PAGE_MASK */
#endif /* !PAGE_MASK */
start = header->p_vaddr & PAGE_MASK;
end = ((header->p_vaddr + header->p_filesz
@ -895,10 +897,6 @@ format_pid (char *in, unsigned int pid)
with #!; in that case, find the program to open and use that
instead.
If REENTRANT is not defined, NAME is actually a buffer of size
PATH_MAX + 80. In that case, copy over the file name actually
opened.
Next, read the executable header, and add the necessary memory
mappings for each file. Finally, return the action data and its
size in *SIZE.
@ -976,11 +974,6 @@ exec_0 (char *name, struct exec_tracee *tracee,
rewrite = buffer1 + link_size;
remaining = buffer1 + sizeof buffer1 - rewrite - 1;
memcpy (rewrite, name, strnlen (name, remaining));
/* Replace name with buffer1. */
#ifndef REENTRANT
strcpy (name, buffer1);
#endif /* REENTRANT */
}
}

View file

@ -152,6 +152,16 @@ struct exec_tracee
completion. */
USER_WORD sp;
/* Name of the executable being run. */
char *exec_file;
/* Pointer to a storage area holding instructions for loading an
executable if an `exec' system call is outstanding, or NULL. */
char *exec_data;
/* Number of bytes in exec_data. */
size_t data_size;
/* The thread ID of this process. */
pid_t pid;
@ -162,11 +172,6 @@ struct exec_tracee
/* Whether or not the tracee has been created but is not yet
processed by `handle_clone'. */
bool new_child : 1;
#ifndef REENTRANT
/* Name of the executable being run. */
char *exec_file;
#endif /* !REENTRANT */
};

View file

@ -42,6 +42,9 @@ main (int argc, char **argv)
extern char **environ;
int wstatus;
/* Provide the file name of the loader. */
exec_init (argv[1]);
pid1 = getpid ();
pid = fork ();
@ -58,9 +61,6 @@ main (int argc, char **argv)
}
else
{
/* Provide the file name of the loader. */
exec_init (argv[1]);
if (after_fork (pid))
exit (127);

View file

@ -24,10 +24,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <sys/user.h>
#ifndef ELF_NGREG
#define ELF_NGREG 45
#endif /* ELF_NGREG */
/* This file defines a structure containing user mode general purpose
@ -36,7 +32,15 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
struct mipsel_regs
{
/* General purpose registers. */
uint64_t gregs[ELF_NGREG];
uint64_t gregs[32];
/* Saved special registers. */
uint64_t lo;
uint64_t hi;
uint64_t cp0_epc;
uint64_t cp0_badvaddr;
uint64_t cp0_status;
uint64_t cp0_cause;
};
#endif /* _MIPSEL_USER_H_ */

File diff suppressed because it is too large Load diff