diff options
Diffstat (limited to 'src/firejail/join.c')
-rw-r--r-- | src/firejail/join.c | 175 |
1 files changed, 79 insertions, 96 deletions
diff --git a/src/firejail/join.c b/src/firejail/join.c index 98e140ce4..628002d35 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -23,12 +23,19 @@ | |||
23 | #include <fcntl.h> | 23 | #include <fcntl.h> |
24 | #include <unistd.h> | 24 | #include <unistd.h> |
25 | #include <sys/prctl.h> | 25 | #include <sys/prctl.h> |
26 | #include <errno.h> | ||
26 | 27 | ||
27 | static int apply_caps = 0; | 28 | static int apply_caps = 0; |
28 | static uint64_t caps = 0; | 29 | static uint64_t caps = 0; |
29 | static int apply_seccomp = 0; | 30 | static int apply_seccomp = 0; |
30 | #define BUFLEN 4096 | 31 | #define BUFLEN 4096 |
31 | 32 | ||
33 | static void signal_handler(int sig){ | ||
34 | flush_stdin(); | ||
35 | |||
36 | exit(sig); | ||
37 | } | ||
38 | |||
32 | static void extract_command(int argc, char **argv, int index) { | 39 | static void extract_command(int argc, char **argv, int index) { |
33 | EUID_ASSERT(); | 40 | EUID_ASSERT(); |
34 | if (index >= argc) | 41 | if (index >= argc) |
@@ -48,22 +55,9 @@ static void extract_command(int argc, char **argv, int index) { | |||
48 | exit(1); | 55 | exit(1); |
49 | } | 56 | } |
50 | 57 | ||
51 | |||
52 | int len = 0; | ||
53 | int i; | ||
54 | // calculate command length | ||
55 | for (i = index; i < argc; i++) { | ||
56 | len += strlen(argv[i]) + 1; | ||
57 | } | ||
58 | assert(len > 0); | ||
59 | |||
60 | // build command | 58 | // build command |
61 | cfg.command_line = malloc(len + 1); | 59 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, index); |
62 | *cfg.command_line = '\0'; | 60 | |
63 | for (i = index; i < argc; i++) { | ||
64 | strcat(cfg.command_line, argv[i]); | ||
65 | strcat(cfg.command_line, " "); | ||
66 | } | ||
67 | if (arg_debug) | 61 | if (arg_debug) |
68 | printf("Extracted command #%s#\n", cfg.command_line); | 62 | printf("Extracted command #%s#\n", cfg.command_line); |
69 | } | 63 | } |
@@ -134,7 +128,7 @@ static void extract_caps_seccomp(pid_t pid) { | |||
134 | break; | 128 | break; |
135 | } | 129 | } |
136 | else if (strncmp(buf, "CapBnd:", 7) == 0) { | 130 | else if (strncmp(buf, "CapBnd:", 7) == 0) { |
137 | char *ptr = buf + 8; | 131 | char *ptr = buf + 7; |
138 | unsigned long long val; | 132 | unsigned long long val; |
139 | sscanf(ptr, "%llx", &val); | 133 | sscanf(ptr, "%llx", &val); |
140 | apply_caps = 1; | 134 | apply_caps = 1; |
@@ -179,26 +173,12 @@ static void extract_user_namespace(pid_t pid) { | |||
179 | free(uidmap); | 173 | free(uidmap); |
180 | } | 174 | } |
181 | 175 | ||
182 | void join_name(const char *name, int argc, char **argv, int index) { | ||
183 | EUID_ASSERT(); | ||
184 | if (!name || strlen(name) == 0) { | ||
185 | fprintf(stderr, "Error: invalid sandbox name\n"); | ||
186 | exit(1); | ||
187 | } | ||
188 | |||
189 | pid_t pid; | ||
190 | if (name2pid(name, &pid)) { | ||
191 | fprintf(stderr, "Error: cannot find sandbox %s\n", name); | ||
192 | exit(1); | ||
193 | } | ||
194 | join(pid, argc, argv, index); | ||
195 | } | ||
196 | |||
197 | void join(pid_t pid, int argc, char **argv, int index) { | 176 | void join(pid_t pid, int argc, char **argv, int index) { |
198 | EUID_ASSERT(); | 177 | EUID_ASSERT(); |
199 | char *homedir = cfg.homedir; | 178 | char *homedir = cfg.homedir; |
200 | 179 | ||
201 | extract_command(argc, argv, index); | 180 | extract_command(argc, argv, index); |
181 | signal (SIGTERM, signal_handler); | ||
202 | 182 | ||
203 | // if the pid is that of a firejail process, use the pid of the first child process | 183 | // if the pid is that of a firejail process, use the pid of the first child process |
204 | EUID_ROOT(); | 184 | EUID_ROOT(); |
@@ -249,15 +229,11 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
249 | exit(1); | 229 | exit(1); |
250 | } | 230 | } |
251 | else { | 231 | else { |
252 | if (join_namespace(pid, "ipc")) | 232 | if (join_namespace(pid, "ipc") || |
253 | exit(1); | 233 | join_namespace(pid, "net") || |
254 | if (join_namespace(pid, "net")) | 234 | join_namespace(pid, "pid") || |
255 | exit(1); | 235 | join_namespace(pid, "uts") || |
256 | if (join_namespace(pid, "pid")) | 236 | join_namespace(pid, "mnt")) |
257 | exit(1); | ||
258 | if (join_namespace(pid, "uts")) | ||
259 | exit(1); | ||
260 | if (join_namespace(pid, "mnt")) | ||
261 | exit(1); | 237 | exit(1); |
262 | } | 238 | } |
263 | 239 | ||
@@ -297,19 +273,18 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
297 | if (apply_caps == 1) // not available for uid 0 | 273 | if (apply_caps == 1) // not available for uid 0 |
298 | caps_set(caps); | 274 | caps_set(caps); |
299 | #ifdef HAVE_SECCOMP | 275 | #ifdef HAVE_SECCOMP |
300 | // set protocol filter | 276 | // read cfg.protocol from file |
301 | if (getuid() != 0) | 277 | if (getuid() != 0) |
302 | protocol_filter_load(RUN_PROTOCOL_CFG); | 278 | protocol_filter_load(RUN_PROTOCOL_CFG); |
303 | if (cfg.protocol) { // not available for uid 0 | 279 | if (cfg.protocol) { // not available for uid 0 |
304 | protocol_filter(); | 280 | seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter |
305 | } | 281 | } |
306 | 282 | ||
307 | // set seccomp filter | 283 | // set seccomp filter |
308 | if (apply_seccomp == 1) // not available for uid 0 | 284 | if (apply_seccomp == 1) // not available for uid 0 |
309 | seccomp_set(); | 285 | seccomp_load(RUN_SECCOMP_CFG); |
310 | |||
311 | #endif | 286 | #endif |
312 | 287 | ||
313 | // fix qt 4.8 | 288 | // fix qt 4.8 |
314 | if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0) | 289 | if (setenv("QT_X11_NO_MITSHM", "1", 1) < 0) |
315 | errExit("setenv"); | 290 | errExit("setenv"); |
@@ -322,76 +297,84 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
322 | printf("Joining user namespace\n"); | 297 | printf("Joining user namespace\n"); |
323 | if (join_namespace(1, "user")) | 298 | if (join_namespace(1, "user")) |
324 | exit(1); | 299 | exit(1); |
300 | |||
301 | // user namespace resets capabilities | ||
302 | // set caps filter | ||
303 | if (apply_caps == 1) // not available for uid 0 | ||
304 | caps_set(caps); | ||
325 | } | 305 | } |
326 | else | 306 | else |
327 | drop_privs(arg_nogroups); // nogroups not available for uid 0 | 307 | drop_privs(arg_nogroups); // nogroups not available for uid 0 |
328 | 308 | ||
309 | |||
329 | // set prompt color to green | 310 | // set prompt color to green |
330 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' | 311 | char *prompt = getenv("FIREJAIL_PROMPT"); |
331 | if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) | 312 | if (prompt && strcmp(prompt, "yes") == 0) { |
332 | errExit("setenv"); | 313 | //export PS1='\[\e[1;32m\][\u@\h \W]\$\[\e[0m\] ' |
314 | if (setenv("PROMPT_COMMAND", "export PS1=\"\\[\\e[1;32m\\][\\u@\\h \\W]\\$\\[\\e[0m\\] \"", 1) < 0) | ||
315 | errExit("setenv"); | ||
316 | } | ||
317 | |||
318 | // set nice | ||
319 | if (arg_nice) { | ||
320 | errno = 0; | ||
321 | int rv = nice(cfg.nice); | ||
322 | (void) rv; | ||
323 | if (errno) { | ||
324 | fprintf(stderr, "Warning: cannot set nice value\n"); | ||
325 | errno = 0; | ||
326 | } | ||
327 | } | ||
333 | 328 | ||
334 | // run cmdline trough /bin/bash | 329 | // run cmdline trough shell |
335 | if (cfg.command_line == NULL) { | 330 | if (cfg.command_line == NULL) { |
331 | // if the sandbox was started with --shell=none, it is possible we don't have a shell | ||
332 | // inside the sandbox | ||
333 | if (cfg.shell == NULL) { | ||
334 | cfg.shell = guess_shell(); | ||
335 | if (!cfg.shell) { | ||
336 | fprintf(stderr, "Error: no POSIX shell found, please use --shell command line option\n"); | ||
337 | exit(1); | ||
338 | } | ||
339 | } | ||
340 | |||
336 | struct stat s; | 341 | struct stat s; |
342 | if (stat(cfg.shell, &s) == -1) { | ||
343 | fprintf(stderr, "Error: %s shell not found inside the sandbox\n", cfg.shell); | ||
344 | exit(1); | ||
345 | } | ||
337 | 346 | ||
338 | // replace the process with a shell | 347 | cfg.command_line = cfg.shell; |
339 | if (stat("/bin/bash", &s) == 0) | 348 | cfg.window_title = cfg.shell; |
340 | execlp("/bin/bash", "/bin/bash", NULL); | ||
341 | else if (stat("/usr/bin/zsh", &s) == 0) | ||
342 | execlp("/usr/bin/zsh", "/usr/bin/zsh", NULL); | ||
343 | else if (stat("/bin/csh", &s) == 0) | ||
344 | execlp("/bin/csh", "/bin/csh", NULL); | ||
345 | else if (stat("/bin/sh", &s) == 0) | ||
346 | execlp("/bin/sh", "/bin/sh", NULL); | ||
347 | |||
348 | // no shell found, print an error and exit | ||
349 | fprintf(stderr, "Error: no POSIX shell found\n"); | ||
350 | sleep(5); | ||
351 | exit(1); | ||
352 | } | 349 | } |
353 | else { | ||
354 | // run the command supplied by the user | ||
355 | int cwd = 0; | ||
356 | if (cfg.cwd) { | ||
357 | if (chdir(cfg.cwd) == 0) | ||
358 | cwd = 1; | ||
359 | } | ||
360 | |||
361 | if (!cwd) { | ||
362 | if (chdir("/") < 0) | ||
363 | errExit("chdir"); | ||
364 | if (cfg.homedir) { | ||
365 | struct stat s; | ||
366 | if (stat(cfg.homedir, &s) == 0) { | ||
367 | if (chdir(cfg.homedir) < 0) | ||
368 | errExit("chdir"); | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | 350 | ||
373 | char *arg[5]; | 351 | int cwd = 0; |
374 | arg[0] = "/bin/bash"; | 352 | if (cfg.cwd) { |
375 | arg[1] = "-c"; | 353 | if (chdir(cfg.cwd) == 0) |
376 | if (arg_debug) | 354 | cwd = 1; |
377 | printf("Starting %s\n", cfg.command_line); | 355 | } |
378 | if (!arg_doubledash) { | 356 | |
379 | arg[2] = cfg.command_line; | 357 | if (!cwd) { |
380 | arg[3] = NULL; | 358 | if (chdir("/") < 0) |
381 | } | 359 | errExit("chdir"); |
382 | else { | 360 | if (cfg.homedir) { |
383 | arg[2] = "--"; | 361 | struct stat s; |
384 | arg[3] = cfg.command_line; | 362 | if (stat(cfg.homedir, &s) == 0) { |
385 | arg[4] = NULL; | 363 | /* coverity[toctou] */ |
364 | if (chdir(cfg.homedir) < 0) | ||
365 | errExit("chdir"); | ||
366 | } | ||
386 | } | 367 | } |
387 | execvp("/bin/bash", arg); | ||
388 | } | 368 | } |
389 | 369 | ||
370 | start_application(); | ||
371 | |||
390 | // it will never get here!!! | 372 | // it will never get here!!! |
391 | } | 373 | } |
392 | 374 | ||
393 | // wait for the child to finish | 375 | // wait for the child to finish |
394 | waitpid(child, NULL, 0); | 376 | waitpid(child, NULL, 0); |
377 | flush_stdin(); | ||
395 | exit(0); | 378 | exit(0); |
396 | } | 379 | } |
397 | 380 | ||