diff options
author | 2018-08-28 16:45:55 +0200 | |
---|---|---|
committer | 2018-08-28 16:45:55 +0200 | |
commit | 34f148031a41bd9d2db3a3bd286d8741a7ed1fe9 (patch) | |
tree | 2a16419e5a8accc430e8f10c82ff3cdb811cc552 /src/firejail/util.c | |
parent | Add private-bin to 0ad (diff) | |
download | firejail-34f148031a41bd9d2db3a3bd286d8741a7ed1fe9.tar.gz firejail-34f148031a41bd9d2db3a3bd286d8741a7ed1fe9.tar.zst firejail-34f148031a41bd9d2db3a3bd286d8741a7ed1fe9.zip |
fix and harden overlay options
Diffstat (limited to 'src/firejail/util.c')
-rw-r--r-- | src/firejail/util.c | 78 |
1 files changed, 55 insertions, 23 deletions
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) { |