aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/main.c')
-rw-r--r--src/firejail/main.c117
1 files changed, 79 insertions, 38 deletions
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 2ae3213ee..6fd011868 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -85,13 +85,14 @@ int arg_shell_none = 0; // run the program directly without a shell
85int arg_private_dev = 0; // private dev directory 85int arg_private_dev = 0; // private dev directory
86int arg_private_etc = 0; // private etc directory 86int arg_private_etc = 0; // private etc directory
87int arg_private_bin = 0; // private bin directory 87int arg_private_bin = 0; // private bin directory
88int arg_private_tmp = 0; // private tmp directory
88int arg_scan = 0; // arp-scan all interfaces 89int arg_scan = 0; // arp-scan all interfaces
89int arg_whitelist = 0; // whitelist commad 90int arg_whitelist = 0; // whitelist commad
90int arg_nosound = 0; // disable sound 91int arg_nosound = 0; // disable sound
91int arg_quiet = 0; // no output for scripting 92int arg_quiet = 0; // no output for scripting
92int arg_join_network = 0; // join only the network namespace 93int arg_join_network = 0; // join only the network namespace
93int arg_join_filesystem = 0; // join only the mount namespace 94int arg_join_filesystem = 0; // join only the mount namespace
94 95int arg_nice = 0; // nice value configured
95 96
96int parent_to_child_fds[2]; 97int parent_to_child_fds[2];
97int child_to_parent_fds[2]; 98int child_to_parent_fds[2];
@@ -107,7 +108,7 @@ static void myexit(int rv) {
107 printf("\nparent is shutting down, bye...\n"); 108 printf("\nparent is shutting down, bye...\n");
108 109
109 // delete sandbox files in shared memory 110 // delete sandbox files in shared memory
110 bandwidth_shm_del_file(sandbox_pid); // bandwidht file 111 bandwidth_shm_del_file(sandbox_pid); // bandwidth file
111 network_shm_del_file(sandbox_pid); // network map file 112 network_shm_del_file(sandbox_pid); // network map file
112 113
113 exit(rv); 114 exit(rv);
@@ -208,7 +209,7 @@ static void check_network(Bridge *br) {
208 } 209 }
209} 210}
210 211
211 212#ifdef HAVE_USERNS
212void check_user_namespace(void) { 213void check_user_namespace(void) {
213 if (getuid() == 0) { 214 if (getuid() == 0) {
214 fprintf(stderr, "Error: --noroot option cannot be used when starting the sandbox as root.\n"); 215 fprintf(stderr, "Error: --noroot option cannot be used when starting the sandbox as root.\n");
@@ -228,6 +229,7 @@ void check_user_namespace(void) {
228 arg_noroot = 0; 229 arg_noroot = 0;
229 } 230 }
230} 231}
232#endif
231 233
232// exit commands 234// exit commands
233static void run_cmd_and_exit(int i, int argc, char **argv) { 235static void run_cmd_and_exit(int i, int argc, char **argv) {
@@ -241,8 +243,24 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
241 } 243 }
242 else if (strcmp(argv[i], "--version") == 0) { 244 else if (strcmp(argv[i], "--version") == 0) {
243 printf("firejail version %s\n", VERSION); 245 printf("firejail version %s\n", VERSION);
246#ifndef HAVE_NETWORK
247 printf("Networking support is disabled.\n");
248#endif
249#ifndef HAVE_USERNS
250 printf("User namespace support is disabled.\n");
251#endif
252#ifndef HAVE_SECCOMP
253 printf("Seccomp-bpf support is disabled.\n");
254#endif
255#ifndef HAVE_BIND
256 printf("Bind support is disabled.\n");
257#endif
258#ifndef HAVE_CHROOT
259 printf("Chroot support is disabled.\n");
260#endif
244 exit(0); 261 exit(0);
245 } 262 }
263#ifdef HAVE_NETWORK
246 else if (strncmp(argv[i], "--bandwidth=", 12) == 0) { 264 else if (strncmp(argv[i], "--bandwidth=", 12) == 0) {
247 logargs(argc, argv); 265 logargs(argc, argv);
248 266
@@ -300,10 +318,10 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
300 if (read_pid(argv[i] + 12, &pid) == 0) 318 if (read_pid(argv[i] + 12, &pid) == 0)
301 bandwidth_pid(pid, cmd, dev, down, up); 319 bandwidth_pid(pid, cmd, dev, down, up);
302 else 320 else
303 bandwidth_name(argv[i] + 12, cmd, dev, down, up); 321 bandwidth_name(argv[i] + 12, cmd, dev, down, up);
304 exit(0); 322 exit(0);
305 } 323 }
306 324#endif
307 //************************************* 325 //*************************************
308 // independent commands - the program will exit! 326 // independent commands - the program will exit!
309 //************************************* 327 //*************************************
@@ -382,10 +400,12 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
382 top(); 400 top();
383 exit(0); 401 exit(0);
384 } 402 }
403#ifdef HAVE_NETWORK
385 else if (strcmp(argv[i], "--netstats") == 0) { 404 else if (strcmp(argv[i], "--netstats") == 0) {
386 netstats(); 405 netstats();
387 exit(0); 406 exit(0);
388 } 407 }
408#endif
389 else if (strncmp(argv[i], "--join=", 7) == 0) { 409 else if (strncmp(argv[i], "--join=", 7) == 0) {
390 logargs(argc, argv); 410 logargs(argc, argv);
391 411
@@ -397,6 +417,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
397 join_name(argv[i] + 7, cfg.homedir, argc, argv, i + 1); 417 join_name(argv[i] + 7, cfg.homedir, argc, argv, i + 1);
398 exit(0); 418 exit(0);
399 } 419 }
420#ifdef HAVE_NETWORK
400 else if (strncmp(argv[i], "--join-network=", 15) == 0) { 421 else if (strncmp(argv[i], "--join-network=", 15) == 0) {
401 logargs(argc, argv); 422 logargs(argc, argv);
402 arg_join_network = 1; 423 arg_join_network = 1;
@@ -413,6 +434,7 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
413 join_name(argv[i] + 15, cfg.homedir, argc, argv, i + 1); 434 join_name(argv[i] + 15, cfg.homedir, argc, argv, i + 1);
414 exit(0); 435 exit(0);
415 } 436 }
437#endif
416 else if (strncmp(argv[i], "--join-filesystem=", 18) == 0) { 438 else if (strncmp(argv[i], "--join-filesystem=", 18) == 0) {
417 logargs(argc, argv); 439 logargs(argc, argv);
418 arg_join_filesystem = 1; 440 arg_join_filesystem = 1;
@@ -459,8 +481,9 @@ int main(int argc, char **argv) {
459 int highest_errno = errno_highest_nr(); 481 int highest_errno = errno_highest_nr();
460#endif 482#endif
461 483
462 // check argv[0] symlink wrapper 484 // check argv[0] symlink wrapper if this is not a login shell
463 run_symlink(argc, argv); 485 if (*argv[0] != '-')
486 run_symlink(argc, argv);
464 487
465 488
466 // check if we already have a sandbox running 489 // check if we already have a sandbox running
@@ -514,6 +537,7 @@ int main(int argc, char **argv) {
514 else { 537 else {
515 // check --output option and execute it; 538 // check --output option and execute it;
516 check_output(argc, argv); // the function will not return if --output option was found 539 check_output(argc, argv); // the function will not return if --output option was found
540 check_user(argc, argv); // the function will not return if --user option was found
517 } 541 }
518 542
519 // parse arguments 543 // parse arguments
@@ -669,6 +693,10 @@ int main(int argc, char **argv) {
669 arg_ipc = 1; 693 arg_ipc = 1;
670 else if (strncmp(argv[i], "--cpu=", 6) == 0) 694 else if (strncmp(argv[i], "--cpu=", 6) == 0)
671 read_cpu_list(argv[i] + 6); 695 read_cpu_list(argv[i] + 6);
696 else if (strncmp(argv[i], "--nice=", 7) == 0) {
697 cfg.nice = atoi(argv[i] + 7);
698 arg_nice = 1;
699 }
672 else if (strncmp(argv[i], "--cgroup=", 9) == 0) { 700 else if (strncmp(argv[i], "--cgroup=", 9) == 0) {
673 if (arg_cgroup) { 701 if (arg_cgroup) {
674 fprintf(stderr, "Error: only a cgroup can be defined\n"); 702 fprintf(stderr, "Error: only a cgroup can be defined\n");
@@ -750,13 +778,18 @@ int main(int argc, char **argv) {
750 struct stat s; 778 struct stat s;
751 if (stat(dirname, &s) == -1) { 779 if (stat(dirname, &s) == -1) {
752 /* coverity[toctou] */ 780 /* coverity[toctou] */
753 if (mkdir(dirname, S_IRWXU | S_IRWXG | S_IRWXO)) 781 if (mkdir(dirname, 0700))
754 errExit("mkdir"); 782 errExit("mkdir");
755 if (chown(dirname, getuid(), getgid()) < 0) 783 if (chown(dirname, getuid(), getgid()) < 0)
756 errExit("chown"); 784 errExit("chown");
757 if (chmod(dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) < 0) 785 if (chmod(dirname, 0700) < 0)
758 errExit("chmod"); 786 errExit("chmod");
759 } 787 }
788 else if (is_link(dirname)) {
789 fprintf(stderr, "Error: invalid ~/.firejail directory\n");
790 exit(1);
791 }
792
760 free(dirname); 793 free(dirname);
761 794
762 // check overlay directory 795 // check overlay directory
@@ -882,11 +915,6 @@ int main(int argc, char **argv) {
882 else if (strcmp(argv[i], "--private") == 0) 915 else if (strcmp(argv[i], "--private") == 0)
883 arg_private = 1; 916 arg_private = 1;
884 else if (strncmp(argv[i], "--private=", 10) == 0) { 917 else if (strncmp(argv[i], "--private=", 10) == 0) {
885 if (cfg.home_private_keep) {
886 fprintf(stderr, "Error: a private list of files was already defined with --private-home option.\n");
887 exit(1);
888 }
889
890 // extract private home dirname 918 // extract private home dirname
891 cfg.home_private = argv[i] + 10; 919 cfg.home_private = argv[i] + 10;
892 if (*cfg.home_private == '\0') { 920 if (*cfg.home_private == '\0') {
@@ -896,26 +924,11 @@ int main(int argc, char **argv) {
896 fs_check_private_dir(); 924 fs_check_private_dir();
897 arg_private = 1; 925 arg_private = 1;
898 } 926 }
899 else if (strncmp(argv[i], "--private-home=", 15) == 0) {
900 if (cfg.home_private) {
901 fprintf(stderr, "Error: a private home directory was already defined with --private option.\n");
902 exit(1);
903 }
904
905 // extract private home dirname
906 cfg.home_private_keep = argv[i] + 15;
907 if (*cfg.home_private_keep == '\0') {
908 fprintf(stderr, "Error: invalid private-home option\n");
909 exit(1);
910 }
911 fs_check_home_list();
912 arg_private = 1;
913 }
914 else if (strcmp(argv[i], "--private-dev") == 0) { 927 else if (strcmp(argv[i], "--private-dev") == 0) {
915 arg_private_dev = 1; 928 arg_private_dev = 1;
916 } 929 }
917 else if (strncmp(argv[i], "--private-etc=", 14) == 0) { 930 else if (strncmp(argv[i], "--private-etc=", 14) == 0) {
918 // extract private etc dirname 931 // extract private etc list
919 cfg.etc_private_keep = argv[i] + 14; 932 cfg.etc_private_keep = argv[i] + 14;
920 if (*cfg.etc_private_keep == '\0') { 933 if (*cfg.etc_private_keep == '\0') {
921 fprintf(stderr, "Error: invalid private-etc option\n"); 934 fprintf(stderr, "Error: invalid private-etc option\n");
@@ -930,7 +943,7 @@ int main(int argc, char **argv) {
930 } 943 }
931 } 944 }
932 else if (strncmp(argv[i], "--private-bin=", 14) == 0) { 945 else if (strncmp(argv[i], "--private-bin=", 14) == 0) {
933 // extract private etc dirname 946 // extract private bin list
934 cfg.bin_private_keep = argv[i] + 14; 947 cfg.bin_private_keep = argv[i] + 14;
935 if (*cfg.bin_private_keep == '\0') { 948 if (*cfg.bin_private_keep == '\0') {
936 fprintf(stderr, "Error: invalid private-bin option\n"); 949 fprintf(stderr, "Error: invalid private-bin option\n");
@@ -939,8 +952,9 @@ int main(int argc, char **argv) {
939 fs_check_bin_list(); 952 fs_check_bin_list();
940 arg_private_bin = 1; 953 arg_private_bin = 1;
941 } 954 }
942 955 else if (strcmp(argv[i], "--private-tmp") == 0) {
943 956 arg_private_tmp = 1;
957 }
944 958
945 //************************************* 959 //*************************************
946 // hostname, etc 960 // hostname, etc
@@ -961,9 +975,11 @@ int main(int argc, char **argv) {
961 } 975 }
962 else if (strcmp(argv[i], "--nogroups") == 0) 976 else if (strcmp(argv[i], "--nogroups") == 0)
963 arg_nogroups = 1; 977 arg_nogroups = 1;
978#ifdef HAVE_USERNS
964 else if (strcmp(argv[i], "--noroot") == 0) { 979 else if (strcmp(argv[i], "--noroot") == 0) {
965 check_user_namespace(); 980 check_user_namespace();
966 } 981 }
982#endif
967 else if (strncmp(argv[i], "--env=", 6) == 0) 983 else if (strncmp(argv[i], "--env=", 6) == 0)
968 env_store(argv[i] + 6); 984 env_store(argv[i] + 6);
969 else if (strncmp(argv[i], "--nosound", 9) == 0) { 985 else if (strncmp(argv[i], "--nosound", 9) == 0) {
@@ -974,6 +990,7 @@ int main(int argc, char **argv) {
974 //************************************* 990 //*************************************
975 // network 991 // network
976 //************************************* 992 //*************************************
993#ifdef HAVE_NETWORK
977 else if (strncmp(argv[i], "--interface=", 12) == 0) { 994 else if (strncmp(argv[i], "--interface=", 12) == 0) {
978 // checks 995 // checks
979 if (arg_nonetwork) { 996 if (arg_nonetwork) {
@@ -1163,6 +1180,7 @@ int main(int argc, char **argv) {
1163 return 1; 1180 return 1;
1164 } 1181 }
1165 } 1182 }
1183#endif
1166 else if (strncmp(argv[i], "--dns=", 6) == 0) { 1184 else if (strncmp(argv[i], "--dns=", 6) == 0) {
1167 uint32_t dns; 1185 uint32_t dns;
1168 if (atoip(argv[i] + 6, &dns)) { 1186 if (atoip(argv[i] + 6, &dns)) {
@@ -1181,6 +1199,7 @@ int main(int argc, char **argv) {
1181 return 1; 1199 return 1;
1182 } 1200 }
1183 } 1201 }
1202#ifdef HAVE_NETWORK
1184 else if (strcmp(argv[i], "--netfilter") == 0) 1203 else if (strcmp(argv[i], "--netfilter") == 0)
1185 arg_netfilter = 1; 1204 arg_netfilter = 1;
1186 else if (strncmp(argv[i], "--netfilter=", 12) == 0) { 1205 else if (strncmp(argv[i], "--netfilter=", 12) == 0) {
@@ -1193,7 +1212,7 @@ int main(int argc, char **argv) {
1193 arg_netfilter6_file = argv[i] + 13; 1212 arg_netfilter6_file = argv[i] + 13;
1194 check_netfilter_file(arg_netfilter6_file); 1213 check_netfilter_file(arg_netfilter6_file);
1195 } 1214 }
1196 1215#endif
1197 //************************************* 1216 //*************************************
1198 // command 1217 // command
1199 //************************************* 1218 //*************************************
@@ -1315,18 +1334,22 @@ int main(int argc, char **argv) {
1315 // build the sandbox command 1334 // build the sandbox command
1316 if (prog_index == -1 && arg_zsh) { 1335 if (prog_index == -1 && arg_zsh) {
1317 cfg.command_line = "/usr/bin/zsh"; 1336 cfg.command_line = "/usr/bin/zsh";
1337 cfg.window_title = "/usr/bin/zsh";
1318 cfg.command_name = "zsh"; 1338 cfg.command_name = "zsh";
1319 } 1339 }
1320 else if (prog_index == -1 && arg_csh) { 1340 else if (prog_index == -1 && arg_csh) {
1321 cfg.command_line = "/bin/csh"; 1341 cfg.command_line = "/bin/csh";
1342 cfg.window_title = "/bin/csh";
1322 cfg.command_name = "csh"; 1343 cfg.command_name = "csh";
1323 } 1344 }
1324 else if (prog_index == -1 && cfg.shell) { 1345 else if (prog_index == -1 && cfg.shell) {
1325 cfg.command_line = cfg.shell; 1346 cfg.command_line = cfg.shell;
1347 cfg.window_title = cfg.shell;
1326 cfg.command_name = cfg.shell; 1348 cfg.command_name = cfg.shell;
1327 } 1349 }
1328 else if (prog_index == -1) { 1350 else if (prog_index == -1) {
1329 cfg.command_line = "/bin/bash"; 1351 cfg.command_line = "/bin/bash";
1352 cfg.window_title = "/bin/bash";
1330 cfg.command_name = "bash"; 1353 cfg.command_name = "bash";
1331 } 1354 }
1332 else { 1355 else {
@@ -1341,16 +1364,24 @@ int main(int argc, char **argv) {
1341 cfg.command_line = malloc(len + 1); // + '\0' 1364 cfg.command_line = malloc(len + 1); // + '\0'
1342 if (!cfg.command_line) 1365 if (!cfg.command_line)
1343 errExit("malloc"); 1366 errExit("malloc");
1344 char *ptr = cfg.command_line; 1367 cfg.window_title = malloc(len + 1); // + '\0'
1368 if (!cfg.window_title)
1369 errExit("malloc");
1370
1371 char *ptr1 = cfg.command_line;
1372 char *ptr2 = cfg.window_title;
1345 for (i = 0; i < argcnt; i++) { 1373 for (i = 0; i < argcnt; i++) {
1346 // detect bash commands 1374 // detect bash commands
1347 if (strstr(argv[i + prog_index], "&&") || strstr(argv[i + prog_index], "||")) { 1375 if (strstr(argv[i + prog_index], "&&") || strstr(argv[i + prog_index], "||")) {
1348 sprintf(ptr, "%s ", argv[i + prog_index]); 1376 sprintf(ptr1, "%s ", argv[i + prog_index]);
1349 } 1377 }
1350 else { 1378 else {
1351 sprintf(ptr, "\"%s\" ", argv[i + prog_index]); 1379 sprintf(ptr1, "\"%s\" ", argv[i + prog_index]);
1352 } 1380 }
1353 ptr += strlen(ptr); 1381 sprintf(ptr2, "%s ", argv[i + prog_index]);
1382
1383 ptr1 += strlen(ptr1);
1384 ptr2 += strlen(ptr2);
1354 } 1385 }
1355 } 1386 }
1356 1387
@@ -1582,6 +1613,16 @@ int main(int argc, char **argv) {
1582 free(cfg.seccomp_list_errno); 1613 free(cfg.seccomp_list_errno);
1583 } 1614 }
1584#endif 1615#endif
1616 if (cfg.profile) {
1617 ProfileEntry *prf = cfg.profile;
1618 while (prf != NULL) {
1619 ProfileEntry *next = prf->next;
1620 free(prf->data);
1621 free(prf->link);
1622 free(prf);
1623 prf = next;
1624 }
1625 }
1585 1626
1586 myexit(0); 1627 myexit(0);
1587 1628