]> git.eshelyaron.com Git - emacs.git/commitdiff
Work around system restrictions regarding exec
authorPo Lu <luangruo@yahoo.com>
Mon, 1 May 2023 01:31:58 +0000 (09:31 +0800)
committerPo Lu <luangruo@yahoo.com>
Mon, 1 May 2023 01:31:58 +0000 (09:31 +0800)
* doc/emacs/android.texi (Android Environment): Document
`android-use-exec-loader'.
* exec/exec1.c (main): Set program group of child process.
* src/android.c (android_rewrite_spawn_argv): New function.
* src/android.h: Update prototypes.
* src/androidfns.c (syms_of_androidfns): New variable
`android_use_exec_loader'.
* src/callproc.c (emacs_spawn): Rewrite the argument vector to
use exec1 if necessary.

doc/emacs/android.texi
exec/exec1.c
src/android.c
src/android.h
src/androidfns.c
src/callproc.c

index 08897d3f97e8126d036d5e631c76f4054d766f86..e1c644d60438e45e1ebd2b8858200e8eff4bce03 100644 (file)
@@ -252,10 +252,7 @@ Emacs, the system has an overwhelming number of users.
 which is the app data directory (@pxref{Android File System}.)
 
   Each application is also prohibited from accessing system
-directories, and the app data directories of other applications.  In
-recent versions of Android, the system also prohibits, for security
-reasons, even Emacs itself from running executables inside the app
-data directory.
+directories, and the app data directories of other applications.
 
   Emacs comes with several binaries.  While being executable files,
 they are packaged as libraries in the library directory, because
@@ -277,6 +274,17 @@ However, the approach it takes was devised by reading Android source
 code, and is not sanctioned by the Android compatibility definition
 documents, so your mileage may vary.
 
+@cindex call-process, Android
+@vindex android-use-exec-loader
+  Android 10 and later versions of the system also prohibit Emacs
+itself from running executables inside the app data directory.  On
+these systems, Emacs normally applies a workaround; however, this
+workaround requires running all sub-processes in another subprocess,
+and applying process tracing to all executables, which may prove to be
+problematic for various different reasons.  In that case, the
+workaround can be disabled by changing the variable
+@code{android-use-exec-loader} to @code{nil}.
+
 @section Running Emacs in the background
 @cindex emacs killed, android
 @cindex emacs in the background, android
index 835bf8e72b92d502256199f54dabfc2fdfdc7f80..d77ca8adf547693d29ade4bf35a4c5b0b48d0eed 100644 (file)
@@ -20,6 +20,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <config.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <sys/wait.h>
 
 #include "exec.h"
@@ -41,10 +42,15 @@ main (int argc, char **argv)
   extern char **environ;
   int wstatus;
 
+  pid1 = getpid ();
   pid = fork ();
 
   if (!pid)
     {
+      /* Set the process group used to the parent.  */
+      if (setpgid (0, pid1))
+       perror ("setpgid");
+
       tracing_execve (argv[2], argv + 2, environ);
 
       /* An error occured.  Exit with failure.  */
index 3798758ff16193d1a4d6147cd5896f40c2a0a677..ce8f277e120eb186413c7e3d1dcfac334c708b27 100644 (file)
@@ -6514,6 +6514,89 @@ android_free_cursor (android_cursor cursor)
   android_destroy_handle (cursor);
 }
 
