aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/util.c
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2018-08-28 16:45:55 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2018-08-28 16:45:55 +0200
commit34f148031a41bd9d2db3a3bd286d8741a7ed1fe9 (patch)
tree2a16419e5a8accc430e8f10c82ff3cdb811cc552 /src/firejail/util.c
parentAdd private-bin to 0ad (diff)
downloadfirejail-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.c78
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
831static int len_homedir = 0; 831
832static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { 832static 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
857int remove_overlay_directory(void) { 851int 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
880void flush_stdin(void) { 912void flush_stdin(void) {