From 4df931507606a0a1ee2d0e916d027d01c801d926 Mon Sep 17 00:00:00 2001 From: smitsohu Date: Mon, 28 Dec 2020 21:06:52 +0100 Subject: join: add fexecve fallback for shells Allows users to join a sandbox and get a shell even if there is none in the sandbox mount namespace. There are few limitations: 1. This will fail with scripted shells (see man 3 fexecve for an explanation) 2. Shell process names are not user friendly --- src/firejail/firejail.h | 2 +- src/firejail/join.c | 32 ++++++++++++++++++++++++++++---- src/firejail/main.c | 2 +- src/firejail/no_sandbox.c | 4 ++-- src/firejail/sandbox.c | 41 ++++++++++++++++++++++------------------- 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 6c0ebcd43..80987e494 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -372,7 +372,7 @@ char *guess_shell(void); // sandbox.c #define SANDBOX_DONE '1' int sandbox(void* sandbox_arg); -void start_application(int no_sandbox, char *set_sandbox_status) __attribute__((noreturn)); +void start_application(int no_sandbox, int fd, char *set_sandbox_status) __attribute__((noreturn)); void set_apparmor(void); // network_main.c diff --git a/src/firejail/join.c b/src/firejail/join.c index ca8b8c4bf..d2f802add 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c @@ -20,10 +20,14 @@ #include "firejail.h" #include #include -#include #include #include +#include +#ifndef O_PATH +#define O_PATH 010000000 +#endif + #include #ifndef PR_SET_NO_NEW_PRIVS #define PR_SET_NO_NEW_PRIVS 38 @@ -299,6 +303,21 @@ static void extract_umask(pid_t pid) { fclose(fp); } +static int open_shell(void) { + EUID_ASSERT(); + assert(cfg.shell); + + if (arg_debug) + printf("Opening shell %s\n", cfg.shell); + // file descriptor will leak if not opened with O_CLOEXEC !! + int fd = open(cfg.shell, O_PATH|O_CLOEXEC); + if (fd == -1) { + fprintf(stderr, "Error: cannot open shell %s\n", cfg.shell); + exit(1); + } + return fd; +} + // return false if the sandbox identified by pid is not fully set up yet or if // it is no firejail sandbox at all, return true if the sandbox is complete bool is_ready_for_join(const pid_t pid) { @@ -391,6 +410,10 @@ void join(pid_t pid, int argc, char **argv, int index) { extract_x11_display(parent); + int shfd = -1; + if (!arg_shell_none) + shfd = open_shell(); + EUID_ROOT(); // in user mode set caps seccomp, cpu, cgroup, etc if (getuid() != 0) { @@ -522,10 +545,9 @@ void join(pid_t pid, int argc, char **argv, int index) { extract_command(argc, argv, index); if (cfg.command_line == NULL) { assert(cfg.shell); - cfg.command_line = cfg.shell; cfg.window_title = cfg.shell; } - if (arg_debug) + else if (arg_debug) printf("Extracted command #%s#\n", cfg.command_line); // set cpu affinity @@ -554,11 +576,13 @@ void join(pid_t pid, int argc, char **argv, int index) { dbus_set_system_bus_env(); #endif - start_application(0, NULL); + start_application(0, shfd, NULL); __builtin_unreachable(); } EUID_USER(); + if (shfd != -1) + close(shfd); int status = 0; //***************************** diff --git a/src/firejail/main.c b/src/firejail/main.c index b8ed29ece..213d5c014 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -2786,7 +2786,7 @@ int main(int argc, char **argv, char **envp) { // build the sandbox command if (prog_index == -1 && cfg.shell) { - cfg.command_line = cfg.shell; + assert(cfg.command_line == NULL); // runs cfg.shell cfg.window_title = cfg.shell; cfg.command_name = cfg.shell; } diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c index 01df77ee6..22f36ef07 100644 --- a/src/firejail/no_sandbox.c +++ b/src/firejail/no_sandbox.c @@ -211,7 +211,7 @@ void run_no_sandbox(int argc, char **argv) { } if (prog_index == 0) { - cfg.command_line = cfg.shell; + assert(cfg.command_line == NULL); // runs cfg.shell cfg.window_title = cfg.shell; } else { build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); @@ -230,5 +230,5 @@ void run_no_sandbox(int argc, char **argv) { arg_quiet = 1; - start_application(1, NULL); + start_application(1, -1, NULL); } diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 5c7b5e556..991e5b2f2 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -461,7 +461,7 @@ static int ok_to_run(const char *program) { return 0; } -void start_application(int no_sandbox, char *set_sandbox_status) { +void start_application(int no_sandbox, int fd, char *set_sandbox_status) { // set environment if (no_sandbox == 0) { env_defaults(); @@ -471,7 +471,7 @@ void start_application(int no_sandbox, char *set_sandbox_status) { umask(orig_umask); if (arg_debug) { - printf("starting application\n"); + printf("Starting application\n"); printf("LD_PRELOAD=%s\n", getenv("LD_PRELOAD")); } @@ -488,9 +488,6 @@ void start_application(int no_sandbox, char *set_sandbox_status) { if (set_sandbox_status) *set_sandbox_status = SANDBOX_DONE; execl(arg_audit_prog, arg_audit_prog, NULL); - - perror("execl"); - exit(1); } //**************************************** // start the program without using a shell @@ -532,35 +529,37 @@ void start_application(int no_sandbox, char *set_sandbox_status) { //**************************************** else { assert(cfg.shell); - assert(cfg.command_line); char *arg[5]; int index = 0; arg[index++] = cfg.shell; - if (login_shell) { - arg[index++] = "-l"; - if (arg_debug) - printf("Starting %s login shell\n", cfg.shell); - } else { - arg[index++] = "-c"; + if (cfg.command_line) { if (arg_debug) printf("Running %s command through %s\n", cfg.command_line, cfg.shell); + arg[index++] = "-c"; if (arg_doubledash) arg[index++] = "--"; arg[index++] = cfg.command_line; } - arg[index] = NULL; + else if (login_shell) { + if (arg_debug) + printf("Starting %s login shell\n", cfg.shell); + arg[index++] = "-l"; + } + else if (arg_debug) + printf("Starting %s shell\n", cfg.shell); + assert(index < 5); + arg[index] = NULL; if (arg_debug) { char *msg; - if (asprintf(&msg, "sandbox %d, execvp into %s", sandbox_pid, cfg.command_line) == -1) + if (asprintf(&msg, "sandbox %d, execvp into %s", + sandbox_pid, cfg.command_line ? cfg.command_line : cfg.shell) == -1) errExit("asprintf"); logmsg(msg); free(msg); - } - if (arg_debug) { int i; for (i = 0; i < 5; i++) { if (arg[i] == NULL) @@ -580,10 +579,14 @@ void start_application(int no_sandbox, char *set_sandbox_status) { if (set_sandbox_status) *set_sandbox_status = SANDBOX_DONE; execvp(arg[0], arg); + + // join sandbox without shell in the mount namespace + if (fd > -1) + fexecve(fd, arg, environ); } - perror("execvp"); - exit(1); // it should never get here!!! + perror("Cannot start application"); + exit(1); } static void enforce_filters(void) { @@ -1223,7 +1226,7 @@ int sandbox(void* sandbox_arg) { set_nice(cfg.nice); set_rlimits(); - start_application(0, set_sandbox_status); + start_application(0, -1, set_sandbox_status); } munmap(set_sandbox_status, 1); -- cgit v1.2.3-70-g09d2