diff options
Diffstat (limited to 'src/firejail/main.c')
-rw-r--r-- | src/firejail/main.c | 117 |
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 | |||
85 | int arg_private_dev = 0; // private dev directory | 85 | int arg_private_dev = 0; // private dev directory |
86 | int arg_private_etc = 0; // private etc directory | 86 | int arg_private_etc = 0; // private etc directory |
87 | int arg_private_bin = 0; // private bin directory | 87 | int arg_private_bin = 0; // private bin directory |
88 | int arg_private_tmp = 0; // private tmp directory | ||
88 | int arg_scan = 0; // arp-scan all interfaces | 89 | int arg_scan = 0; // arp-scan all interfaces |
89 | int arg_whitelist = 0; // whitelist commad | 90 | int arg_whitelist = 0; // whitelist commad |
90 | int arg_nosound = 0; // disable sound | 91 | int arg_nosound = 0; // disable sound |
91 | int arg_quiet = 0; // no output for scripting | 92 | int arg_quiet = 0; // no output for scripting |
92 | int arg_join_network = 0; // join only the network namespace | 93 | int arg_join_network = 0; // join only the network namespace |
93 | int arg_join_filesystem = 0; // join only the mount namespace | 94 | int arg_join_filesystem = 0; // join only the mount namespace |
94 | 95 | int arg_nice = 0; // nice value configured | |
95 | 96 | ||
96 | int parent_to_child_fds[2]; | 97 | int parent_to_child_fds[2]; |
97 | int child_to_parent_fds[2]; | 98 | int 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 | |
212 | void check_user_namespace(void) { | 213 | void 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 |
233 | static void run_cmd_and_exit(int i, int argc, char **argv) { | 235 | static 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 | ||