diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 6c0ebcd4335..80987e4940e 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 ca8b8c4bf01..d255b72c4a7 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c @@ -299,6 +299,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 +406,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 +541,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 +572,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 b8ed29eceed..213d5c01453 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 01df77ee679..22f36ef0703 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 5c7b5e55682..991e5b2f260 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);