[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
feature/android 5550816f596 3/5: Work around system restrictions regardi
From: |
Po Lu |
Subject: |
feature/android 5550816f596 3/5: Work around system restrictions regarding exec |
Date: |
Sun, 30 Apr 2023 23:29:56 -0400 (EDT) |
branch: feature/android
commit 5550816f5962943abd81fbf68901dad575f18c06
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Work around system restrictions regarding exec
* 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 | 16 +++++++---
exec/exec1.c | 6 ++++
src/android.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/android.h | 5 +++
src/androidfns.c | 14 +++++++++
src/callproc.c | 16 ++++++++++
6 files changed, 136 insertions(+), 4 deletions(-)
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index 08897d3f97e..e1c644d6043 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -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
diff --git a/exec/exec1.c b/exec/exec1.c
index 835bf8e72b9..d77ca8adf54 100644
--- a/exec/exec1.c
+++ b/exec/exec1.c
@@ -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. */
diff --git a/src/android.c b/src/android.c
index 3798758ff16..ce8f277e120 100644
--- a/src/android.c
+++ b/src/android.c
@@ -6514,6 +6514,89 @@ android_free_cursor (android_cursor cursor)
android_destroy_handle (cursor);
}
+
+
+/* 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;
+}
+
+
+
#else /* ANDROID_STUBIFY */
/* X emulation functions for Android. */
diff --git a/src/android.h b/src/android.h
index 24666aaf989..62d420d4cce 100644
--- a/src/android.h
+++ b/src/android.h
@@ -190,6 +190,11 @@ extern void android_write_event (union android_event *);
extern unsigned int event_serial;
+
+
+/* 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
diff --git a/src/androidfns.c b/src/androidfns.c
index 3367ebdf755..3bd34edd5b9 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -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);
diff --git a/src/callproc.c b/src/callproc.c
index a1811a3bb23..015b52bc9bc 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -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