diff options
author | 2018-08-28 16:45:55 +0200 | |
---|---|---|
committer | 2018-08-28 16:45:55 +0200 | |
commit | 34f148031a41bd9d2db3a3bd286d8741a7ed1fe9 (patch) | |
tree | 2a16419e5a8accc430e8f10c82ff3cdb811cc552 | |
parent | Add private-bin to 0ad (diff) | |
download | firejail-34f148031a41bd9d2db3a3bd286d8741a7ed1fe9.tar.gz firejail-34f148031a41bd9d2db3a3bd286d8741a7ed1fe9.tar.zst firejail-34f148031a41bd9d2db3a3bd286d8741a7ed1fe9.zip |
fix and harden overlay options
-rw-r--r-- | src/faudit/faudit.h | 2 | ||||
-rw-r--r-- | src/firejail/fs.c | 222 | ||||
-rw-r--r-- | src/firejail/util.c | 78 | ||||
-rw-r--r-- | src/include/common.h | 2 | ||||
-rw-r--r-- | src/man/firejail.txt | 9 |
5 files changed, 198 insertions, 115 deletions
diff --git a/src/faudit/faudit.h b/src/faudit/faudit.h index 180121ec1..e940a9dbf 100644 --- a/src/faudit/faudit.h +++ b/src/faudit/faudit.h | |||
@@ -31,7 +31,7 @@ | |||
31 | #include <sys/mount.h> | 31 | #include <sys/mount.h> |
32 | #include <assert.h> | 32 | #include <assert.h> |
33 | 33 | ||
34 | #define errExit(msg) do { char msgout[500]; sprintf(msgout, "Error %s:%s(%d)", msg, __FUNCTION__, __LINE__); perror(msgout); exit(1);} while (0) | 34 | #define errExit(msg) do { char msgout[500]; snprintf(msgout, 500, "Error %s:%s(%d)", msg, __FUNCTION__, __LINE__); perror(msgout); exit(1);} while (0) |
35 | 35 | ||
36 | // main.c | 36 | // main.c |
37 | extern char *prog; | 37 | extern char *prog; |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index d262d18bf..98efb5e41 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -779,19 +779,28 @@ void fs_basic_fs(void) { | |||
779 | 779 | ||
780 | #ifdef HAVE_OVERLAYFS | 780 | #ifdef HAVE_OVERLAYFS |
781 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | 781 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { |
782 | assert(subdirname); | ||
782 | struct stat s; | 783 | struct stat s; |
783 | char *dirname; | 784 | char *dirname; |
784 | 785 | ||
785 | // create ~/.firejail directory | ||
786 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) | 786 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) |
787 | errExit("asprintf"); | 787 | errExit("asprintf"); |
788 | 788 | // check if ~/.firejail already exists | |
789 | if (is_link(dirname)) { | 789 | if (lstat(dirname, &s) == 0) { |
790 | fprintf(stderr, "Error: ~/.firejail directory is a symbolic link\n"); | 790 | if (!S_ISDIR(s.st_mode)) { |
791 | exit(1); | 791 | if (S_ISLNK(s.st_mode)) |
792 | fprintf(stderr, "Error: ~/.firejail is a symbolic link\n"); | ||
793 | else | ||
794 | fprintf(stderr, "Error: ~/.firejail is not a directory\n"); | ||
795 | exit(1); | ||
796 | } | ||
797 | if (s.st_uid != getuid()) { | ||
798 | fprintf(stderr, "Error: ~/.firejail directory is not owned by the current user\n"); | ||
799 | exit(1); | ||
800 | } | ||
792 | } | 801 | } |
793 | if (stat(dirname, &s) == -1) { | 802 | else { |
794 | // create directory | 803 | // create ~/.firejail directory |
795 | pid_t child = fork(); | 804 | pid_t child = fork(); |
796 | if (child < 0) | 805 | if (child < 0) |
797 | errExit("fork"); | 806 | errExit("fork"); |
@@ -805,6 +814,9 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
805 | if (chmod(dirname, 0700) == -1) | 814 | if (chmod(dirname, 0700) == -1) |
806 | errExit("chmod"); | 815 | errExit("chmod"); |
807 | ASSERT_PERMS(dirname, getuid(), getgid(), 0700); | 816 | ASSERT_PERMS(dirname, getuid(), getgid(), 0700); |
817 | #ifdef HAVE_GCOV | ||
818 | __gcov_flush(); | ||
819 | #endif | ||
808 | _exit(0); | 820 | _exit(0); |
809 | } | 821 | } |
810 | // wait for the child to finish | 822 | // wait for the child to finish |
@@ -813,23 +825,27 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
813 | fprintf(stderr, "Error: cannot create ~/.firejail directory\n"); | 825 | fprintf(stderr, "Error: cannot create ~/.firejail directory\n"); |
814 | exit(1); | 826 | exit(1); |
815 | } | 827 | } |
816 | } | 828 | fs_logger2("create", dirname); |
817 | else if (s.st_uid != getuid()) { | ||
818 | fprintf(stderr, "Error: ~/.firejail directory is not owned by the current user\n"); | ||
819 | exit(1); | ||
820 | } | 829 | } |
821 | free(dirname); | 830 | free(dirname); |
822 | 831 | ||
823 | // check overlay directory | 832 | // check overlay directory |
824 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) | 833 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) |
825 | errExit("asprintf"); | 834 | errExit("asprintf"); |
826 | if (is_link(dirname)) { | 835 | if (lstat(dirname, &s) == 0) { |
827 | fprintf(stderr, "Error: overlay directory is a symbolic link\n"); | 836 | if (!S_ISDIR(s.st_mode)) { |
828 | exit(1); | 837 | if (S_ISLNK(s.st_mode)) |
829 | } | 838 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); |
830 | if (allow_reuse == 0) { | 839 | else |
831 | if (stat(dirname, &s) == 0) { | 840 | fprintf(stderr, "Error: %s is not a directory\n", dirname); |
832 | fprintf(stderr, "Error: overlay directory already exists: %s\n", dirname); | 841 | exit(1); |
842 | } | ||
843 | if (s.st_uid != 0) { | ||
844 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", dirname); | ||
845 | exit(1); | ||
846 | } | ||
847 | if (allow_reuse == 0) { | ||
848 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | ||
833 | exit(1); | 849 | exit(1); |
834 | } | 850 | } |
835 | } | 851 | } |
@@ -866,9 +882,11 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
866 | // # umount /root/overlay/root | 882 | // # umount /root/overlay/root |
867 | 883 | ||
868 | 884 | ||
869 | // to do: fix the code below; also, it might work without /dev; impose seccomp/caps filters when not root | 885 | // to do: fix the code below; also, it might work without /dev, but consider keeping /dev/shm; add locking mechanism for overlay-clean |
870 | #include <sys/utsname.h> | 886 | #include <sys/utsname.h> |
871 | void fs_overlayfs(void) { | 887 | void fs_overlayfs(void) { |
888 | struct stat s; | ||
889 | |||
872 | // check kernel version | 890 | // check kernel version |
873 | struct utsname u; | 891 | struct utsname u; |
874 | int rv = uname(&u); | 892 | int rv = uname(&u); |
@@ -894,50 +912,78 @@ void fs_overlayfs(void) { | |||
894 | char *oroot = RUN_OVERLAY_ROOT; | 912 | char *oroot = RUN_OVERLAY_ROOT; |
895 | mkdir_attr(oroot, 0755, 0, 0); | 913 | mkdir_attr(oroot, 0755, 0, 0); |
896 | 914 | ||
897 | struct stat s; | 915 | // set base for working and diff directories |
898 | char *basedir = RUN_MNT_DIR; | 916 | char *basedir = RUN_MNT_DIR; |
917 | int basefd = -1; | ||
918 | |||
899 | if (arg_overlay_keep) { | 919 | if (arg_overlay_keep) { |
900 | // set base for working and diff directories | ||
901 | basedir = cfg.overlay_dir; | 920 | basedir = cfg.overlay_dir; |
902 | assert(basedir); | 921 | assert(basedir); |
903 | 922 | // get a file descriptor for ~/.firejail, fails if there is any symlink | |
904 | // does the overlay exist? | 923 | char *firejail; |
905 | if (stat(basedir, &s) == 0) { | 924 | if (asprintf(&firejail, "%s/.firejail", cfg.homedir) == -1) |
906 | if (arg_overlay_reuse == 0) { | 925 | errExit("asprintf"); |
907 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | 926 | int fd = safe_fd(firejail, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
908 | exit(1); | 927 | if (fd == -1) |
909 | } | 928 | errExit("safe_fd"); |
910 | } | 929 | free(firejail); |
911 | else { | 930 | // create basedir if it doesn't exist |
912 | /* coverity[toctou] */ | 931 | // the new directory will be owned by root |
913 | if (mkdir(basedir, 0755) != 0) { | 932 | const char *dirname = gnu_basename(basedir); |
914 | fprintf(stderr, "Error: cannot create overlay directory\n"); | 933 | if (mkdirat(fd, dirname, 0755) == -1 && errno != EEXIST) { |
915 | exit(1); | 934 | perror("mkdir"); |
916 | } | 935 | fprintf(stderr, "Error: cannot create overlay directory %s\n", basedir); |
936 | exit(1); | ||
917 | } | 937 | } |
938 | // open basedir | ||
939 | basefd = openat(fd, dirname, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
940 | close(fd); | ||
941 | } | ||
942 | else { | ||
943 | basefd = open(basedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
944 | } | ||
945 | if (basefd == -1) { | ||
946 | perror("open"); | ||
947 | fprintf(stderr, "Error: cannot open overlay directory %s\n", basedir); | ||
948 | exit(1); | ||
918 | } | 949 | } |
919 | 950 | ||
920 | char *odiff; | 951 | // confirm once more base is owned by root |
921 | if(asprintf(&odiff, "%s/odiff", basedir) == -1) | 952 | if (fstat(basefd, &s) == -1) |
922 | errExit("asprintf"); | 953 | errExit("fstat"); |
954 | if (s.st_uid != 0) { | ||
955 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", basedir); | ||
956 | exit(1); | ||
957 | } | ||
958 | // confirm permissions of base are 0755 | ||
959 | if (((S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) & s.st_mode) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) { | ||
960 | fprintf(stderr, "Error: invalid permissions on overlay directory %s\n", basedir); | ||
961 | exit(1); | ||
962 | } | ||
923 | 963 | ||
964 | // create diff and work directories inside base | ||
924 | // no need to check arg_overlay_reuse | 965 | // no need to check arg_overlay_reuse |
925 | if (stat(odiff, &s) != 0) { | 966 | char *odiff; |
926 | mkdir_attr(odiff, 0755, 0, 0); | 967 | if (asprintf(&odiff, "%s/odiff", basedir) == -1) |
968 | errExit("asprintf"); | ||
969 | // the new directory will be owned by root | ||
970 | if (mkdirat(basefd, "odiff", 0755) == -1 && errno != EEXIST) { | ||
971 | perror("mkdir"); | ||
972 | fprintf(stderr, "Error: cannot create overlay directory %s\n", odiff); | ||
973 | exit(1); | ||
927 | } | 974 | } |
928 | else if (set_perms(odiff, 0, 0, 0755)) | 975 | ASSERT_PERMS(odiff, 0, 0, 0755); |
929 | errExit("set_perms"); | ||
930 | 976 | ||
931 | char *owork; | 977 | char *owork; |
932 | if(asprintf(&owork, "%s/owork", basedir) == -1) | 978 | if (asprintf(&owork, "%s/owork", basedir) == -1) |
933 | errExit("asprintf"); | 979 | errExit("asprintf"); |
934 | 980 | // the new directory will be owned by root | |
935 | // no need to check arg_overlay_reuse | 981 | if (mkdirat(basefd, "owork", 0755) == -1 && errno != EEXIST) { |
936 | if (stat(owork, &s) != 0) { | 982 | perror("mkdir"); |
937 | mkdir_attr(owork, 0755, 0, 0); | 983 | fprintf(stderr, "Error: cannot create overlay directory %s\n", owork); |
984 | exit(1); | ||
938 | } | 985 | } |
939 | else if (set_perms(owork, 0, 0, 0755)) | 986 | ASSERT_PERMS(owork, 0, 0, 0755); |
940 | errExit("chown"); | ||
941 | 987 | ||
942 | // mount overlayfs | 988 | // mount overlayfs |
943 | if (arg_debug) | 989 | if (arg_debug) |
@@ -977,43 +1023,48 @@ void fs_overlayfs(void) { | |||
977 | 1023 | ||
978 | // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? | 1024 | // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? |
979 | // must create var for oroot/cfg.homedir | 1025 | // must create var for oroot/cfg.homedir |
980 | if (asprintf(&overlayhome,"%s%s",oroot,cfg.homedir) == -1) | 1026 | if (asprintf(&overlayhome, "%s%s", oroot, cfg.homedir) == -1) |
981 | errExit("asprintf"); | 1027 | errExit("asprintf"); |
982 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n",overlayhome); | 1028 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n", overlayhome); |
983 | 1029 | ||
984 | // if no homedir in overlay -- create another overlay for /home | 1030 | // if no homedir in overlay -- create another overlay for /home |
985 | if (stat(overlayhome, &s) == -1) { | 1031 | if (stat(cfg.homedir, &s) == 0 && stat(overlayhome, &s) == -1) { |
986 | |||
987 | if(asprintf(&hroot, "%s/oroot/home", RUN_MNT_DIR) == -1) | ||
988 | errExit("asprintf"); | ||
989 | |||
990 | if(asprintf(&hdiff, "%s/hdiff", basedir) == -1) | ||
991 | errExit("asprintf"); | ||
992 | 1032 | ||
993 | // no need to check arg_overlay_reuse | 1033 | // no need to check arg_overlay_reuse |
994 | if (stat(hdiff, &s) != 0) { | 1034 | if (asprintf(&hdiff, "%s/hdiff", basedir) == -1) |
995 | mkdir_attr(hdiff, S_IRWXU | S_IRWXG | S_IRWXO, 0, 0); | ||
996 | } | ||
997 | else if (set_perms(hdiff, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) | ||
998 | errExit("set_perms"); | ||
999 | |||
1000 | if(asprintf(&hwork, "%s/hwork", basedir) == -1) | ||
1001 | errExit("asprintf"); | 1035 | errExit("asprintf"); |
1036 | // the new directory will be owned by root | ||
1037 | if (mkdirat(basefd, "hdiff", 0755) == -1 && errno != EEXIST) { | ||
1038 | perror("mkdir"); | ||
1039 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hdiff); | ||
1040 | exit(1); | ||
1041 | } | ||
1042 | ASSERT_PERMS(hdiff, 0, 0, 0755); | ||
1002 | 1043 | ||
1003 | // no need to check arg_overlay_reuse | 1044 | // no need to check arg_overlay_reuse |
1004 | if (stat(hwork, &s) != 0) { | 1045 | if (asprintf(&hwork, "%s/hwork", basedir) == -1) |
1005 | mkdir_attr(hwork, S_IRWXU | S_IRWXG | S_IRWXO, 0, 0); | 1046 | errExit("asprintf"); |
1047 | // the new directory will be owned by root | ||
1048 | if (mkdirat(basefd, "hwork", 0755) == -1 && errno != EEXIST) { | ||
1049 | perror("mkdir"); | ||
1050 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hwork); | ||
1051 | exit(1); | ||
1006 | } | 1052 | } |
1007 | else if (set_perms(hwork, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) | 1053 | ASSERT_PERMS(hwork, 0, 0, 0755); |
1008 | errExit("set_perms"); | ||
1009 | 1054 | ||
1010 | // no homedir in overlay so now mount another overlay for /home | 1055 | // no homedir in overlay so now mount another overlay for /home |
1056 | if (asprintf(&hroot, "%s/home", oroot) == -1) | ||
1057 | errExit("asprintf"); | ||
1011 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) | 1058 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) |
1012 | errExit("asprintf"); | 1059 | errExit("asprintf"); |
1013 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) | 1060 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) |
1014 | errExit("mounting overlayfs for mounted home directory"); | 1061 | errExit("mounting overlayfs for mounted home directory"); |
1015 | 1062 | ||
1016 | printf("OverlayFS for /home configured in %s directory\n", basedir); | 1063 | printf("OverlayFS for /home configured in %s directory\n", basedir); |
1064 | free(hroot); | ||
1065 | free(hdiff); | ||
1066 | free(hwork); | ||
1067 | |||
1017 | } // stat(overlayhome) | 1068 | } // stat(overlayhome) |
1018 | free(overlayhome); | 1069 | free(overlayhome); |
1019 | } | 1070 | } |
@@ -1021,7 +1072,9 @@ void fs_overlayfs(void) { | |||
1021 | //*************************** | 1072 | //*************************** |
1022 | } | 1073 | } |
1023 | fmessage("OverlayFS configured in %s directory\n", basedir); | 1074 | fmessage("OverlayFS configured in %s directory\n", basedir); |
1075 | close(basefd); | ||
1024 | 1076 | ||
1077 | // /dev, /run and /tmp are not covered by the overlay | ||
1025 | // mount-bind dev directory | 1078 | // mount-bind dev directory |
1026 | if (arg_debug) | 1079 | if (arg_debug) |
1027 | printf("Mounting /dev\n"); | 1080 | printf("Mounting /dev\n"); |
@@ -1042,19 +1095,15 @@ void fs_overlayfs(void) { | |||
1042 | errExit("mounting /run"); | 1095 | errExit("mounting /run"); |
1043 | fs_logger("whitelist /run"); | 1096 | fs_logger("whitelist /run"); |
1044 | 1097 | ||
1045 | // mount-bind /tmp/.X11-unix directory | 1098 | // mount-bind tmp directory |
1046 | if (stat("/tmp/.X11-unix", &s) == 0) { | 1099 | if (arg_debug) |
1047 | if (arg_debug) | 1100 | printf("Mounting /tmp\n"); |
1048 | printf("Mounting /tmp/.X11-unix\n"); | 1101 | char *tmp; |
1049 | char *x11; | 1102 | if (asprintf(&tmp, "%s/tmp", oroot) == -1) |
1050 | if (asprintf(&x11, "%s/tmp/.X11-unix", oroot) == -1) | 1103 | errExit("asprintf"); |
1051 | errExit("asprintf"); | 1104 | if (mount("/tmp", tmp, NULL, MS_BIND|MS_REC, NULL) < 0) |
1052 | if (mount("/tmp/.X11-unix", x11, NULL, MS_BIND|MS_REC, NULL) < 0) | 1105 | errExit("mounting /tmp"); |
1053 | fwarning("cannot mount /tmp/.X11-unix in overlay\n"); | 1106 | fs_logger("whitelist /tmp"); |
1054 | else | ||
1055 | fs_logger("whitelist /tmp/.X11-unix"); | ||
1056 | free(x11); | ||
1057 | } | ||
1058 | 1107 | ||
1059 | // chroot in the new filesystem | 1108 | // chroot in the new filesystem |
1060 | #ifdef HAVE_GCOV | 1109 | #ifdef HAVE_GCOV |
@@ -1068,12 +1117,9 @@ void fs_overlayfs(void) { | |||
1068 | // fs_dev_shm(); | 1117 | // fs_dev_shm(); |
1069 | fs_var_lock(); | 1118 | fs_var_lock(); |
1070 | if (!arg_keep_var_tmp) | 1119 | if (!arg_keep_var_tmp) |
1071 | fs_var_tmp(); | 1120 | fs_var_tmp(); |
1072 | if (!arg_writable_var_log) | 1121 | if (!arg_writable_var_log) |
1073 | fs_var_log(); | 1122 | fs_var_log(); |
1074 | else | ||
1075 | fs_rdwr("/var/log"); | ||
1076 | |||
1077 | fs_var_lib(); | 1123 | fs_var_lib(); |
1078 | fs_var_cache(); | 1124 | fs_var_cache(); |
1079 | fs_var_utmp(); | 1125 | fs_var_utmp(); |
@@ -1089,6 +1135,10 @@ void fs_overlayfs(void) { | |||
1089 | // cleanup and exit | 1135 | // cleanup and exit |
1090 | free(option); | 1136 | free(option); |
1091 | free(odiff); | 1137 | free(odiff); |
1138 | free(owork); | ||
1139 | free(dev); | ||
1140 | free(run); | ||
1141 | free(tmp); | ||
1092 | } | 1142 | } |
1093 | #endif | 1143 | #endif |
1094 | 1144 | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c index 050f7534a..ff2bceacd 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -828,25 +828,19 @@ uid_t get_group_id(const char *group) { | |||
828 | return gid; | 828 | return gid; |
829 | } | 829 | } |
830 | 830 | ||
831 | static int len_homedir = 0; | 831 | |
832 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { | 832 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { |
833 | (void) sb; | 833 | (void) sb; |
834 | (void) typeflag; | 834 | (void) typeflag; |
835 | (void) ftwbuf; | 835 | (void) ftwbuf; |
836 | assert(fpath); | 836 | assert(fpath); |
837 | 837 | ||
838 | if (len_homedir == 0) | 838 | if (strcmp(fpath, ".") == 0) |
839 | len_homedir = strlen(cfg.homedir); | 839 | return 0; |
840 | |||
841 | char *rp = realpath(fpath, NULL); // this should never fail! | ||
842 | if (!rp) | ||
843 | return 1; | ||
844 | if (strncmp(rp, cfg.homedir, len_homedir) != 0) | ||
845 | return 1; | ||
846 | free(rp); | ||
847 | 840 | ||
848 | if (remove(fpath)) { // removes the link not the actual file | 841 | if (remove(fpath)) { // removes the link not the actual file |
849 | fprintf(stderr, "Error: cannot remove file %s\n", fpath); | 842 | perror("remove"); |
843 | fprintf(stderr, "Error: cannot remove file from user .firejail directory: %s\n", fpath); | ||
850 | exit(1); | 844 | exit(1); |
851 | } | 845 | } |
852 | 846 | ||
@@ -855,26 +849,64 @@ static int remove_callback(const char *fpath, const struct stat *sb, int typefla | |||
855 | 849 | ||
856 | 850 | ||
857 | int remove_overlay_directory(void) { | 851 | int remove_overlay_directory(void) { |
852 | EUID_ASSERT(); | ||
853 | struct stat s; | ||
858 | sleep(1); | 854 | sleep(1); |
859 | 855 | ||
860 | char *path; | 856 | char *path; |
861 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | 857 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) |
862 | errExit("asprintf"); | 858 | errExit("asprintf"); |
863 | 859 | ||
864 | // deal with obvious problems such as symlinks and root ownership | 860 | if (lstat(path, &s) == 0) { |
865 | if (is_link(path)) | 861 | // deal with obvious problems such as symlinks and root ownership |
866 | errLogExit("overlay directory is a symlink\n"); | 862 | if (!S_ISDIR(s.st_mode)) { |
867 | if (access(path, R_OK | W_OK | X_OK) == -1) | 863 | if (S_ISLNK(s.st_mode)) |
868 | errLogExit("no access to overlay directory\n"); | 864 | fprintf(stderr, "Error: %s is a symbolic link\n", path); |
865 | else | ||
866 | fprintf(stderr, "Error: %s is not a directory\n", path); | ||
867 | exit(1); | ||
868 | } | ||
869 | if (s.st_uid != getuid()) { | ||
870 | fprintf(stderr, "Error: %s is not owned by the current user\n", path); | ||
871 | exit(1); | ||
872 | } | ||
873 | |||
874 | pid_t child = fork(); | ||
875 | if (child < 0) | ||
876 | errExit("fork"); | ||
877 | if (child == 0) { | ||
878 | // open ~/.firejail, fails if there is any symlink | ||
879 | int fd = safe_fd(path, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
880 | if (fd == -1) | ||
881 | errExit("safe_fd"); | ||
882 | // chdir to ~/.firejail | ||
883 | if (fchdir(fd) == -1) | ||
884 | errExit("fchdir"); | ||
885 | close(fd); | ||
869 | 886 | ||
870 | EUID_ROOT(); | 887 | EUID_ROOT(); |
871 | if (setreuid(0, 0) < 0 || | 888 | // FTW_PHYS - do not follow symbolic links |
872 | setregid(0, 0) < 0) | 889 | if (nftw(".", remove_callback, 64, FTW_DEPTH | FTW_PHYS) == -1) |
873 | errExit("setreuid/setregid"); | 890 | errExit("nftw"); |
874 | errno = 0; | ||
875 | 891 | ||
876 | // FTW_PHYS - do not follow symbolic links | 892 | EUID_USER(); |
877 | return nftw(path, remove_callback, 64, FTW_DEPTH | FTW_PHYS); | 893 | // remove ~/.firejail |
894 | if (rmdir(path) == -1) | ||
895 | errExit("rmdir"); | ||
896 | #ifdef HAVE_GCOV | ||
897 | __gcov_flush(); | ||
898 | #endif | ||
899 | _exit(0); | ||
900 | } | ||
901 | // wait for the child to finish | ||
902 | waitpid(child, NULL, 0); | ||
903 | // check if ~/.firejail was deleted | ||
904 | if (stat(path, &s) == -1) | ||
905 | return 0; | ||
906 | else | ||
907 | return 1; | ||
908 | } | ||
909 | return 0; | ||
878 | } | 910 | } |
879 | 911 | ||
880 | void flush_stdin(void) { | 912 | void flush_stdin(void) { |
diff --git a/src/include/common.h b/src/include/common.h index 413cf98a5..a80ad4688 100644 --- a/src/include/common.h +++ b/src/include/common.h | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <ctype.h> | 32 | #include <ctype.h> |
33 | #include <assert.h> | 33 | #include <assert.h> |
34 | 34 | ||
35 | #define errExit(msg) do { char msgout[500]; sprintf(msgout, "Error %s: %s:%d %s", msg, __FILE__, __LINE__, __FUNCTION__); perror(msgout); exit(1);} while (0) | 35 | #define errExit(msg) do { char msgout[500]; snprintf(msgout, 500, "Error %s: %s:%d %s", msg, __FILE__, __LINE__, __FUNCTION__); perror(msgout); exit(1);} while (0) |
36 | 36 | ||
37 | // macro to print ip addresses in a printf statement | 37 | // macro to print ip addresses in a printf statement |
38 | #define PRINT_IP(A) \ | 38 | #define PRINT_IP(A) \ |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 7de1bff50..d7e402e31 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -1267,7 +1267,7 @@ Similar to \-\-output, but stderr is also stored. | |||
1267 | \fB\-\-overlay | 1267 | \fB\-\-overlay |
1268 | Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, | 1268 | Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, |
1269 | the system directories are mounted read-write. All filesystem modifications go into the overlay. | 1269 | the system directories are mounted read-write. All filesystem modifications go into the overlay. |
1270 | The overlay is stored in $HOME/.firejail/<PID> directory. | 1270 | Directories /run, /tmp and /dev are not covered by the overlay. The overlay is stored in $HOME/.firejail/<PID> directory. |
1271 | .br | 1271 | .br |
1272 | 1272 | ||
1273 | .br | 1273 | .br |
@@ -1285,8 +1285,8 @@ $ firejail \-\-overlay firefox | |||
1285 | \fB\-\-overlay-named=name | 1285 | \fB\-\-overlay-named=name |
1286 | Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, | 1286 | Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container, |
1287 | the system directories are mounted read-write. All filesystem modifications go into the overlay. | 1287 | the system directories are mounted read-write. All filesystem modifications go into the overlay. |
1288 | The overlay is stored in $HOME/.firejail/<NAME> directory. The created overlay can be reused between multiple | 1288 | Directories /run, /tmp and /dev are not covered by the overlay. The overlay is stored in $HOME/.firejail/<NAME> directory. |
1289 | sessions. | 1289 | The created overlay can be reused between multiple sessions. |
1290 | .br | 1290 | .br |
1291 | 1291 | ||
1292 | .br | 1292 | .br |
@@ -1303,7 +1303,8 @@ $ firejail \-\-overlay-named=jail1 firefox | |||
1303 | .TP | 1303 | .TP |
1304 | \fB\-\-overlay-tmpfs | 1304 | \fB\-\-overlay-tmpfs |
1305 | Mount a filesystem overlay on top of the current filesystem. All filesystem modifications | 1305 | Mount a filesystem overlay on top of the current filesystem. All filesystem modifications |
1306 | are discarded when the sandbox is closed. | 1306 | are discarded when the sandbox is closed. Directories /run, /tmp and /dev are not covered by the overlay. |
1307 | |||
1307 | .br | 1308 | .br |
1308 | 1309 | ||
1309 | .br | 1310 | .br |