diff options
author | netblue30 <netblue30@yahoo.com> | 2018-01-31 09:22:36 -0500 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2018-01-31 09:22:36 -0500 |
commit | 00b6315c91893c3316686fa9d71350690d506b56 (patch) | |
tree | 86a431ef4ca848240ff42ad4c4ec871b4a579516 | |
parent | fix cd/dvd for dragon (diff) | |
download | firejail-00b6315c91893c3316686fa9d71350690d506b56.tar.gz firejail-00b6315c91893c3316686fa9d71350690d506b56.tar.zst firejail-00b6315c91893c3316686fa9d71350690d506b56.zip |
overlay fixes and additional hardening
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs.c | 5 | ||||
-rw-r--r-- | src/firejail/main.c | 27 | ||||
-rw-r--r-- | src/firejail/profile.c | 12 | ||||
-rw-r--r-- | src/firejail/util.c | 46 |
5 files changed, 73 insertions, 19 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 97e740e6b..e8dc390d4 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -513,7 +513,7 @@ const char *gnu_basename(const char *path); | |||
513 | uid_t pid_get_uid(pid_t pid); | 513 | uid_t pid_get_uid(pid_t pid); |
514 | void invalid_filename(const char *fname, int globbing); | 514 | void invalid_filename(const char *fname, int globbing); |
515 | uid_t get_group_id(const char *group); | 515 | uid_t get_group_id(const char *group); |
516 | int remove_directory(const char *path); | 516 | int remove_overlay_directory(void); |
517 | void flush_stdin(void); | 517 | void flush_stdin(void); |
518 | void create_empty_dir_as_root(const char *dir, mode_t mode); | 518 | void create_empty_dir_as_root(const char *dir, mode_t mode); |
519 | void create_empty_file_as_root(const char *dir, mode_t mode); | 519 | void create_empty_file_as_root(const char *dir, mode_t mode); |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index ab2958593..25b52f5ce 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -725,7 +725,7 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
725 | errExit("asprintf"); | 725 | errExit("asprintf"); |
726 | 726 | ||
727 | if (is_link(dirname)) { | 727 | if (is_link(dirname)) { |
728 | fprintf(stderr, "Error: invalid ~/.firejail directory\n"); | 728 | fprintf(stderr, "Error: ~/.firejail directory is a symbolic link\n"); |
729 | exit(1); | 729 | exit(1); |
730 | } | 730 | } |
731 | if (stat(dirname, &s) == -1) { | 731 | if (stat(dirname, &s) == -1) { |
@@ -753,7 +753,7 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
753 | } | 753 | } |
754 | } | 754 | } |
755 | else if (s.st_uid != getuid()) { | 755 | else if (s.st_uid != getuid()) { |
756 | fprintf(stderr, "Error: invalid ~/.firejail directory\n"); | 756 | fprintf(stderr, "Error: ~/.firejail directory is not owned by the current user\n"); |
757 | exit(1); | 757 | exit(1); |
758 | } | 758 | } |
759 | free(dirname); | 759 | free(dirname); |
@@ -837,6 +837,7 @@ void fs_overlayfs(void) { | |||
837 | if (arg_overlay_keep) { | 837 | if (arg_overlay_keep) { |
838 | // set base for working and diff directories | 838 | // set base for working and diff directories |
839 | basedir = cfg.overlay_dir; | 839 | basedir = cfg.overlay_dir; |
840 | assert(basedir); | ||
840 | 841 | ||
841 | // does the overlay exist? | 842 | // does the overlay exist? |
842 | if (stat(basedir, &s) == 0) { | 843 | if (stat(basedir, &s) == 0) { |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 00e3729d0..7543c5f4b 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -314,16 +314,10 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
314 | #ifdef HAVE_OVERLAYFS | 314 | #ifdef HAVE_OVERLAYFS |
315 | else if (strcmp(argv[i], "--overlay-clean") == 0) { | 315 | else if (strcmp(argv[i], "--overlay-clean") == 0) { |
316 | if (checkcfg(CFG_OVERLAYFS)) { | 316 | if (checkcfg(CFG_OVERLAYFS)) { |
317 | char *path; | 317 | if (remove_overlay_directory()) { |
318 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | 318 | fprintf(stderr, "Error: cannot remove overlay directory\n"); |
319 | errExit("asprintf"); | 319 | exit(1); |
320 | EUID_ROOT(); | 320 | } |
321 | if (setreuid(0, 0) < 0 || | ||
322 | setregid(0, 0) < 0) | ||
323 | errExit("setreuid/setregid"); | ||
324 | errno = 0; | ||
325 | if (remove_directory(path)) | ||
326 | errExit("remove_directory"); | ||
327 | } | 321 | } |
328 | else | 322 | else |
329 | exit_err_feature("overlayfs"); | 323 | exit_err_feature("overlayfs"); |
@@ -1429,6 +1423,11 @@ int main(int argc, char **argv) { | |||
1429 | #ifdef HAVE_OVERLAYFS | 1423 | #ifdef HAVE_OVERLAYFS |
1430 | else if (strcmp(argv[i], "--overlay") == 0) { | 1424 | else if (strcmp(argv[i], "--overlay") == 0) { |
1431 | if (checkcfg(CFG_OVERLAYFS)) { | 1425 | if (checkcfg(CFG_OVERLAYFS)) { |
1426 | if (arg_overlay) { | ||
1427 | fprintf(stderr, "Error: only one overlay command is allowed\n"); | ||
1428 | exit(1); | ||
1429 | } | ||
1430 | |||
1432 | if (cfg.chrootdir) { | 1431 | if (cfg.chrootdir) { |
1433 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 1432 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
1434 | exit(1); | 1433 | exit(1); |
@@ -1453,6 +1452,10 @@ int main(int argc, char **argv) { | |||
1453 | } | 1452 | } |
1454 | else if (strncmp(argv[i], "--overlay-named=", 16) == 0) { | 1453 | else if (strncmp(argv[i], "--overlay-named=", 16) == 0) { |
1455 | if (checkcfg(CFG_OVERLAYFS)) { | 1454 | if (checkcfg(CFG_OVERLAYFS)) { |
1455 | if (arg_overlay) { | ||
1456 | fprintf(stderr, "Error: only one overlay command is allowed\n"); | ||
1457 | exit(1); | ||
1458 | } | ||
1456 | if (cfg.chrootdir) { | 1459 | if (cfg.chrootdir) { |
1457 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 1460 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
1458 | exit(1); | 1461 | exit(1); |
@@ -1485,6 +1488,10 @@ int main(int argc, char **argv) { | |||
1485 | } | 1488 | } |
1486 | else if (strcmp(argv[i], "--overlay-tmpfs") == 0) { | 1489 | else if (strcmp(argv[i], "--overlay-tmpfs") == 0) { |
1487 | if (checkcfg(CFG_OVERLAYFS)) { | 1490 | if (checkcfg(CFG_OVERLAYFS)) { |
1491 | if (arg_overlay) { | ||
1492 | fprintf(stderr, "Error: only one overlay command is allowed\n"); | ||
1493 | exit(1); | ||
1494 | } | ||
1488 | if (cfg.chrootdir) { | 1495 | if (cfg.chrootdir) { |
1489 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 1496 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
1490 | exit(1); | 1497 | exit(1); |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index d0c43d13e..77308b7ac 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -920,6 +920,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
920 | #ifdef HAVE_OVERLAYFS | 920 | #ifdef HAVE_OVERLAYFS |
921 | if (strncmp(ptr, "overlay-named ", 14) == 0) { | 921 | if (strncmp(ptr, "overlay-named ", 14) == 0) { |
922 | if (checkcfg(CFG_OVERLAYFS)) { | 922 | if (checkcfg(CFG_OVERLAYFS)) { |
923 | if (arg_overlay) { | ||
924 | fprintf(stderr, "Error: only one overlay command is allowed\n"); | ||
925 | exit(1); | ||
926 | } | ||
923 | if (cfg.chrootdir) { | 927 | if (cfg.chrootdir) { |
924 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 928 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
925 | exit(1); | 929 | exit(1); |
@@ -951,6 +955,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
951 | return 0; | 955 | return 0; |
952 | } else if (strcmp(ptr, "overlay-tmpfs") == 0) { | 956 | } else if (strcmp(ptr, "overlay-tmpfs") == 0) { |
953 | if (checkcfg(CFG_OVERLAYFS)) { | 957 | if (checkcfg(CFG_OVERLAYFS)) { |
958 | if (arg_overlay) { | ||
959 | fprintf(stderr, "Error: only one overlay command is allowed\n"); | ||
960 | exit(1); | ||
961 | } | ||
954 | if (cfg.chrootdir) { | 962 | if (cfg.chrootdir) { |
955 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 963 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
956 | exit(1); | 964 | exit(1); |
@@ -966,6 +974,10 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
966 | } | 974 | } |
967 | } else if (strcmp(ptr, "overlay") == 0) { | 975 | } else if (strcmp(ptr, "overlay") == 0) { |
968 | if (checkcfg(CFG_OVERLAYFS)) { | 976 | if (checkcfg(CFG_OVERLAYFS)) { |
977 | if (arg_overlay) { | ||
978 | fprintf(stderr, "Error: only one overlay command is allowed\n"); | ||
979 | exit(1); | ||
980 | } | ||
969 | if (cfg.chrootdir) { | 981 | if (cfg.chrootdir) { |
970 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 982 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
971 | exit(1); | 983 | exit(1); |
diff --git a/src/firejail/util.c b/src/firejail/util.c index 5a9f3a6e0..0adca5e33 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -800,21 +800,55 @@ uid_t get_group_id(const char *group) { | |||
800 | return gid; | 800 | return gid; |
801 | } | 801 | } |
802 | 802 | ||
803 | 803 | static int len_homedir = 0; | |
804 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { | 804 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { |
805 | (void) sb; | 805 | (void) sb; |
806 | (void) typeflag; | 806 | (void) typeflag; |
807 | (void) ftwbuf; | 807 | (void) ftwbuf; |
808 | assert(fpath); | ||
808 | 809 | ||
809 | int rv = remove(fpath); | 810 | if (len_homedir == 0) |
810 | if (rv) | 811 | len_homedir = strlen(cfg.homedir); |
811 | perror(fpath); | ||
812 | 812 | ||
813 | return rv; | 813 | char *rp = realpath(fpath, NULL); // this should never fail! |
814 | if (!rp) | ||
815 | return 1; | ||
816 | if (strncmp(rp, cfg.homedir, len_homedir) != 0) | ||
817 | return 1; | ||
818 | free(rp); | ||
819 | |||
820 | if (remove(fpath)) { // removes the link not the actual file | ||
821 | fprintf(stderr, "Error: cannot remove file %s\n", fpath); | ||
822 | exit(1); | ||
823 | } | ||
824 | |||
825 | return 0; | ||
814 | } | 826 | } |
815 | 827 | ||
816 | 828 | ||
817 | int remove_directory(const char *path) { | 829 | int remove_overlay_directory(void) { |
830 | sleep(1); | ||
831 | |||
832 | char *path; | ||
833 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | ||
834 | errExit("asprintf"); | ||
835 | |||
836 | // deal with obvious problems such as symlinks and root ownership | ||
837 | if (is_link(path)) { | ||
838 | fprintf(stderr, "Error: cannot follow symbolic link\n"); | ||
839 | exit(1); | ||
840 | } | ||
841 | if (access(path, R_OK | W_OK | X_OK) == -1) { | ||
842 | fprintf(stderr, "Error: cannot access ~/.firejail directory\n"); | ||
843 | exit(1); | ||
844 | } | ||
845 | |||
846 | EUID_ROOT(); | ||
847 | if (setreuid(0, 0) < 0 || | ||
848 | setregid(0, 0) < 0) | ||
849 | errExit("setreuid/setregid"); | ||
850 | errno = 0; | ||
851 | |||
818 | // FTW_PHYS - do not follow symbolic links | 852 | // FTW_PHYS - do not follow symbolic links |
819 | return nftw(path, remove_callback, 64, FTW_DEPTH | FTW_PHYS); | 853 | return nftw(path, remove_callback, 64, FTW_DEPTH | FTW_PHYS); |
820 | } | 854 | } |