diff options
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/fs.c | 84 | ||||
-rw-r--r-- | src/firejail/main.c | 17 | ||||
-rw-r--r-- | src/firejail/util.c | 4 |
4 files changed, 85 insertions, 22 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 18199c122..a656dcf7c 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -333,7 +333,7 @@ void fs_basic_fs(void); | |||
333 | void fs_overlayfs(void); | 333 | void fs_overlayfs(void); |
334 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf | 334 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf |
335 | void fs_chroot(const char *rootdir); | 335 | void fs_chroot(const char *rootdir); |
336 | int fs_check_chroot_dir(const char *rootdir); | 336 | void fs_check_chroot_dir(const char *rootdir); |
337 | void fs_private_tmp(void); | 337 | void fs_private_tmp(void); |
338 | 338 | ||
339 | // profile.c | 339 | // profile.c |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index fa212bbd5..da63ecd00 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -837,17 +837,36 @@ void fs_overlayfs(void) { | |||
837 | 837 | ||
838 | #ifdef HAVE_CHROOT | 838 | #ifdef HAVE_CHROOT |
839 | // return 1 if error | 839 | // return 1 if error |
840 | int fs_check_chroot_dir(const char *rootdir) { | 840 | void fs_check_chroot_dir(const char *rootdir) { |
841 | assert(rootdir); | 841 | assert(rootdir); |
842 | struct stat s; | 842 | struct stat s; |
843 | char *name; | 843 | char *name; |
844 | 844 | ||
845 | if (strcmp(rootdir, "/tmp") == 0 || strcmp(rootdir, "/var/tmp") == 0) { | ||
846 | fprintf(stderr, "Error: invalid chroot directory\n"); | ||
847 | exit(1); | ||
848 | } | ||
849 | |||
850 | // rootdir has to be owned by root | ||
851 | if (stat(rootdir, &s) != 0) { | ||
852 | fprintf(stderr, "Error: cannot find chroot directory\n"); | ||
853 | exit(1); | ||
854 | } | ||
855 | if (s.st_uid != 0) { | ||
856 | fprintf(stderr, "Error: chroot directory should be owned by root\n"); | ||
857 | exit(1); | ||
858 | } | ||
859 | |||
845 | // check /dev | 860 | // check /dev |
846 | if (asprintf(&name, "%s/dev", rootdir) == -1) | 861 | if (asprintf(&name, "%s/dev", rootdir) == -1) |
847 | errExit("asprintf"); | 862 | errExit("asprintf"); |
848 | if (stat(name, &s) == -1) { | 863 | if (stat(name, &s) == -1) { |
849 | fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); | 864 | fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); |
850 | return 1; | 865 | exit(1); |
866 | } | ||
867 | if (s.st_uid != 0) { | ||
868 | fprintf(stderr, "Error: chroot /dev directory should be owned by root\n"); | ||
869 | exit(1); | ||
851 | } | 870 | } |
852 | free(name); | 871 | free(name); |
853 | 872 | ||
@@ -856,7 +875,11 @@ int fs_check_chroot_dir(const char *rootdir) { | |||
856 | errExit("asprintf"); | 875 | errExit("asprintf"); |
857 | if (stat(name, &s) == -1) { | 876 | if (stat(name, &s) == -1) { |
858 | fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); | 877 | fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); |
859 | return 1; | 878 | exit(1); |
879 | } | ||
880 | if (s.st_uid != 0) { | ||
881 | fprintf(stderr, "Error: chroot /var/tmp directory should be owned by root\n"); | ||
882 | exit(1); | ||
860 | } | 883 | } |
861 | free(name); | 884 | free(name); |
862 | 885 | ||
@@ -865,29 +888,54 @@ int fs_check_chroot_dir(const char *rootdir) { | |||
865 | errExit("asprintf"); | 888 | errExit("asprintf"); |
866 | if (stat(name, &s) == -1) { | 889 | if (stat(name, &s) == -1) { |
867 | fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); | 890 | fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); |
868 | return 1; | 891 | exit(1); |
892 | } | ||
893 | if (s.st_uid != 0) { | ||
894 | fprintf(stderr, "Error: chroot /proc directory should be owned by root\n"); | ||
895 | exit(1); | ||
869 | } | 896 | } |
870 | free(name); | 897 | free(name); |
871 | 898 | ||
872 | // check /proc | 899 | // check /tmp |
873 | if (asprintf(&name, "%s/tmp", rootdir) == -1) | 900 | if (asprintf(&name, "%s/tmp", rootdir) == -1) |
874 | errExit("asprintf"); | 901 | errExit("asprintf"); |
875 | if (stat(name, &s) == -1) { | 902 | if (stat(name, &s) == -1) { |
876 | fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); | 903 | fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); |
877 | return 1; | 904 | exit(1); |
905 | } | ||
906 | if (s.st_uid != 0) { | ||
907 | fprintf(stderr, "Error: chroot /tmp directory should be owned by root\n"); | ||
908 | exit(1); | ||
878 | } | 909 | } |
879 | free(name); | 910 | free(name); |
880 | 911 | ||
881 | // check /bin/bash | 912 | // check /etc |
882 | if (asprintf(&name, "%s/bin/bash", rootdir) == -1) | 913 | if (asprintf(&name, "%s/etc", rootdir) == -1) |
883 | errExit("asprintf"); | 914 | errExit("asprintf"); |
884 | if (stat(name, &s) == -1) { | 915 | if (stat(name, &s) == -1) { |
885 | fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); | 916 | fprintf(stderr, "Error: cannot find /etc in chroot directory\n"); |
886 | return 1; | 917 | exit(1); |
918 | } | ||
919 | if (s.st_uid != 0) { | ||
920 | fprintf(stderr, "Error: chroot /etc directory should be owned by root\n"); | ||
921 | exit(1); | ||
887 | } | 922 | } |
888 | free(name); | 923 | free(name); |
889 | 924 | ||
890 | return 0; | 925 | // check /etc/resolv.conf |
926 | if (asprintf(&name, "%s/etc/resolv.conf", rootdir) == -1) | ||
927 | errExit("asprintf"); | ||
928 | if (stat(name, &s) == 0) { | ||
929 | if (s.st_uid != 0) { | ||
930 | fprintf(stderr, "Error: chroot /etc/resolv.conf should be owned by root\n"); | ||
931 | exit(1); | ||
932 | } | ||
933 | } | ||
934 | if (is_link(name)) { | ||
935 | fprintf(stderr, "Error: invalid %s file\n", name); | ||
936 | exit(1); | ||
937 | } | ||
938 | free(name); | ||
891 | } | 939 | } |
892 | 940 | ||
893 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf | 941 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf |
@@ -912,6 +960,10 @@ void fs_chroot(const char *rootdir) { | |||
912 | char *rundir; | 960 | char *rundir; |
913 | if (asprintf(&rundir, "%s/run", rootdir) == -1) | 961 | if (asprintf(&rundir, "%s/run", rootdir) == -1) |
914 | errExit("asprintf"); | 962 | errExit("asprintf"); |
963 | if (is_link(rundir)) { | ||
964 | fprintf(stderr, "Error: invalid run directory inside chroot\n"); | ||
965 | exit(1); | ||
966 | } | ||
915 | if (!is_dir(rundir)) { | 967 | if (!is_dir(rundir)) { |
916 | int rv = mkdir(rundir, 0755); | 968 | int rv = mkdir(rundir, 0755); |
917 | (void) rv; | 969 | (void) rv; |
@@ -931,8 +983,14 @@ void fs_chroot(const char *rootdir) { | |||
931 | fprintf(stderr, "Error: invalid %s file\n", fname); | 983 | fprintf(stderr, "Error: invalid %s file\n", fname); |
932 | exit(1); | 984 | exit(1); |
933 | } | 985 | } |
934 | if (copy_file("/etc/resolv.conf", fname) == -1) | 986 | if (copy_file("/etc/resolv.conf", fname) == -1) // root needed |
935 | fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); | 987 | fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); |
988 | else { | ||
989 | if (chown("/etc/resolv.conf", 0, 0) == -1) | ||
990 | errExit("chown"); | ||
991 | if (chmod("/etc/resolv.conf", 0644) == -1) | ||
992 | errExit("chmod"); | ||
993 | } | ||
936 | 994 | ||
937 | // chroot into the new directory | 995 | // chroot into the new directory |
938 | if (arg_debug) | 996 | if (arg_debug) |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 9c1b73e7a..a7bd71356 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -885,6 +885,14 @@ int main(int argc, char **argv) { | |||
885 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 885 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
886 | exit(1); | 886 | exit(1); |
887 | } | 887 | } |
888 | |||
889 | struct stat s; | ||
890 | if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { | ||
891 | fprintf(stderr, "Error: --chroot option is not available on Grsecurity systems\n"); | ||
892 | exit(1); | ||
893 | } | ||
894 | |||
895 | |||
888 | invalid_filename(argv[i] + 9); | 896 | invalid_filename(argv[i] + 9); |
889 | 897 | ||
890 | // extract chroot dirname | 898 | // extract chroot dirname |
@@ -909,13 +917,10 @@ int main(int argc, char **argv) { | |||
909 | fprintf(stderr, "Error: invalid chroot directory\n"); | 917 | fprintf(stderr, "Error: invalid chroot directory\n"); |
910 | exit(1); | 918 | exit(1); |
911 | } | 919 | } |
912 | free(rpath); | 920 | cfg.chrootdir = rpath; |
913 | 921 | ||
914 | // check chroot directory structure | 922 | // check chroot directory structure |
915 | if (fs_check_chroot_dir(cfg.chrootdir)) { | 923 | fs_check_chroot_dir(cfg.chrootdir); |
916 | fprintf(stderr, "Error: invalid chroot\n"); | ||
917 | exit(1); | ||
918 | } | ||
919 | } | 924 | } |
920 | #endif | 925 | #endif |
921 | else if (strcmp(argv[i], "--private") == 0) | 926 | else if (strcmp(argv[i], "--private") == 0) |
diff --git a/src/firejail/util.c b/src/firejail/util.c index 21f9a73e3..5a6cb0296 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -228,9 +228,9 @@ void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid | |||
228 | fprintf(stderr, "Warning: cannot copy %s\n", srcname); | 228 | fprintf(stderr, "Warning: cannot copy %s\n", srcname); |
229 | else { | 229 | else { |
230 | if (chown(destname, uid, gid) == -1) | 230 | if (chown(destname, uid, gid) == -1) |
231 | errExit("fchown"); | 231 | errExit("chown"); |
232 | if (chmod(destname, mode) == -1) | 232 | if (chmod(destname, mode) == -1) |
233 | errExit("fchmod"); | 233 | errExit("chmod"); |
234 | } | 234 | } |
235 | _exit(0); | 235 | _exit(0); |
236 | } | 236 | } |