emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master c37b50ad417: Intercept calls to `openat' under Android


From: Po Lu
Subject: master c37b50ad417: Intercept calls to `openat' under Android
Date: Fri, 26 Jan 2024 21:44:17 -0500 (EST)

branch: master
commit c37b50ad417c6cb340f54ffe218f5d889345451a
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    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.
---
 exec/configure.ac |  13 +++++-
 exec/exec.h       |   4 ++
 exec/trace.c      | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 150 insertions(+), 2 deletions(-)

diff --git a/exec/configure.ac b/exec/configure.ac
index 9008c84f6a6..d70dbea3477 100644
--- a/exec/configure.ac
+++ b/exec/configure.ac
@@ -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([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.])
 
 AC_CANONICAL_HOST
@@ -257,6 +259,8 @@ AS_CASE([$host], [x86_64-*linux*],
      AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
      AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
      AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
+     AC_DEFINE([OPEN_SYSCALL], [__NR_open])
+     AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
      exec_CHECK_LINUX_CLONE3
      # Make sure the loader doesn't conflict with other position
      # dependent code.
@@ -285,6 +289,8 @@ AS_CASE([$host], [x86_64-*linux*],
      AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
      AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
      AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
+     AC_DEFINE([OPEN_SYSCALL], [__NR_open])
+     AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
      exec_CHECK_LINUX_CLONE3
      # Make sure the loader doesn't conflict with other position
      # dependent code.
@@ -312,8 +318,9 @@ AS_CASE([$host], [x86_64-*linux*],
      AC_DEFINE([INTERPRETER_BASE], [0x3f00000000])
      AC_DEFINE([STACK_GROWS_DOWNWARDS], [1])
      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([OPENAT_SYSCALL], [__NR_openat])
      exec_CHECK_LINUX_CLONE3
      # Make sure the loader doesn't conflict with other position
      # 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([READLINK_SYSCALL], [__NR_readlink])
      AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
+     AC_DEFINE([OPEN_SYSCALL], [__NR_open])
+     AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
      exec_CHECK_LINUX_CLONE3
      LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
      exec_loader=loader-armeabi.s],
@@ -365,6 +374,8 @@ AS_CASE([$host], [x86_64-*linux*],
        AC_DEFINE([CLONE_SYSCALL], [__NR_clone])
        AC_DEFINE([READLINK_SYSCALL], [__NR_readlink])
        AC_DEFINE([READLINKAT_SYSCALL], [__NR_readlinkat])
+       AC_DEFINE([OPEN_SYSCALL], [__NR_open])
+       AC_DEFINE([OPENAT_SYSCALL], [__NR_openat])
        exec_CHECK_LINUX_CLONE3
        LOADERFLAGS="$LOADERFLAGS $LDPREFIX-Ttext=0x20000000"
        exec_loader=loader-armeabi.s],
diff --git a/exec/exec.h b/exec/exec.h
index bed5edc9bab..ad1b50276c8 100644
--- a/exec/exec.h
+++ b/exec/exec.h
@@ -148,6 +148,10 @@ struct exec_tracee
   /* The next process being traced.  */
   struct exec_tracee *next;
 
+  /* Address of any stack pointer to restore after system call
+     completion.  */
+  USER_WORD sp;
+
   /* The thread ID of this process.  */
   pid_t pid;
 
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,
     return 0;
 
   /* 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 = MIN (size, MIN (PATH_MAX, length));
@@ -979,6 +979,98 @@ handle_readlinkat (USER_WORD callno, USER_REGS_STRUCT 
*regs,
 #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
    call is not known or not exec, send TRACEE on its way.  Otherwise,
    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 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, &regs, 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, &regs, true))
+           return;
+#else /* !__aarch64__ */
+         if (ptrace (PTRACE_SETREGS, tracee->pid, NULL, &regs))
+           return;
+#endif /* __aarch64__ */
+       }
+
       /* Fallthrough.  */
 
     default:
+    continue_syscall:
       /* Don't wait for the system call to finish; instead, the system
         will DTRT upon the next call to PTRACE_SYSCALL after the
         syscall-trap signal is delivered.  */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]