1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-25 07:28:20 +00:00

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.
This commit is contained in:
Po Lu 2023-05-01 09:31:58 +08:00
parent 9a7c645dd4
commit 5550816f59
6 changed files with 136 additions and 4 deletions

View 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

View 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. */

View File

@ -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. */

View File

@ -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

View 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);

View 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