+\f
+
+/* Process execution.
+
+   Newer Android systems use SELinux to restrict user programs from
+   executing programs installed in the application data directory for
+   security reasons.  Emacs uses a `loader' binary installed in the
+   application data directory to manually load executables and replace
+   the `execve' system call.  */
+
+enum
+  {
+    /* Maximum number of arguments available.  */
+    MAXARGS = 1024,
+  };
+
+/* Rewrite the command line given in *ARGV to utilize the `exec1'
+   bootstrap binary if necessary.
+
+   Value is 0 upon success, else 1.  Set errno upon failure.
+
+   ARGV holds a pointer to a NULL-terminated array of arguments given
+   to `emacs_spawn'.  */
+
+int
+android_rewrite_spawn_argv (const char ***argv)
+{
+  static const char *new_args[MAXARGS];
+  static char exec1_name[PATH_MAX], loader_name[PATH_MAX];
+  size_t i, nargs;
+
+  /* This isn't required on Android 9 or earlier.  */
+
+  if (android_api_level < 29 || !android_use_exec_loader)
+    return 0;
+
+  /* Get argv[0]; this should never be NULL.
+     Then, verify that it exists and is executable.  */
+
+  eassert (**argv);
+  if (access (**argv, R_OK | X_OK))
+    return 1;
+
+  /* Count the number of arguments in *argv.  */
+
+  nargs = 0;
+  while ((*argv)[nargs])
+    ++nargs;
+
+  /* nargs now holds the number of arguments in argv.  If it's larger
+     than MAXARGS, return failure.  */
+
+  if (nargs + 2 > MAXARGS)
+    {
+      errno = E2BIG;
+      return 1;
+    }
+
+  /* Fill in the name of `libexec1.so'.  */
+  snprintf (exec1_name, PATH_MAX, "%s/libexec1.so",
+           android_lib_dir);
+
+  /* And libloader.so.  */
+  snprintf (loader_name, PATH_MAX, "%s/libloader.so",
+           android_lib_dir);
+
+  /* Now fill in the first two arguments.  */
+  new_args[0] = exec1_name;
+  new_args[1] = loader_name;
+
+  /* And insert the rest.  */
+  for (i = 0; i < nargs; ++i)
+    new_args[i + 2] = (*argv)[i];
+
+  /* Replace argv.  */
+  *argv = new_args;
+
+  /* Return success.  */
+  return 0;
+}
+
+\f
+
 #else /* ANDROID_STUBIFY */
 
 /* X emulation functions for Android.  */
index 24666aaf98953e3940ad4f8d59bd866610dde295..62d420d4cce11c2a3d4d0660bcc5bcdfe758b309 100644 (file)
@@ -190,6 +190,11 @@ extern void android_write_event (union android_event *);
 
 extern unsigned int event_serial;
 
+\f
+
+/* Process related functions.  */
+extern int android_rewrite_spawn_argv (const char ***);
+
 #endif
 
 /* JNI functions should not be built when Emacs is stubbed out for the
index 3367ebdf75584a34088969c8b62d9fb3cf652739..3bd34edd5b98b5a29c00a76ca073efbe51634730 100644 (file)
@@ -3112,6 +3112,20 @@ Note that if you set this, you will no longer be able to quit Emacs
 using the volume down button.  */);
   android_pass_multimedia_buttons_to_system = false;
 
+  DEFVAR_BOOL ("android-use-exec-loader", android_use_exec_loader,
+    doc: /* Whether or not to bypass system restrictions on program execution.
+
+Android 10 and later prevent programs from executing files installed
+in writable directories, such as the application data directory.
+
+When non-nil, Emacs will bypass this restriction by running such
+executables under system call tracing, and replacing the `execve'
+system call with a version which ignores the system's security
+restrictions.
+
+This option has no effect on Android 9 and earlier.  */);
+  android_use_exec_loader = true;
+
   /* Functions defined.  */
   defsubr (&Sx_create_frame);
   defsubr (&Sxw_color_defined_p);
index a1811a3bb2393f65923b84ae5a51c3f218f2785d..015b52bc9bc9970cefea8a1c5111f12ca043cd5f 100644 (file)
@@ -92,6 +92,10 @@ extern char **environ;
 #include "pgtkterm.h"
 #endif
 
+#ifdef HAVE_ANDROID
+#include "android.h"
+#endif /* HAVE_ANDROID */
+
 /* Pattern used by call-process-region to make temp files.  */
 static Lisp_Object Vtemp_file_name_pattern;
 
@@ -1437,6 +1441,18 @@ emacs_spawn (pid_t *newpid, int std_in, int std_out, int std_err,
              const char *pty_name, bool pty_in, bool pty_out,
              const sigset_t *oldset)
 {
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  /* Android 10 and later don't allow directly executing programs
+     installed in the application data directory.  Emacs provides a
+     loader binary which replaces the `execve' system call for it and
+     all its children.  On these systems, rewrite the command line to
+     call that loader binary instead.  */
+
+  if (android_rewrite_spawn_argv ((const char ***) &argv))
+    return 1;
+#endif /* defined HAVE_ANDROID && !defined ANDROID_STUBIFY */
+
+
 #if USABLE_POSIX_SPAWN
   /* Prefer the simpler `posix_spawn' if available.  `posix_spawn'
      doesn't yet support setting up pseudoterminals, so we fall back