aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/join.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/join.c')
-rw-r--r--src/firejail/join.c175
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
27static int apply_caps = 0; 28static int apply_caps = 0;
28static uint64_t caps = 0; 29static uint64_t caps = 0;
29static int apply_seccomp = 0; 30static int apply_seccomp = 0;
30#define BUFLEN 4096 31#define BUFLEN 4096
31 32
33static void signal_handler(int sig){
34 flush_stdin();
35
36 exit(sig);
37}
38
32static void extract_command(int argc, char **argv, int index) { 39static 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
182void 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
197void join(pid_t pid, int argc, char **argv, int index) { 176void 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