Skip to content

Commit

Permalink
join: add fexecve fallback for shells
Browse files Browse the repository at this point in the history
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
  • Loading branch information
smitsohu committed Dec 29, 2020
1 parent f3056a8 commit 1eb3d66
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
26 changes: 23 additions & 3 deletions src/firejail/join.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
//*****************************
Expand Down
2 changes: 1 addition & 1 deletion src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
4 changes: 2 additions & 2 deletions src/firejail/no_sandbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -230,5 +230,5 @@ void run_no_sandbox(int argc, char **argv) {

arg_quiet = 1;

start_application(1, NULL);
start_application(1, -1, NULL);
}
41 changes: 22 additions & 19 deletions src/firejail/sandbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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"));
}

Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1eb3d66

Please sign in to comment.