diff options
-rw-r--r-- | src/firecfg/desktop_files.c | 12 | ||||
-rw-r--r-- | src/firecfg/firecfg.config | 4 | ||||
-rw-r--r-- | src/firecfg/main.c | 5 | ||||
-rw-r--r-- | src/firejail/arp.c | 4 | ||||
-rw-r--r-- | src/firejail/cmdline.c | 1 | ||||
-rw-r--r-- | src/firejail/fs.c | 397 | ||||
-rw-r--r-- | src/firejail/fs_whitelist.c | 40 | ||||
-rw-r--r-- | src/firejail/main.c | 108 | ||||
-rw-r--r-- | src/firejail/network.c | 6 | ||||
-rw-r--r-- | src/firejail/preproc.c | 2 | ||||
-rw-r--r-- | src/firejail/profile.c | 1 | ||||
-rw-r--r-- | src/firejail/restrict_users.c | 2 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 36 | ||||
-rw-r--r-- | src/firejail/sbox.c | 4 | ||||
-rw-r--r-- | src/firejail/util.c | 78 | ||||
-rw-r--r-- | src/firemon/interface.c | 2 | ||||
-rw-r--r-- | src/fnet/arp.c | 2 | ||||
-rw-r--r-- | src/fnet/interface.c | 16 | ||||
-rw-r--r-- | src/fsec-optimize/main.c | 3 | ||||
-rw-r--r-- | src/fsec-print/main.c | 3 | ||||
-rw-r--r-- | src/include/common.h | 2 | ||||
-rw-r--r-- | src/libpostexecseccomp/libpostexecseccomp.c | 6 |
22 files changed, 458 insertions, 276 deletions
diff --git a/src/firecfg/desktop_files.c b/src/firecfg/desktop_files.c index 71b39390e..f09a23977 100644 --- a/src/firecfg/desktop_files.c +++ b/src/firecfg/desktop_files.c | |||
@@ -144,6 +144,8 @@ void fix_desktop_files(char *homedir) { | |||
144 | perror("opendir"); | 144 | perror("opendir"); |
145 | fprintf(stderr, "Warning: cannot access /usr/share/applications directory, desktop files fixing skipped...\n"); | 145 | fprintf(stderr, "Warning: cannot access /usr/share/applications directory, desktop files fixing skipped...\n"); |
146 | free(user_apps_dir); | 146 | free(user_apps_dir); |
147 | if (dir) | ||
148 | closedir(dir); | ||
147 | return; | 149 | return; |
148 | } | 150 | } |
149 | 151 | ||
@@ -182,7 +184,9 @@ void fix_desktop_files(char *homedir) { | |||
182 | } | 184 | } |
183 | 185 | ||
184 | fseek(fp, 0, SEEK_END); | 186 | fseek(fp, 0, SEEK_END); |
185 | size_t size = ftell(fp); | 187 | long size = ftell(fp); |
188 | if (size == -1) | ||
189 | errExit("ftell"); | ||
186 | fseek(fp, 0, SEEK_SET); | 190 | fseek(fp, 0, SEEK_SET); |
187 | char *buf = malloc(size + 1); | 191 | char *buf = malloc(size + 1); |
188 | if (!buf) | 192 | if (!buf) |
@@ -266,12 +270,16 @@ void fix_desktop_files(char *homedir) { | |||
266 | 270 | ||
267 | if (stat(outname, &sb) == 0) { | 271 | if (stat(outname, &sb) == 0) { |
268 | printf(" %s skipped: file exists\n", filename); | 272 | printf(" %s skipped: file exists\n", filename); |
273 | if (change_exec) | ||
274 | free(change_exec); | ||
269 | continue; | 275 | continue; |
270 | } | 276 | } |
271 | 277 | ||
272 | FILE *fpin = fopen(filename, "r"); | 278 | FILE *fpin = fopen(filename, "r"); |
273 | if (!fpin) { | 279 | if (!fpin) { |
274 | fprintf(stderr, "Warning: cannot open /usr/share/applications/%s\n", filename); | 280 | fprintf(stderr, "Warning: cannot open /usr/share/applications/%s\n", filename); |
281 | if (change_exec) | ||
282 | free(change_exec); | ||
275 | continue; | 283 | continue; |
276 | } | 284 | } |
277 | 285 | ||
@@ -279,6 +287,8 @@ void fix_desktop_files(char *homedir) { | |||
279 | if (!fpout) { | 287 | if (!fpout) { |
280 | fprintf(stderr, "Warning: cannot open ~/.local/share/applications/%s\n", outname); | 288 | fprintf(stderr, "Warning: cannot open ~/.local/share/applications/%s\n", outname); |
281 | fclose(fpin); | 289 | fclose(fpin); |
290 | if (change_exec) | ||
291 | free(change_exec); | ||
282 | continue; | 292 | continue; |
283 | } | 293 | } |
284 | fprintf(fpout, "# converted by firecfg\n"); | 294 | fprintf(fpout, "# converted by firecfg\n"); |
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config index 0bbafb343..676c2d90a 100644 --- a/src/firecfg/firecfg.config +++ b/src/firecfg/firecfg.config | |||
@@ -10,6 +10,7 @@ Discord | |||
10 | DiscordCanary | 10 | DiscordCanary |
11 | FossaMail | 11 | FossaMail |
12 | Fritzing | 12 | Fritzing |
13 | JDownloader | ||
13 | Mathematica | 14 | Mathematica |
14 | Natron | 15 | Natron |
15 | Telegram | 16 | Telegram |
@@ -94,6 +95,7 @@ deadbeef | |||
94 | deluge | 95 | deluge |
95 | dex2jar | 96 | dex2jar |
96 | dia | 97 | dia |
98 | dig | ||
97 | digikam | 99 | digikam |
98 | dillo | 100 | dillo |
99 | dino | 101 | dino |
@@ -217,6 +219,7 @@ inox | |||
217 | iridium | 219 | iridium |
218 | iridium-browser | 220 | iridium-browser |
219 | jd-gui | 221 | jd-gui |
222 | jdownloader | ||
220 | jitsi | 223 | jitsi |
221 | k3b | 224 | k3b |
222 | kaffeine | 225 | kaffeine |
@@ -442,6 +445,7 @@ weechat | |||
442 | weechat-curses | 445 | weechat-curses |
443 | wesnoth | 446 | wesnoth |
444 | wget | 447 | wget |
448 | whois | ||
445 | wine | 449 | wine |
446 | wire-desktop | 450 | wire-desktop |
447 | wireshark | 451 | wireshark |
diff --git a/src/firecfg/main.c b/src/firecfg/main.c index 298314d4f..810af6ff2 100644 --- a/src/firecfg/main.c +++ b/src/firecfg/main.c | |||
@@ -318,13 +318,14 @@ int main(int argc, char **argv) { | |||
318 | 318 | ||
319 | // user setup | 319 | // user setup |
320 | char *user = get_user(); | 320 | char *user = get_user(); |
321 | assert(user); | ||
321 | uid_t uid; | 322 | uid_t uid; |
322 | gid_t gid; | 323 | gid_t gid; |
323 | char *home = get_homedir(user, &uid, &gid); | 324 | char *home = get_homedir(user, &uid, &gid); |
324 | 325 | ||
325 | 326 | ||
326 | // check for --bindir | 327 | // check for --bindir |
327 | for (i = i; i < argc; i++) { | 328 | for (i = 1; i < argc; i++) { |
328 | if (strncmp(argv[i], "--bindir=", 9) == 0) { | 329 | if (strncmp(argv[i], "--bindir=", 9) == 0) { |
329 | if (strncmp(argv[i] + 9, "~/", 2) == 0) { | 330 | if (strncmp(argv[i] + 9, "~/", 2) == 0) { |
330 | if (asprintf(&arg_bindir, "%s/%s", home, argv[i] + 11) == -1) | 331 | if (asprintf(&arg_bindir, "%s/%s", home, argv[i] + 11) == -1) |
@@ -430,7 +431,7 @@ int main(int argc, char **argv) { | |||
430 | set_links_firecfg(); | 431 | set_links_firecfg(); |
431 | 432 | ||
432 | // add user to firejail access database - only for root | 433 | // add user to firejail access database - only for root |
433 | if (user && getuid() == 0) { | 434 | if (getuid() == 0) { |
434 | printf("\nAdding user %s to Firejail access database in %s/firejail.users\n", user, SYSCONFDIR); | 435 | printf("\nAdding user %s to Firejail access database in %s/firejail.users\n", user, SYSCONFDIR); |
435 | firejail_user_add(user); | 436 | firejail_user_add(user); |
436 | } | 437 | } |
diff --git a/src/firejail/arp.c b/src/firejail/arp.c index c19cb0a47..288e5ded3 100644 --- a/src/firejail/arp.c +++ b/src/firejail/arp.c | |||
@@ -66,7 +66,7 @@ void arp_announce(const char *dev, Bridge *br) { | |||
66 | // Find interface MAC address | 66 | // Find interface MAC address |
67 | struct ifreq ifr; | 67 | struct ifreq ifr; |
68 | memset(&ifr, 0, sizeof (ifr)); | 68 | memset(&ifr, 0, sizeof (ifr)); |
69 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); | 69 | strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1); |
70 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) | 70 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) |
71 | errExit("ioctl"); | 71 | errExit("ioctl"); |
72 | close(sock); | 72 | close(sock); |
@@ -138,7 +138,7 @@ int arp_check(const char *dev, uint32_t destaddr) { | |||
138 | // Find interface MAC address | 138 | // Find interface MAC address |
139 | struct ifreq ifr; | 139 | struct ifreq ifr; |
140 | memset(&ifr, 0, sizeof (ifr)); | 140 | memset(&ifr, 0, sizeof (ifr)); |
141 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); | 141 | strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1); |
142 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) | 142 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) |
143 | errExit("ioctl"); | 143 | errExit("ioctl"); |
144 | close(sock); | 144 | close(sock); |
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c index ce1e281a5..1fe5a2398 100644 --- a/src/firejail/cmdline.c +++ b/src/firejail/cmdline.c | |||
@@ -208,4 +208,5 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc, | |||
208 | 208 | ||
209 | // free strdup | 209 | // free strdup |
210 | free(tmp1); | 210 | free(tmp1); |
211 | free(command_line_tmp); | ||
211 | } | 212 | } |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index d28ff534f..d92b6b1e0 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -555,6 +555,7 @@ void fs_mnt(void) { | |||
555 | 555 | ||
556 | // mount /proc and /sys directories | 556 | // mount /proc and /sys directories |
557 | void fs_proc_sys_dev_boot(void) { | 557 | void fs_proc_sys_dev_boot(void) { |
558 | |||
558 | if (arg_debug) | 559 | if (arg_debug) |
559 | printf("Remounting /proc and /proc/sys filesystems\n"); | 560 | printf("Remounting /proc and /proc/sys filesystems\n"); |
560 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | 561 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) |
@@ -571,8 +572,11 @@ void fs_proc_sys_dev_boot(void) { | |||
571 | /* Mount a version of /sys that describes the network namespace */ | 572 | /* Mount a version of /sys that describes the network namespace */ |
572 | if (arg_debug) | 573 | if (arg_debug) |
573 | printf("Remounting /sys directory\n"); | 574 | printf("Remounting /sys directory\n"); |
574 | if (umount2("/sys", MNT_DETACH) < 0) | 575 | // if this is an overlay, don't try to unmount, just mount a new sysfs |
575 | fwarning("failed to unmount /sys\n"); | 576 | if (!arg_overlay) { |
577 | if (umount2("/sys", MNT_DETACH) < 0 && !cfg.chrootdir) | ||
578 | fwarning("failed to unmount /sys\n"); | ||
579 | } | ||
576 | if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) | 580 | if (mount("sysfs", "/sys", "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REC, NULL) < 0) |
577 | fwarning("failed to mount /sys\n"); | 581 | fwarning("failed to mount /sys\n"); |
578 | else | 582 | else |
@@ -779,19 +783,28 @@ void fs_basic_fs(void) { | |||
779 | #ifndef LTS | 783 | #ifndef LTS |
780 | #ifdef HAVE_OVERLAYFS | 784 | #ifdef HAVE_OVERLAYFS |
781 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | 785 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { |
786 | assert(subdirname); | ||
782 | struct stat s; | 787 | struct stat s; |
783 | char *dirname; | 788 | char *dirname; |
784 | 789 | ||
785 | // create ~/.firejail directory | ||
786 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) | 790 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) |
787 | errExit("asprintf"); | 791 | errExit("asprintf"); |
788 | 792 | // check if ~/.firejail already exists | |
789 | if (is_link(dirname)) { | 793 | if (lstat(dirname, &s) == 0) { |
790 | fprintf(stderr, "Error: ~/.firejail directory is a symbolic link\n"); | 794 | if (!S_ISDIR(s.st_mode)) { |
791 | exit(1); | 795 | if (S_ISLNK(s.st_mode)) |
796 | fprintf(stderr, "Error: ~/.firejail is a symbolic link\n"); | ||
797 | else | ||
798 | fprintf(stderr, "Error: ~/.firejail is not a directory\n"); | ||
799 | exit(1); | ||
800 | } | ||
801 | if (s.st_uid != getuid()) { | ||
802 | fprintf(stderr, "Error: ~/.firejail directory is not owned by the current user\n"); | ||
803 | exit(1); | ||
804 | } | ||
792 | } | 805 | } |
793 | if (stat(dirname, &s) == -1) { | 806 | else { |
794 | // create directory | 807 | // create ~/.firejail directory |
795 | pid_t child = fork(); | 808 | pid_t child = fork(); |
796 | if (child < 0) | 809 | if (child < 0) |
797 | errExit("fork"); | 810 | errExit("fork"); |
@@ -805,6 +818,9 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
805 | if (chmod(dirname, 0700) == -1) | 818 | if (chmod(dirname, 0700) == -1) |
806 | errExit("chmod"); | 819 | errExit("chmod"); |
807 | ASSERT_PERMS(dirname, getuid(), getgid(), 0700); | 820 | ASSERT_PERMS(dirname, getuid(), getgid(), 0700); |
821 | #ifdef HAVE_GCOV | ||
822 | __gcov_flush(); | ||
823 | #endif | ||
808 | _exit(0); | 824 | _exit(0); |
809 | } | 825 | } |
810 | // wait for the child to finish | 826 | // wait for the child to finish |
@@ -813,23 +829,27 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
813 | fprintf(stderr, "Error: cannot create ~/.firejail directory\n"); | 829 | fprintf(stderr, "Error: cannot create ~/.firejail directory\n"); |
814 | exit(1); | 830 | exit(1); |
815 | } | 831 | } |
816 | } | 832 | 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 | } | 833 | } |
821 | free(dirname); | 834 | free(dirname); |
822 | 835 | ||
823 | // check overlay directory | 836 | // check overlay directory |
824 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) | 837 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) |
825 | errExit("asprintf"); | 838 | errExit("asprintf"); |
826 | if (is_link(dirname)) { | 839 | if (lstat(dirname, &s) == 0) { |
827 | fprintf(stderr, "Error: overlay directory is a symbolic link\n"); | 840 | if (!S_ISDIR(s.st_mode)) { |
828 | exit(1); | 841 | if (S_ISLNK(s.st_mode)) |
829 | } | 842 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); |
830 | if (allow_reuse == 0) { | 843 | else |
831 | if (stat(dirname, &s) == 0) { | 844 | fprintf(stderr, "Error: %s is not a directory\n", dirname); |
832 | fprintf(stderr, "Error: overlay directory already exists: %s\n", dirname); | 845 | exit(1); |
846 | } | ||
847 | if (s.st_uid != 0) { | ||
848 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", dirname); | ||
849 | exit(1); | ||
850 | } | ||
851 | if (allow_reuse == 0) { | ||
852 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | ||
833 | exit(1); | 853 | exit(1); |
834 | } | 854 | } |
835 | } | 855 | } |
@@ -866,9 +886,11 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | |||
866 | // # umount /root/overlay/root | 886 | // # umount /root/overlay/root |
867 | 887 | ||
868 | 888 | ||
869 | // to do: fix the code below; also, it might work without /dev; impose seccomp/caps filters when not root | 889 | // 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> | 890 | #include <sys/utsname.h> |
871 | void fs_overlayfs(void) { | 891 | void fs_overlayfs(void) { |
892 | struct stat s; | ||
893 | |||
872 | // check kernel version | 894 | // check kernel version |
873 | struct utsname u; | 895 | struct utsname u; |
874 | int rv = uname(&u); | 896 | int rv = uname(&u); |
@@ -894,50 +916,78 @@ void fs_overlayfs(void) { | |||
894 | char *oroot = RUN_OVERLAY_ROOT; | 916 | char *oroot = RUN_OVERLAY_ROOT; |
895 | mkdir_attr(oroot, 0755, 0, 0); | 917 | mkdir_attr(oroot, 0755, 0, 0); |
896 | 918 | ||
897 | struct stat s; | 919 | // set base for working and diff directories |
898 | char *basedir = RUN_MNT_DIR; | 920 | char *basedir = RUN_MNT_DIR; |
921 | int basefd = -1; | ||
922 | |||
899 | if (arg_overlay_keep) { | 923 | if (arg_overlay_keep) { |
900 | // set base for working and diff directories | ||
901 | basedir = cfg.overlay_dir; | 924 | basedir = cfg.overlay_dir; |
902 | assert(basedir); | 925 | assert(basedir); |
903 | 926 | // get a file descriptor for ~/.firejail, fails if there is any symlink | |
904 | // does the overlay exist? | 927 | char *firejail; |
905 | if (stat(basedir, &s) == 0) { | 928 | if (asprintf(&firejail, "%s/.firejail", cfg.homedir) == -1) |
906 | if (arg_overlay_reuse == 0) { | 929 | errExit("asprintf"); |
907 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | 930 | int fd = safe_fd(firejail, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
908 | exit(1); | 931 | if (fd == -1) |
909 | } | 932 | errExit("safe_fd"); |
910 | } | 933 | free(firejail); |
911 | else { | 934 | // create basedir if it doesn't exist |
912 | /* coverity[toctou] */ | 935 | // the new directory will be owned by root |
913 | if (mkdir(basedir, 0755) != 0) { | 936 | const char *dirname = gnu_basename(basedir); |
914 | fprintf(stderr, "Error: cannot create overlay directory\n"); | 937 | if (mkdirat(fd, dirname, 0755) == -1 && errno != EEXIST) { |
915 | exit(1); | 938 | perror("mkdir"); |
916 | } | 939 | fprintf(stderr, "Error: cannot create overlay directory %s\n", basedir); |
940 | exit(1); | ||
917 | } | 941 | } |
942 | // open basedir | ||
943 | basefd = openat(fd, dirname, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
944 | close(fd); | ||
945 | } | ||
946 | else { | ||
947 | basefd = open(basedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
948 | } | ||
949 | if (basefd == -1) { | ||
950 | perror("open"); | ||
951 | fprintf(stderr, "Error: cannot open overlay directory %s\n", basedir); | ||
952 | exit(1); | ||
918 | } | 953 | } |
919 | 954 | ||
920 | char *odiff; | 955 | // confirm once more base is owned by root |
921 | if(asprintf(&odiff, "%s/odiff", basedir) == -1) | 956 | if (fstat(basefd, &s) == -1) |
922 | errExit("asprintf"); | 957 | errExit("fstat"); |
958 | if (s.st_uid != 0) { | ||
959 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", basedir); | ||
960 | exit(1); | ||
961 | } | ||
962 | // confirm permissions of base are 0755 | ||
963 | if (((S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) & s.st_mode) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) { | ||
964 | fprintf(stderr, "Error: invalid permissions on overlay directory %s\n", basedir); | ||
965 | exit(1); | ||
966 | } | ||
923 | 967 | ||
968 | // create diff and work directories inside base | ||
924 | // no need to check arg_overlay_reuse | 969 | // no need to check arg_overlay_reuse |
925 | if (stat(odiff, &s) != 0) { | 970 | char *odiff; |
926 | mkdir_attr(odiff, 0755, 0, 0); | 971 | if (asprintf(&odiff, "%s/odiff", basedir) == -1) |
972 | errExit("asprintf"); | ||
973 | // the new directory will be owned by root | ||
974 | if (mkdirat(basefd, "odiff", 0755) == -1 && errno != EEXIST) { | ||
975 | perror("mkdir"); | ||
976 | fprintf(stderr, "Error: cannot create overlay directory %s\n", odiff); | ||
977 | exit(1); | ||
927 | } | 978 | } |
928 | else if (set_perms(odiff, 0, 0, 0755)) | 979 | ASSERT_PERMS(odiff, 0, 0, 0755); |
929 | errExit("set_perms"); | ||
930 | 980 | ||
931 | char *owork; | 981 | char *owork; |
932 | if(asprintf(&owork, "%s/owork", basedir) == -1) | 982 | if (asprintf(&owork, "%s/owork", basedir) == -1) |
933 | errExit("asprintf"); | 983 | errExit("asprintf"); |
934 | 984 | // the new directory will be owned by root | |
935 | // no need to check arg_overlay_reuse | 985 | if (mkdirat(basefd, "owork", 0755) == -1 && errno != EEXIST) { |
936 | if (stat(owork, &s) != 0) { | 986 | perror("mkdir"); |
937 | mkdir_attr(owork, 0755, 0, 0); | 987 | fprintf(stderr, "Error: cannot create overlay directory %s\n", owork); |
988 | exit(1); | ||
938 | } | 989 | } |
939 | else if (set_perms(owork, 0, 0, 0755)) | 990 | ASSERT_PERMS(owork, 0, 0, 0755); |
940 | errExit("chown"); | ||
941 | 991 | ||
942 | // mount overlayfs | 992 | // mount overlayfs |
943 | if (arg_debug) | 993 | if (arg_debug) |
@@ -977,43 +1027,48 @@ void fs_overlayfs(void) { | |||
977 | 1027 | ||
978 | // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? | 1028 | // 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 | 1029 | // must create var for oroot/cfg.homedir |
980 | if (asprintf(&overlayhome,"%s%s",oroot,cfg.homedir) == -1) | 1030 | if (asprintf(&overlayhome, "%s%s", oroot, cfg.homedir) == -1) |
981 | errExit("asprintf"); | 1031 | errExit("asprintf"); |
982 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n",overlayhome); | 1032 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n", overlayhome); |
983 | 1033 | ||
984 | // if no homedir in overlay -- create another overlay for /home | 1034 | // if no homedir in overlay -- create another overlay for /home |
985 | if (stat(overlayhome, &s) == -1) { | 1035 | 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 | 1036 | ||
993 | // no need to check arg_overlay_reuse | 1037 | // no need to check arg_overlay_reuse |
994 | if (stat(hdiff, &s) != 0) { | 1038 | 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"); | 1039 | errExit("asprintf"); |
1040 | // the new directory will be owned by root | ||
1041 | if (mkdirat(basefd, "hdiff", 0755) == -1 && errno != EEXIST) { | ||
1042 | perror("mkdir"); | ||
1043 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hdiff); | ||
1044 | exit(1); | ||
1045 | } | ||
1046 | ASSERT_PERMS(hdiff, 0, 0, 0755); | ||
1002 | 1047 | ||
1003 | // no need to check arg_overlay_reuse | 1048 | // no need to check arg_overlay_reuse |
1004 | if (stat(hwork, &s) != 0) { | 1049 | if (asprintf(&hwork, "%s/hwork", basedir) == -1) |
1005 | mkdir_attr(hwork, S_IRWXU | S_IRWXG | S_IRWXO, 0, 0); | 1050 | errExit("asprintf"); |
1051 | // the new directory will be owned by root | ||
1052 | if (mkdirat(basefd, "hwork", 0755) == -1 && errno != EEXIST) { | ||
1053 | perror("mkdir"); | ||
1054 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hwork); | ||
1055 | exit(1); | ||
1006 | } | 1056 | } |
1007 | else if (set_perms(hwork, 0, 0, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) | 1057 | ASSERT_PERMS(hwork, 0, 0, 0755); |
1008 | errExit("set_perms"); | ||
1009 | 1058 | ||
1010 | // no homedir in overlay so now mount another overlay for /home | 1059 | // no homedir in overlay so now mount another overlay for /home |
1060 | if (asprintf(&hroot, "%s/home", oroot) == -1) | ||
1061 | errExit("asprintf"); | ||
1011 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) | 1062 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) |
1012 | errExit("asprintf"); | 1063 | errExit("asprintf"); |
1013 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) | 1064 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) |
1014 | errExit("mounting overlayfs for mounted home directory"); | 1065 | errExit("mounting overlayfs for mounted home directory"); |
1015 | 1066 | ||
1016 | printf("OverlayFS for /home configured in %s directory\n", basedir); | 1067 | printf("OverlayFS for /home configured in %s directory\n", basedir); |
1068 | free(hroot); | ||
1069 | free(hdiff); | ||
1070 | free(hwork); | ||
1071 | |||
1017 | } // stat(overlayhome) | 1072 | } // stat(overlayhome) |
1018 | free(overlayhome); | 1073 | free(overlayhome); |
1019 | } | 1074 | } |
@@ -1021,7 +1076,9 @@ void fs_overlayfs(void) { | |||
1021 | //*************************** | 1076 | //*************************** |
1022 | } | 1077 | } |
1023 | fmessage("OverlayFS configured in %s directory\n", basedir); | 1078 | fmessage("OverlayFS configured in %s directory\n", basedir); |
1079 | close(basefd); | ||
1024 | 1080 | ||
1081 | // /dev, /run and /tmp are not covered by the overlay | ||
1025 | // mount-bind dev directory | 1082 | // mount-bind dev directory |
1026 | if (arg_debug) | 1083 | if (arg_debug) |
1027 | printf("Mounting /dev\n"); | 1084 | printf("Mounting /dev\n"); |
@@ -1042,19 +1099,15 @@ void fs_overlayfs(void) { | |||
1042 | errExit("mounting /run"); | 1099 | errExit("mounting /run"); |
1043 | fs_logger("whitelist /run"); | 1100 | fs_logger("whitelist /run"); |
1044 | 1101 | ||
1045 | // mount-bind /tmp/.X11-unix directory | 1102 | // mount-bind tmp directory |
1046 | if (stat("/tmp/.X11-unix", &s) == 0) { | 1103 | if (arg_debug) |
1047 | if (arg_debug) | 1104 | printf("Mounting /tmp\n"); |
1048 | printf("Mounting /tmp/.X11-unix\n"); | 1105 | char *tmp; |
1049 | char *x11; | 1106 | if (asprintf(&tmp, "%s/tmp", oroot) == -1) |
1050 | if (asprintf(&x11, "%s/tmp/.X11-unix", oroot) == -1) | 1107 | errExit("asprintf"); |
1051 | errExit("asprintf"); | 1108 | 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) | 1109 | errExit("mounting /tmp"); |
1053 | fwarning("cannot mount /tmp/.X11-unix in overlay\n"); | 1110 | fs_logger("whitelist /tmp"); |
1054 | else | ||
1055 | fs_logger("whitelist /tmp/.X11-unix"); | ||
1056 | free(x11); | ||
1057 | } | ||
1058 | 1111 | ||
1059 | // chroot in the new filesystem | 1112 | // chroot in the new filesystem |
1060 | #ifdef HAVE_GCOV | 1113 | #ifdef HAVE_GCOV |
@@ -1068,12 +1121,9 @@ void fs_overlayfs(void) { | |||
1068 | // fs_dev_shm(); | 1121 | // fs_dev_shm(); |
1069 | fs_var_lock(); | 1122 | fs_var_lock(); |
1070 | if (!arg_keep_var_tmp) | 1123 | if (!arg_keep_var_tmp) |
1071 | fs_var_tmp(); | 1124 | fs_var_tmp(); |
1072 | if (!arg_writable_var_log) | 1125 | if (!arg_writable_var_log) |
1073 | fs_var_log(); | 1126 | fs_var_log(); |
1074 | else | ||
1075 | fs_rdwr("/var/log"); | ||
1076 | |||
1077 | fs_var_lib(); | 1127 | fs_var_lib(); |
1078 | fs_var_cache(); | 1128 | fs_var_cache(); |
1079 | fs_var_utmp(); | 1129 | fs_var_utmp(); |
@@ -1089,97 +1139,124 @@ void fs_overlayfs(void) { | |||
1089 | // cleanup and exit | 1139 | // cleanup and exit |
1090 | free(option); | 1140 | free(option); |
1091 | free(odiff); | 1141 | free(odiff); |
1142 | free(owork); | ||
1143 | free(dev); | ||
1144 | free(run); | ||
1145 | free(tmp); | ||
1092 | } | 1146 | } |
1093 | #endif | 1147 | #endif |
1094 | 1148 | ||
1095 | 1149 | ||
1096 | #ifdef HAVE_CHROOT | 1150 | #ifdef HAVE_CHROOT |
1097 | // return 1 if error | 1151 | // exit if error |
1098 | void fs_check_chroot_dir(const char *rootdir) { | 1152 | void fs_check_chroot_dir(const char *rootdir) { |
1099 | EUID_ASSERT(); | 1153 | EUID_ASSERT(); |
1100 | assert(rootdir); | 1154 | assert(rootdir); |
1101 | struct stat s; | 1155 | struct stat s; |
1102 | char *name; | 1156 | int fd = -1; |
1157 | int parentfd = -1; | ||
1103 | 1158 | ||
1104 | if (strcmp(rootdir, "/tmp") == 0 || strcmp(rootdir, "/var/tmp") == 0) { | 1159 | char *overlay; |
1105 | fprintf(stderr, "Error: invalid chroot directory\n"); | 1160 | if (asprintf(&overlay, "%s/.firejail", cfg.homedir) == -1) |
1161 | errExit("asprintf"); | ||
1162 | if (strncmp(rootdir, overlay, strlen(overlay)) == 0) { | ||
1163 | fprintf(stderr, "Error: invalid chroot directory: no directories in ~/.firejail are allowed\n"); | ||
1106 | exit(1); | 1164 | exit(1); |
1107 | } | 1165 | } |
1166 | free(overlay); | ||
1108 | 1167 | ||
1109 | // rootdir has to be owned by root | 1168 | // fails if there is any symlink or if rootdir is not a directory |
1110 | if (stat(rootdir, &s) != 0) { | 1169 | parentfd = safe_fd(rootdir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
1111 | fprintf(stderr, "Error: cannot find chroot directory\n"); | 1170 | if (parentfd == -1) { |
1171 | fprintf(stderr, "Error: invalid chroot directory %s\n", rootdir); | ||
1112 | exit(1); | 1172 | exit(1); |
1113 | } | 1173 | } |
1174 | // rootdir has to be owned by root and is not allowed to be generally writable, | ||
1175 | // this also excludes /tmp, /var/tmp and such | ||
1176 | if (fstat(parentfd, &s) == -1) | ||
1177 | errExit("fstat"); | ||
1114 | if (s.st_uid != 0) { | 1178 | if (s.st_uid != 0) { |
1115 | fprintf(stderr, "Error: chroot directory should be owned by root\n"); | 1179 | fprintf(stderr, "Error: chroot directory should be owned by root\n"); |
1116 | exit(1); | 1180 | exit(1); |
1117 | } | 1181 | } |
1182 | if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) { | ||
1183 | fprintf(stderr, "Error: only root user should be given write permission on chroot directory\n"); | ||
1184 | exit(1); | ||
1185 | } | ||
1118 | 1186 | ||
1119 | // check /dev | 1187 | // check /dev |
1120 | if (asprintf(&name, "%s/dev", rootdir) == -1) | 1188 | fd = openat(parentfd, "dev", O_PATH|O_CLOEXEC); |
1121 | errExit("asprintf"); | 1189 | if (fd == -1) { |
1122 | if (stat(name, &s) == -1) { | 1190 | fprintf(stderr, "Error: cannot open /dev in chroot directory\n"); |
1123 | fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); | ||
1124 | exit(1); | 1191 | exit(1); |
1125 | } | 1192 | } |
1126 | if (s.st_uid != 0) { | 1193 | if (fstat(fd, &s) == -1) |
1127 | fprintf(stderr, "Error: chroot /dev directory should be owned by root\n"); | 1194 | errExit("fstat"); |
1195 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1196 | fprintf(stderr, "Error: chroot /dev should be a directory owned by root\n"); | ||
1128 | exit(1); | 1197 | exit(1); |
1129 | } | 1198 | } |
1130 | free(name); | 1199 | close(fd); |
1131 | 1200 | ||
1132 | // check /var/tmp | 1201 | // check /var/tmp |
1133 | if (asprintf(&name, "%s/var/tmp", rootdir) == -1) | 1202 | fd = openat(parentfd, "var/tmp", O_PATH|O_CLOEXEC); |
1134 | errExit("asprintf"); | 1203 | if (fd == -1) { |
1135 | if (stat(name, &s) == -1) { | 1204 | fprintf(stderr, "Error: cannot open /var/tmp in chroot directory\n"); |
1136 | fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); | ||
1137 | exit(1); | 1205 | exit(1); |
1138 | } | 1206 | } |
1139 | if (s.st_uid != 0) { | 1207 | if (fstat(fd, &s) == -1) |
1140 | fprintf(stderr, "Error: chroot /var/tmp directory should be owned by root\n"); | 1208 | errExit("fstat"); |
1209 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1210 | fprintf(stderr, "Error: chroot /var/tmp should be a directory owned by root\n"); | ||
1141 | exit(1); | 1211 | exit(1); |
1142 | } | 1212 | } |
1143 | free(name); | 1213 | close(fd); |
1144 | 1214 | ||
1145 | // check /proc | 1215 | // check /proc |
1146 | if (asprintf(&name, "%s/proc", rootdir) == -1) | 1216 | fd = openat(parentfd, "proc", O_PATH|O_CLOEXEC); |
1147 | errExit("asprintf"); | 1217 | if (fd == -1) { |
1148 | if (stat(name, &s) == -1) { | 1218 | fprintf(stderr, "Error: cannot open /proc in chroot directory\n"); |
1149 | fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); | ||
1150 | exit(1); | 1219 | exit(1); |
1151 | } | 1220 | } |
1152 | if (s.st_uid != 0) { | 1221 | if (fstat(fd, &s) == -1) |
1153 | fprintf(stderr, "Error: chroot /proc directory should be owned by root\n"); | 1222 | errExit("fstat"); |
1223 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1224 | fprintf(stderr, "Error: chroot /proc should be a directory owned by root\n"); | ||
1154 | exit(1); | 1225 | exit(1); |
1155 | } | 1226 | } |
1156 | free(name); | 1227 | close(fd); |
1157 | 1228 | ||
1158 | // check /tmp | 1229 | // check /tmp |
1159 | if (asprintf(&name, "%s/tmp", rootdir) == -1) | 1230 | fd = openat(parentfd, "tmp", O_PATH|O_CLOEXEC); |
1160 | errExit("asprintf"); | 1231 | if (fd == -1) { |
1161 | if (stat(name, &s) == -1) { | 1232 | fprintf(stderr, "Error: cannot open /tmp in chroot directory\n"); |
1162 | fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); | ||
1163 | exit(1); | 1233 | exit(1); |
1164 | } | 1234 | } |
1165 | if (s.st_uid != 0) { | 1235 | if (fstat(fd, &s) == -1) |
1166 | fprintf(stderr, "Error: chroot /tmp directory should be owned by root\n"); | 1236 | errExit("fstat"); |
1237 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1238 | fprintf(stderr, "Error: chroot /tmp should be a directory owned by root\n"); | ||
1167 | exit(1); | 1239 | exit(1); |
1168 | } | 1240 | } |
1169 | free(name); | 1241 | close(fd); |
1170 | 1242 | ||
1171 | // check /etc | 1243 | // check /etc |
1172 | if (asprintf(&name, "%s/etc", rootdir) == -1) | 1244 | fd = openat(parentfd, "etc", O_PATH|O_CLOEXEC); |
1173 | errExit("asprintf"); | 1245 | if (fd == -1) { |
1174 | if (stat(name, &s) == -1) { | 1246 | fprintf(stderr, "Error: cannot open /etc in chroot directory\n"); |
1175 | fprintf(stderr, "Error: cannot find /etc in chroot directory\n"); | ||
1176 | exit(1); | 1247 | exit(1); |
1177 | } | 1248 | } |
1178 | if (s.st_uid != 0) { | 1249 | if (fstat(fd, &s) == -1) |
1179 | fprintf(stderr, "Error: chroot /etc directory should be owned by root\n"); | 1250 | errExit("fstat"); |
1251 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1252 | fprintf(stderr, "Error: chroot /etc should be a directory owned by root\n"); | ||
1180 | exit(1); | 1253 | exit(1); |
1181 | } | 1254 | } |
1182 | free(name); | 1255 | if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) { |
1256 | fprintf(stderr, "Error: only root user should be given write permission on chroot /etc\n"); | ||
1257 | exit(1); | ||
1258 | } | ||
1259 | close(fd); | ||
1183 | 1260 | ||
1184 | // there should be no checking on <chrootdir>/etc/resolv.conf | 1261 | // there should be no checking on <chrootdir>/etc/resolv.conf |
1185 | // the file is replaced with the real /etc/resolv.conf anyway | 1262 | // the file is replaced with the real /etc/resolv.conf anyway |
@@ -1211,19 +1288,21 @@ void fs_check_chroot_dir(const char *rootdir) { | |||
1211 | 1288 | ||
1212 | // check x11 socket directory | 1289 | // check x11 socket directory |
1213 | if (getenv("FIREJAIL_X11")) { | 1290 | if (getenv("FIREJAIL_X11")) { |
1214 | char *name; | 1291 | fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_CLOEXEC); |
1215 | if (asprintf(&name, "%s/tmp/.X11-unix", rootdir) == -1) | 1292 | if (fd == -1) { |
1216 | errExit("asprintf"); | 1293 | fprintf(stderr, "Error: cannot open /tmp/.X11-unix in chroot directory\n"); |
1217 | if (stat(name, &s) == -1) { | ||
1218 | fprintf(stderr, "Error: cannot find /tmp/.X11-unix in chroot directory\n"); | ||
1219 | exit(1); | 1294 | exit(1); |
1220 | } | 1295 | } |
1221 | if (s.st_uid != 0) { | 1296 | if (fstat(fd, &s) == -1) |
1222 | fprintf(stderr, "Error: chroot /tmp/.X11-unix directory should be owned by root\n"); | 1297 | errExit("fstat"); |
1298 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1299 | fprintf(stderr, "Error: chroot /tmp/.X11-unix should be a directory owned by root\n"); | ||
1223 | exit(1); | 1300 | exit(1); |
1224 | } | 1301 | } |
1225 | free(name); | 1302 | close(fd); |
1226 | } | 1303 | } |
1304 | |||
1305 | close(parentfd); | ||
1227 | } | 1306 | } |
1228 | 1307 | ||
1229 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf | 1308 | // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf |
@@ -1254,27 +1333,49 @@ void fs_chroot(const char *rootdir) { | |||
1254 | 1333 | ||
1255 | // some older distros don't have a /run directory | 1334 | // some older distros don't have a /run directory |
1256 | // create one by default | 1335 | // create one by default |
1257 | // create /run/firejail directory in chroot | ||
1258 | char *rundir; | 1336 | char *rundir; |
1259 | if (asprintf(&rundir, "%s/run", rootdir) == -1) | 1337 | if (asprintf(&rundir, "%s/run", rootdir) == -1) |
1260 | errExit("asprintf"); | 1338 | errExit("asprintf"); |
1261 | if (is_link(rundir)) { | 1339 | struct stat s; |
1262 | fprintf(stderr, "Error: invalid run directory inside chroot\n"); | 1340 | if (lstat(rundir, &s) == 0) { |
1263 | exit(1); | 1341 | if (S_ISLNK(s.st_mode)) { |
1342 | fprintf(stderr, "Error: chroot /run is a symbolic link\n"); | ||
1343 | exit(1); | ||
1344 | } | ||
1345 | if (!S_ISDIR(s.st_mode) || s.st_uid != 0) { | ||
1346 | fprintf(stderr, "Error: chroot /run should be a directory owned by root\n"); | ||
1347 | exit(1); | ||
1348 | } | ||
1349 | if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) { | ||
1350 | fprintf(stderr, "Error: only root user should be given write permission on chroot /run\n"); | ||
1351 | exit(1); | ||
1352 | } | ||
1353 | } | ||
1354 | else { | ||
1355 | // several sandboxes could race to create /run | ||
1356 | if (mkdir(rundir, 0755) == -1 && errno != EEXIST) | ||
1357 | errExit("mkdir"); | ||
1358 | ASSERT_PERMS(rundir, 0, 0, 0755); | ||
1264 | } | 1359 | } |
1265 | create_empty_dir_as_root(rundir, 0755); | ||
1266 | free(rundir); | 1360 | free(rundir); |
1361 | |||
1362 | // create /run/firejail directory in chroot | ||
1267 | if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1) | 1363 | if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1) |
1268 | errExit("asprintf"); | 1364 | errExit("asprintf"); |
1269 | create_empty_dir_as_root(rundir, 0755); | 1365 | if (mkdir(rundir, 0755) == -1 && errno != EEXIST) |
1366 | errExit("mkdir"); | ||
1367 | ASSERT_PERMS(rundir, 0, 0, 0755); | ||
1270 | free(rundir); | 1368 | free(rundir); |
1271 | 1369 | ||
1272 | // create /run/firejail/mnt directory in chroot and mount the current one | 1370 | // create /run/firejail/mnt directory in chroot and mount the current one |
1273 | if (asprintf(&rundir, "%s%s", rootdir, RUN_MNT_DIR) == -1) | 1371 | if (asprintf(&rundir, "%s%s", rootdir, RUN_MNT_DIR) == -1) |
1274 | errExit("asprintf"); | 1372 | errExit("asprintf"); |
1275 | create_empty_dir_as_root(rundir, 0755); | 1373 | if (mkdir(rundir, 0755) == -1 && errno != EEXIST) |
1374 | errExit("mkdir"); | ||
1375 | ASSERT_PERMS(rundir, 0, 0, 0755); | ||
1276 | if (mount(RUN_MNT_DIR, rundir, NULL, MS_BIND|MS_REC, NULL) < 0) | 1376 | if (mount(RUN_MNT_DIR, rundir, NULL, MS_BIND|MS_REC, NULL) < 0) |
1277 | errExit("mount bind"); | 1377 | errExit("mount bind"); |
1378 | free(rundir); | ||
1278 | 1379 | ||
1279 | // copy /etc/resolv.conf in chroot directory | 1380 | // copy /etc/resolv.conf in chroot directory |
1280 | char *fname; | 1381 | char *fname; |
@@ -1285,6 +1386,7 @@ void fs_chroot(const char *rootdir) { | |||
1285 | unlink(fname); | 1386 | unlink(fname); |
1286 | if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) // root needed | 1387 | if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) // root needed |
1287 | fwarning("/etc/resolv.conf not initialized\n"); | 1388 | fwarning("/etc/resolv.conf not initialized\n"); |
1389 | free(fname); | ||
1288 | 1390 | ||
1289 | // chroot into the new directory | 1391 | // chroot into the new directory |
1290 | #ifdef HAVE_GCOV | 1392 | #ifdef HAVE_GCOV |
@@ -1295,7 +1397,8 @@ void fs_chroot(const char *rootdir) { | |||
1295 | if (arg_debug) | 1397 | if (arg_debug) |
1296 | printf("Chrooting into %s\n", rootdir); | 1398 | printf("Chrooting into %s\n", rootdir); |
1297 | char *oroot = RUN_OVERLAY_ROOT; | 1399 | char *oroot = RUN_OVERLAY_ROOT; |
1298 | mkdir_attr(oroot, 0755, 0, 0); | 1400 | if (mkdir(oroot, 0755) == -1) |
1401 | errExit("mkdir"); | ||
1299 | if (mount(rootdir, oroot, NULL, MS_BIND|MS_REC, NULL) < 0) | 1402 | if (mount(rootdir, oroot, NULL, MS_BIND|MS_REC, NULL) < 0) |
1300 | errExit("mounting rootdir oroot"); | 1403 | errExit("mounting rootdir oroot"); |
1301 | if (chroot(oroot) < 0) | 1404 | if (chroot(oroot) < 0) |
@@ -1312,8 +1415,6 @@ void fs_chroot(const char *rootdir) { | |||
1312 | fs_var_tmp(); | 1415 | fs_var_tmp(); |
1313 | if (!arg_writable_var_log) | 1416 | if (!arg_writable_var_log) |
1314 | fs_var_log(); | 1417 | fs_var_log(); |
1315 | else | ||
1316 | fs_rdwr("/var/log"); | ||
1317 | 1418 | ||
1318 | fs_var_lib(); | 1419 | fs_var_lib(); |
1319 | fs_var_cache(); | 1420 | fs_var_cache(); |
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index 602985b4e..1fd1fb675 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -371,10 +371,13 @@ void fs_whitelist(void) { | |||
371 | 371 | ||
372 | // resolve macros | 372 | // resolve macros |
373 | if (is_macro(dataptr)) { | 373 | if (is_macro(dataptr)) { |
374 | char *tmp = resolve_macro(dataptr); | 374 | char *tmp = resolve_macro(dataptr); // returns allocated mem |
375 | if (tmp != NULL) | 375 | if (tmp != NULL) { |
376 | tmp = parse_nowhitelist(nowhitelist_flag, tmp); | 376 | char *tmp1 = parse_nowhitelist(nowhitelist_flag, tmp); |
377 | 377 | assert(tmp1); | |
378 | free(tmp); | ||
379 | tmp = tmp1; | ||
380 | } | ||
378 | if (tmp) { | 381 | if (tmp) { |
379 | entry->data = tmp; | 382 | entry->data = tmp; |
380 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; | 383 | dataptr = (nowhitelist_flag)? entry->data + 12: entry->data + 10; |
@@ -491,6 +494,7 @@ void fs_whitelist(void) { | |||
491 | printf("\"%s\" disabled by --private\n", entry->data); | 494 | printf("\"%s\" disabled by --private\n", entry->data); |
492 | 495 | ||
493 | entry->data = EMPTY_STRING; | 496 | entry->data = EMPTY_STRING; |
497 | free(fname); | ||
494 | continue; | 498 | continue; |
495 | } | 499 | } |
496 | 500 | ||
@@ -503,14 +507,18 @@ void fs_whitelist(void) { | |||
503 | // both path and absolute path are under /home | 507 | // both path and absolute path are under /home |
504 | if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0) { | 508 | if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0) { |
505 | // entire home directory is not allowed | 509 | // entire home directory is not allowed |
506 | if (*(fname + strlen(cfg.homedir)) != '/') | 510 | if (*(fname + strlen(cfg.homedir)) != '/') { |
511 | free(fname); | ||
507 | goto errexit; | 512 | goto errexit; |
513 | } | ||
508 | } | 514 | } |
509 | else { | 515 | else { |
510 | if (checkcfg(CFG_FOLLOW_SYMLINK_AS_USER)) { | 516 | if (checkcfg(CFG_FOLLOW_SYMLINK_AS_USER)) { |
511 | // check if the file is owned by the user | 517 | // check if the file is owned by the user |
512 | if (stat(fname, &s) == 0 && s.st_uid != getuid()) | 518 | if (stat(fname, &s) == 0 && s.st_uid != getuid()) { |
519 | free(fname); | ||
513 | goto errexit; | 520 | goto errexit; |
521 | } | ||
514 | } | 522 | } |
515 | } | 523 | } |
516 | } | 524 | } |
@@ -520,6 +528,7 @@ void fs_whitelist(void) { | |||
520 | 528 | ||
521 | // both path and absolute path are under /tmp | 529 | // both path and absolute path are under /tmp |
522 | if (strncmp(fname, "/tmp/", 5) != 0) { | 530 | if (strncmp(fname, "/tmp/", 5) != 0) { |
531 | free(fname); | ||
523 | goto errexit; | 532 | goto errexit; |
524 | } | 533 | } |
525 | } | 534 | } |
@@ -528,6 +537,7 @@ void fs_whitelist(void) { | |||
528 | media_dir = 1; | 537 | media_dir = 1; |
529 | // both path and absolute path are under /media | 538 | // both path and absolute path are under /media |
530 | if (strncmp(fname, "/media/", 7) != 0) { | 539 | if (strncmp(fname, "/media/", 7) != 0) { |
540 | free(fname); | ||
531 | goto errexit; | 541 | goto errexit; |
532 | } | 542 | } |
533 | } | 543 | } |
@@ -536,6 +546,7 @@ void fs_whitelist(void) { | |||
536 | mnt_dir = 1; | 546 | mnt_dir = 1; |
537 | // both path and absolute path are under /mnt | 547 | // both path and absolute path are under /mnt |
538 | if (strncmp(fname, "/mnt/", 5) != 0) { | 548 | if (strncmp(fname, "/mnt/", 5) != 0) { |
549 | free(fname); | ||
539 | goto errexit; | 550 | goto errexit; |
540 | } | 551 | } |
541 | } | 552 | } |
@@ -550,6 +561,7 @@ void fs_whitelist(void) { | |||
550 | else { | 561 | else { |
551 | // both path and absolute path are under /var | 562 | // both path and absolute path are under /var |
552 | if (strncmp(fname, "/var/", 5) != 0) { | 563 | if (strncmp(fname, "/var/", 5) != 0) { |
564 | free(fname); | ||
553 | goto errexit; | 565 | goto errexit; |
554 | } | 566 | } |
555 | } | 567 | } |
@@ -570,6 +582,7 @@ void fs_whitelist(void) { | |||
570 | else { | 582 | else { |
571 | // both path and absolute path are under /dev | 583 | // both path and absolute path are under /dev |
572 | if (strncmp(fname, "/dev/", 5) != 0) { | 584 | if (strncmp(fname, "/dev/", 5) != 0) { |
585 | free(fname); | ||
573 | goto errexit; | 586 | goto errexit; |
574 | } | 587 | } |
575 | } | 588 | } |
@@ -579,6 +592,7 @@ void fs_whitelist(void) { | |||
579 | opt_dir = 1; | 592 | opt_dir = 1; |
580 | // both path and absolute path are under /dev | 593 | // both path and absolute path are under /dev |
581 | if (strncmp(fname, "/opt/", 5) != 0) { | 594 | if (strncmp(fname, "/opt/", 5) != 0) { |
595 | free(fname); | ||
582 | goto errexit; | 596 | goto errexit; |
583 | } | 597 | } |
584 | } | 598 | } |
@@ -587,6 +601,7 @@ void fs_whitelist(void) { | |||
587 | srv_dir = 1; | 601 | srv_dir = 1; |
588 | // both path and absolute path are under /srv | 602 | // both path and absolute path are under /srv |
589 | if (strncmp(fname, "/srv/", 5) != 0) { | 603 | if (strncmp(fname, "/srv/", 5) != 0) { |
604 | free(fname); | ||
590 | goto errexit; | 605 | goto errexit; |
591 | } | 606 | } |
592 | } | 607 | } |
@@ -599,25 +614,32 @@ void fs_whitelist(void) { | |||
599 | else if (strcmp(new_name, "/etc/os-release") == 0); | 614 | else if (strcmp(new_name, "/etc/os-release") == 0); |
600 | // both path and absolute path are under /etc | 615 | // both path and absolute path are under /etc |
601 | else { | 616 | else { |
602 | if (strncmp(fname, "/etc/", 5) != 0) | 617 | if (strncmp(fname, "/etc/", 5) != 0) { |
618 | free(fname); | ||
603 | goto errexit; | 619 | goto errexit; |
620 | } | ||
604 | } | 621 | } |
605 | } | 622 | } |
606 | else if (strncmp(new_name, "/usr/share/", 11) == 0) { | 623 | else if (strncmp(new_name, "/usr/share/", 11) == 0) { |
607 | entry->share_dir = 1; | 624 | entry->share_dir = 1; |
608 | share_dir = 1; | 625 | share_dir = 1; |
609 | // both path and absolute path are under /etc | 626 | // both path and absolute path are under /etc |
610 | if (strncmp(fname, "/usr/share/", 11) != 0) | 627 | if (strncmp(fname, "/usr/share/", 11) != 0) { |
628 | free(fname); | ||
611 | goto errexit; | 629 | goto errexit; |
630 | } | ||
612 | } | 631 | } |
613 | else if (strncmp(new_name, "/sys/module/", 12) == 0) { | 632 | else if (strncmp(new_name, "/sys/module/", 12) == 0) { |
614 | entry->module_dir = 1; | 633 | entry->module_dir = 1; |
615 | module_dir = 1; | 634 | module_dir = 1; |
616 | // both path and absolute path are under /sys/module | 635 | // both path and absolute path are under /sys/module |
617 | if (strncmp(fname, "/sys/module/", 12) != 0) | 636 | if (strncmp(fname, "/sys/module/", 12) != 0) { |
637 | free(fname); | ||
618 | goto errexit; | 638 | goto errexit; |
639 | } | ||
619 | } | 640 | } |
620 | else { | 641 | else { |
642 | free(fname); | ||
621 | goto errexit; | 643 | goto errexit; |
622 | } | 644 | } |
623 | 645 | ||
diff --git a/src/firejail/main.c b/src/firejail/main.c index c87032f6d..d35d8c207 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -777,18 +777,15 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
777 | 777 | ||
778 | } | 778 | } |
779 | 779 | ||
780 | |||
781 | |||
782 | char *guess_shell(void) { | 780 | char *guess_shell(void) { |
783 | char *shell = NULL; | 781 | char *shell = NULL; |
784 | struct stat s; | 782 | struct stat s; |
785 | 783 | ||
786 | shell = getenv("SHELL"); | 784 | shell = getenv("SHELL"); |
787 | if (shell) { | 785 | if (shell) { |
788 | // TODO: handle rogue shell variables? | 786 | invalid_filename(shell, 0); // no globbing |
789 | if (stat(shell, &s) == 0 && access(shell, R_OK) == 0) { | 787 | if (!is_dir(shell) && strstr(shell, "..") == NULL && stat(shell, &s) == 0 && access(shell, X_OK) == 0) |
790 | return shell; | 788 | return shell; |
791 | } | ||
792 | } | 789 | } |
793 | 790 | ||
794 | // shells in order of preference | 791 | // shells in order of preference |
@@ -797,7 +794,7 @@ char *guess_shell(void) { | |||
797 | int i = 0; | 794 | int i = 0; |
798 | while (shells[i] != NULL) { | 795 | while (shells[i] != NULL) { |
799 | // access call checks as real UID/GID, not as effective UID/GID | 796 | // access call checks as real UID/GID, not as effective UID/GID |
800 | if (stat(shells[i], &s) == 0 && access(shells[i], R_OK) == 0) { | 797 | if (stat(shells[i], &s) == 0 && access(shells[i], X_OK) == 0) { |
801 | shell = shells[i]; | 798 | shell = shells[i]; |
802 | break; | 799 | break; |
803 | } | 800 | } |
@@ -867,6 +864,8 @@ int main(int argc, char **argv) { | |||
867 | int lockfd_directory = -1; | 864 | int lockfd_directory = -1; |
868 | int option_cgroup = 0; | 865 | int option_cgroup = 0; |
869 | int custom_profile = 0; // custom profile loaded | 866 | int custom_profile = 0; // custom profile loaded |
867 | int arg_seccomp_cmdline = 0; // seccomp requested on command line (used to break out of --chroot) | ||
868 | int arg_caps_cmdline = 0; // caps requested on command line (used to break out of --chroot) | ||
870 | 869 | ||
871 | // drop permissions by default and rise them when required | 870 | // drop permissions by default and rise them when required |
872 | EUID_INIT(); | 871 | EUID_INIT(); |
@@ -1154,6 +1153,7 @@ int main(int argc, char **argv) { | |||
1154 | } | 1153 | } |
1155 | arg_seccomp = 1; | 1154 | arg_seccomp = 1; |
1156 | cfg.seccomp_list = seccomp_check_list(argv[i] + 10); | 1155 | cfg.seccomp_list = seccomp_check_list(argv[i] + 10); |
1156 | arg_seccomp_cmdline = 1; | ||
1157 | } | 1157 | } |
1158 | else | 1158 | else |
1159 | exit_err_feature("seccomp"); | 1159 | exit_err_feature("seccomp"); |
@@ -1166,6 +1166,7 @@ int main(int argc, char **argv) { | |||
1166 | } | 1166 | } |
1167 | arg_seccomp = 1; | 1167 | arg_seccomp = 1; |
1168 | cfg.seccomp_list_drop = seccomp_check_list(argv[i] + 15); | 1168 | cfg.seccomp_list_drop = seccomp_check_list(argv[i] + 15); |
1169 | arg_seccomp_cmdline = 1; | ||
1169 | } | 1170 | } |
1170 | else | 1171 | else |
1171 | exit_err_feature("seccomp"); | 1172 | exit_err_feature("seccomp"); |
@@ -1178,6 +1179,7 @@ int main(int argc, char **argv) { | |||
1178 | } | 1179 | } |
1179 | arg_seccomp = 1; | 1180 | arg_seccomp = 1; |
1180 | cfg.seccomp_list_keep = seccomp_check_list(argv[i] + 15); | 1181 | cfg.seccomp_list_keep = seccomp_check_list(argv[i] + 15); |
1182 | arg_seccomp_cmdline = 1; | ||
1181 | } | 1183 | } |
1182 | else | 1184 | else |
1183 | exit_err_feature("seccomp"); | 1185 | exit_err_feature("seccomp"); |
@@ -1196,8 +1198,10 @@ int main(int argc, char **argv) { | |||
1196 | exit_err_feature("seccomp"); | 1198 | exit_err_feature("seccomp"); |
1197 | } | 1199 | } |
1198 | #endif | 1200 | #endif |
1199 | else if (strcmp(argv[i], "--caps") == 0) | 1201 | else if (strcmp(argv[i], "--caps") == 0) { |
1200 | arg_caps_default_filter = 1; | 1202 | arg_caps_default_filter = 1; |
1203 | arg_caps_cmdline = 1; | ||
1204 | } | ||
1201 | else if (strcmp(argv[i], "--caps.drop=all") == 0) | 1205 | else if (strcmp(argv[i], "--caps.drop=all") == 0) |
1202 | arg_caps_drop_all = 1; | 1206 | arg_caps_drop_all = 1; |
1203 | else if (strncmp(argv[i], "--caps.drop=", 12) == 0) { | 1207 | else if (strncmp(argv[i], "--caps.drop=", 12) == 0) { |
@@ -1207,6 +1211,7 @@ int main(int argc, char **argv) { | |||
1207 | errExit("strdup"); | 1211 | errExit("strdup"); |
1208 | // verify caps list and exit if problems | 1212 | // verify caps list and exit if problems |
1209 | caps_check_list(arg_caps_list, NULL); | 1213 | caps_check_list(arg_caps_list, NULL); |
1214 | arg_caps_cmdline = 1; | ||
1210 | } | 1215 | } |
1211 | else if (strncmp(argv[i], "--caps.keep=", 12) == 0) { | 1216 | else if (strncmp(argv[i], "--caps.keep=", 12) == 0) { |
1212 | arg_caps_keep = 1; | 1217 | arg_caps_keep = 1; |
@@ -1215,6 +1220,7 @@ int main(int argc, char **argv) { | |||
1215 | errExit("strdup"); | 1220 | errExit("strdup"); |
1216 | // verify caps list and exit if problems | 1221 | // verify caps list and exit if problems |
1217 | caps_check_list(arg_caps_list, NULL); | 1222 | caps_check_list(arg_caps_list, NULL); |
1223 | arg_caps_cmdline = 1; | ||
1218 | } | 1224 | } |
1219 | 1225 | ||
1220 | 1226 | ||
@@ -1516,13 +1522,12 @@ int main(int argc, char **argv) { | |||
1516 | cfg.chrootdir = tmp; | 1522 | cfg.chrootdir = tmp; |
1517 | } | 1523 | } |
1518 | 1524 | ||
1519 | // check chroot dirname exists | 1525 | if (strstr(cfg.chrootdir, "..") || is_link(cfg.chrootdir)) { |
1520 | if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { | 1526 | fprintf(stderr, "Error: invalid chroot directory %s\n", cfg.chrootdir); |
1521 | fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir); | ||
1522 | return 1; | 1527 | return 1; |
1523 | } | 1528 | } |
1524 | 1529 | ||
1525 | // don't allow "--chroot=/" | 1530 | // check chroot dirname exists, don't allow "--chroot=/" |
1526 | char *rpath = realpath(cfg.chrootdir, NULL); | 1531 | char *rpath = realpath(cfg.chrootdir, NULL); |
1527 | if (rpath == NULL || strcmp(rpath, "/") == 0) { | 1532 | if (rpath == NULL || strcmp(rpath, "/") == 0) { |
1528 | fprintf(stderr, "Error: invalid chroot directory\n"); | 1533 | fprintf(stderr, "Error: invalid chroot directory\n"); |
@@ -2159,12 +2164,12 @@ int main(int argc, char **argv) { | |||
2159 | char *shellpath; | 2164 | char *shellpath; |
2160 | if (asprintf(&shellpath, "%s%s", cfg.chrootdir, cfg.shell) == -1) | 2165 | if (asprintf(&shellpath, "%s%s", cfg.chrootdir, cfg.shell) == -1) |
2161 | errExit("asprintf"); | 2166 | errExit("asprintf"); |
2162 | if (access(shellpath, R_OK)) { | 2167 | if (access(shellpath, X_OK)) { |
2163 | fprintf(stderr, "Error: cannot access shell file in chroot\n"); | 2168 | fprintf(stderr, "Error: cannot access shell file in chroot\n"); |
2164 | exit(1); | 2169 | exit(1); |
2165 | } | 2170 | } |
2166 | free(shellpath); | 2171 | free(shellpath); |
2167 | } else if (access(cfg.shell, R_OK)) { | 2172 | } else if (access(cfg.shell, X_OK)) { |
2168 | fprintf(stderr, "Error: cannot access shell file\n"); | 2173 | fprintf(stderr, "Error: cannot access shell file\n"); |
2169 | exit(1); | 2174 | exit(1); |
2170 | } | 2175 | } |
@@ -2200,12 +2205,6 @@ int main(int argc, char **argv) { | |||
2200 | return 1; | 2205 | return 1; |
2201 | } | 2206 | } |
2202 | } | 2207 | } |
2203 | else if (strcmp(argv[i], "--git-install") == 0 || | ||
2204 | strcmp(argv[i], "--git-uninstall") == 0) { | ||
2205 | fprintf(stderr, "This feature is not enabled in the current build\n"); | ||
2206 | exit(1); | ||
2207 | } | ||
2208 | |||
2209 | else if (strcmp(argv[i], "--") == 0) { | 2208 | else if (strcmp(argv[i], "--") == 0) { |
2210 | // double dash - positional params to follow | 2209 | // double dash - positional params to follow |
2211 | arg_doubledash = 1; | 2210 | arg_doubledash = 1; |
@@ -2242,6 +2241,14 @@ int main(int argc, char **argv) { | |||
2242 | } | 2241 | } |
2243 | EUID_ASSERT(); | 2242 | EUID_ASSERT(); |
2244 | 2243 | ||
2244 | // exit for --chroot sandboxes when secomp or caps are explicitly specified on command line | ||
2245 | if (getuid() != 0 && cfg.chrootdir && (arg_seccomp_cmdline || arg_caps_cmdline)) { | ||
2246 | fprintf(stderr, "Error: for chroot sandboxes, default seccomp and capabilities filters are\n" | ||
2247 | "enabled by default. Please remove all --seccomp and --caps options from the\n" | ||
2248 | "command line.\n"); | ||
2249 | exit(1); | ||
2250 | } | ||
2251 | |||
2245 | // prog_index could still be -1 if no program was specified | 2252 | // prog_index could still be -1 if no program was specified |
2246 | if (prog_index == -1 && arg_shell_none) { | 2253 | if (prog_index == -1 && arg_shell_none) { |
2247 | fprintf(stderr, "Error: shell=none configured, but no program specified\n"); | 2254 | fprintf(stderr, "Error: shell=none configured, but no program specified\n"); |
@@ -2257,12 +2264,12 @@ int main(int argc, char **argv) { | |||
2257 | // check user namespace (--noroot) options | 2264 | // check user namespace (--noroot) options |
2258 | if (arg_noroot) { | 2265 | if (arg_noroot) { |
2259 | if (arg_overlay) { | 2266 | if (arg_overlay) { |
2260 | fprintf(stderr, "Error: --overlay and --noroot are mutually exclusive.\n"); | 2267 | fwarning("--overlay and --noroot are mutually exclusive, --noroot disabled...\n"); |
2261 | exit(1); | 2268 | arg_noroot = 0; |
2262 | } | 2269 | } |
2263 | else if (cfg.chrootdir) { | 2270 | else if (cfg.chrootdir) { |
2264 | fprintf(stderr, "Error: --chroot and --noroot are mutually exclusive.\n"); | 2271 | fwarning("--chroot and --noroot are mutually exclusive, --noroot disabled...\n"); |
2265 | exit(1); | 2272 | arg_noroot = 0; |
2266 | } | 2273 | } |
2267 | } | 2274 | } |
2268 | 2275 | ||
@@ -2336,39 +2343,30 @@ int main(int argc, char **argv) { | |||
2336 | 2343 | ||
2337 | // use default.profile as the default | 2344 | // use default.profile as the default |
2338 | if (!custom_profile && !arg_noprofile) { | 2345 | if (!custom_profile && !arg_noprofile) { |
2339 | if (cfg.chrootdir) { | 2346 | char *profile_name = DEFAULT_USER_PROFILE; |
2340 | fwarning("default profile disabled by --chroot option\n"); | 2347 | if (getuid() == 0) |
2341 | } | 2348 | profile_name = DEFAULT_ROOT_PROFILE; |
2342 | // else if (arg_overlay) { | 2349 | if (arg_debug) |
2343 | // fwarning("default profile disabled by --overlay option\n"); | 2350 | printf("Attempting to find %s.profile...\n", profile_name); |
2344 | // } | ||
2345 | else { | ||
2346 | // try to load a default profile | ||
2347 | char *profile_name = DEFAULT_USER_PROFILE; | ||
2348 | if (getuid() == 0) | ||
2349 | profile_name = DEFAULT_ROOT_PROFILE; | ||
2350 | if (arg_debug) | ||
2351 | printf("Attempting to find %s.profile...\n", profile_name); | ||
2352 | |||
2353 | // look for the profile in ~/.config/firejail directory | ||
2354 | char *usercfgdir; | ||
2355 | if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) | ||
2356 | errExit("asprintf"); | ||
2357 | custom_profile = profile_find(profile_name, usercfgdir); | ||
2358 | free(usercfgdir); | ||
2359 | 2351 | ||
2360 | if (!custom_profile) | 2352 | // look for the profile in ~/.config/firejail directory |
2361 | // look for the profile in /etc/firejail directory | 2353 | char *usercfgdir; |
2362 | custom_profile = profile_find(profile_name, SYSCONFDIR); | 2354 | if (asprintf(&usercfgdir, "%s/.config/firejail", cfg.homedir) == -1) |
2355 | errExit("asprintf"); | ||
2356 | custom_profile = profile_find(profile_name, usercfgdir); | ||
2357 | free(usercfgdir); | ||
2363 | 2358 | ||
2364 | if (!custom_profile) { | 2359 | if (!custom_profile) |
2365 | fprintf(stderr, "Error: no default.profile installed\n"); | 2360 | // look for the profile in /etc/firejail directory |
2366 | exit(1); | 2361 | custom_profile = profile_find(profile_name, SYSCONFDIR); |
2367 | } | ||
2368 | 2362 | ||
2369 | if (custom_profile) | 2363 | if (!custom_profile) { |
2370 | fmessage("\n** Note: you can use --noprofile to disable %s.profile **\n\n", profile_name); | 2364 | fprintf(stderr, "Error: no default.profile installed\n"); |
2365 | exit(1); | ||
2371 | } | 2366 | } |
2367 | |||
2368 | if (custom_profile) | ||
2369 | fmessage("\n** Note: you can use --noprofile to disable %s.profile **\n\n", profile_name); | ||
2372 | } | 2370 | } |
2373 | EUID_ASSERT(); | 2371 | EUID_ASSERT(); |
2374 | 2372 | ||
@@ -2436,8 +2434,10 @@ int main(int argc, char **argv) { | |||
2436 | if (display > 0) | 2434 | if (display > 0) |
2437 | set_x11_run_file(sandbox_pid, display); | 2435 | set_x11_run_file(sandbox_pid, display); |
2438 | #endif | 2436 | #endif |
2439 | flock(lockfd_directory, LOCK_UN); | 2437 | if (lockfd_directory != -1) { |
2440 | close(lockfd_directory); | 2438 | flock(lockfd_directory, LOCK_UN); |
2439 | close(lockfd_directory); | ||
2440 | } | ||
2441 | EUID_USER(); | 2441 | EUID_USER(); |
2442 | 2442 | ||
2443 | // clone environment | 2443 | // clone environment |
diff --git a/src/firejail/network.c b/src/firejail/network.c index 7b84854d3..fed7539ca 100644 --- a/src/firejail/network.c +++ b/src/firejail/network.c | |||
@@ -78,7 +78,7 @@ int net_get_mtu(const char *ifname) { | |||
78 | 78 | ||
79 | memset(&ifr, 0, sizeof(ifr)); | 79 | memset(&ifr, 0, sizeof(ifr)); |
80 | ifr.ifr_addr.sa_family = AF_INET; | 80 | ifr.ifr_addr.sa_family = AF_INET; |
81 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 81 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
82 | if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) | 82 | if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) |
83 | mtu = ifr.ifr_mtu; | 83 | mtu = ifr.ifr_mtu; |
84 | if (arg_debug) | 84 | if (arg_debug) |
@@ -106,7 +106,7 @@ void net_set_mtu(const char *ifname, int mtu) { | |||
106 | 106 | ||
107 | memset(&ifr, 0, sizeof(ifr)); | 107 | memset(&ifr, 0, sizeof(ifr)); |
108 | ifr.ifr_addr.sa_family = AF_INET; | 108 | ifr.ifr_addr.sa_family = AF_INET; |
109 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 109 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
110 | ifr.ifr_mtu = mtu; | 110 | ifr.ifr_mtu = mtu; |
111 | if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0) | 111 | if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0) |
112 | fwarning("cannot set mtu for interface %s\n", ifname); | 112 | fwarning("cannot set mtu for interface %s\n", ifname); |
@@ -269,7 +269,7 @@ int net_get_mac(const char *ifname, unsigned char mac[6]) { | |||
269 | errExit("socket"); | 269 | errExit("socket"); |
270 | 270 | ||
271 | memset(&ifr, 0, sizeof(ifr)); | 271 | memset(&ifr, 0, sizeof(ifr)); |
272 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 272 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
273 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; | 273 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; |
274 | 274 | ||
275 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) | 275 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) |
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c index 9fb4840c6..f519ed85f 100644 --- a/src/firejail/preproc.c +++ b/src/firejail/preproc.c | |||
@@ -140,6 +140,8 @@ void preproc_clean_run(void) { | |||
140 | if (fp) { | 140 | if (fp) { |
141 | int val; | 141 | int val; |
142 | if (fscanf(fp, "%d", &val) == 1) { | 142 | if (fscanf(fp, "%d", &val) == 1) { |
143 | if (val > 4194304) // this is the max value supported on 64 bit Linux kernels | ||
144 | val = 4194304; | ||
143 | if (val >= max_pids) | 145 | if (val >= max_pids) |
144 | max_pids = val + 1; | 146 | max_pids = val + 1; |
145 | } | 147 | } |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index a90a5e7d6..5f6707e4b 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -728,6 +728,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
728 | cfg.dns4 = dns; | 728 | cfg.dns4 = dns; |
729 | else { | 729 | else { |
730 | fprintf(stderr, "Error: up to 4 DNS servers can be specified\n"); | 730 | fprintf(stderr, "Error: up to 4 DNS servers can be specified\n"); |
731 | free(dns); | ||
731 | return 1; | 732 | return 1; |
732 | } | 733 | } |
733 | return 0; | 734 | return 0; |
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c index d66deeb97..fa672eccb 100644 --- a/src/firejail/restrict_users.c +++ b/src/firejail/restrict_users.c | |||
@@ -41,6 +41,8 @@ static void ulist_add(const char *user) { | |||
41 | assert(user); | 41 | assert(user); |
42 | 42 | ||
43 | USER_LIST *nlist = malloc(sizeof(USER_LIST)); | 43 | USER_LIST *nlist = malloc(sizeof(USER_LIST)); |
44 | if (!nlist) | ||
45 | errExit("malloc"); | ||
44 | memset(nlist, 0, sizeof(USER_LIST)); | 46 | memset(nlist, 0, sizeof(USER_LIST)); |
45 | nlist->user = user; | 47 | nlist->user = user; |
46 | nlist->next = ulist; | 48 | nlist->next = ulist; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 380257223..e0bc0e02f 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -546,7 +546,8 @@ static void enforce_filters(void) { | |||
546 | // drop all supplementary groups; /etc/group file inside chroot | 546 | // drop all supplementary groups; /etc/group file inside chroot |
547 | // is controlled by a regular usr | 547 | // is controlled by a regular usr |
548 | arg_nogroups = 1; | 548 | arg_nogroups = 1; |
549 | fmessage("Dropping all Linux capabilities and enforcing default seccomp filter\n"); | 549 | fmessage("\n** Warning: dropping all Linux capabilities and enforcing **\n"); |
550 | fmessage("** default seccomp filter **\n\n"); | ||
550 | } | 551 | } |
551 | 552 | ||
552 | int sandbox(void* sandbox_arg) { | 553 | int sandbox(void* sandbox_arg) { |
@@ -751,6 +752,17 @@ int sandbox(void* sandbox_arg) { | |||
751 | #else | 752 | #else |
752 | bool need_preload = arg_seccomp_postexec; | 753 | bool need_preload = arg_seccomp_postexec; |
753 | #endif | 754 | #endif |
755 | // for --appimage, --chroot and --overlay* we replace the seccomp filter with the default one | ||
756 | // we also drop all capabilities | ||
757 | if (getuid() != 0 && (arg_appimage || cfg.chrootdir || arg_overlay)) { | ||
758 | enforce_filters(); | ||
759 | #ifdef LTS | ||
760 | need_preload = 0; | ||
761 | #else | ||
762 | need_preload = arg_trace || arg_tracelog; | ||
763 | #endif | ||
764 | arg_seccomp = 1; | ||
765 | } | ||
754 | // trace pre-install | 766 | // trace pre-install |
755 | if (need_preload) | 767 | if (need_preload) |
756 | fs_trace_preload(); | 768 | fs_trace_preload(); |
@@ -762,20 +774,11 @@ int sandbox(void* sandbox_arg) { | |||
762 | //**************************** | 774 | //**************************** |
763 | // configure filesystem | 775 | // configure filesystem |
764 | //**************************** | 776 | //**************************** |
765 | if (arg_appimage) | ||
766 | enforce_filters(); | ||
767 | |||
768 | #ifndef LTS | 777 | #ifndef LTS |
769 | #ifdef HAVE_CHROOT | 778 | #ifdef HAVE_CHROOT |
770 | if (cfg.chrootdir) { | 779 | if (cfg.chrootdir) { |
771 | fs_chroot(cfg.chrootdir); | 780 | fs_chroot(cfg.chrootdir); |
772 | 781 | ||
773 | // force caps and seccomp if not started as root | ||
774 | if (getuid() != 0) | ||
775 | enforce_filters(); | ||
776 | else | ||
777 | arg_seccomp = 1; | ||
778 | |||
779 | //**************************** | 782 | //**************************** |
780 | // trace pre-install, this time inside chroot | 783 | // trace pre-install, this time inside chroot |
781 | //**************************** | 784 | //**************************** |
@@ -785,14 +788,8 @@ int sandbox(void* sandbox_arg) { | |||
785 | else | 788 | else |
786 | #endif | 789 | #endif |
787 | #ifdef HAVE_OVERLAYFS | 790 | #ifdef HAVE_OVERLAYFS |
788 | if (arg_overlay) { | 791 | if (arg_overlay) |
789 | fs_overlayfs(); | 792 | fs_overlayfs(); |
790 | // force caps and seccomp if not started as root | ||
791 | if (getuid() != 0) | ||
792 | enforce_filters(); | ||
793 | else | ||
794 | arg_seccomp = 1; | ||
795 | } | ||
796 | else | 793 | else |
797 | #endif | 794 | #endif |
798 | #endif // LTS | 795 | #endif // LTS |
@@ -1052,7 +1049,10 @@ int sandbox(void* sandbox_arg) { | |||
1052 | //**************************** | 1049 | //**************************** |
1053 | // set capabilities | 1050 | // set capabilities |
1054 | set_caps(); | 1051 | set_caps(); |
1055 | 1052 | #ifndef LTS | |
1053 | // set rlimits | ||
1054 | set_rlimits(); | ||
1055 | #endif //LTS | ||
1056 | // set cpu affinity | 1056 | // set cpu affinity |
1057 | if (cfg.cpus) { | 1057 | if (cfg.cpus) { |
1058 | save_cpu(); // save cpu affinity mask to CPU_CFG file | 1058 | save_cpu(); // save cpu affinity mask to CPU_CFG file |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index c11daad58..1c6f3c327 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -142,8 +142,10 @@ int sbox_run(unsigned filter, int num, ...) { | |||
142 | } | 142 | } |
143 | else if ((filter & SBOX_ALLOW_STDIN) == 0) { | 143 | else if ((filter & SBOX_ALLOW_STDIN) == 0) { |
144 | int fd = open("/dev/null",O_RDWR, 0); | 144 | int fd = open("/dev/null",O_RDWR, 0); |
145 | if (fd != -1) | 145 | if (fd != -1) { |
146 | dup2(fd, STDIN_FILENO); | 146 | dup2(fd, STDIN_FILENO); |
147 | close(fd); | ||
148 | } | ||
147 | else // the user could run the sandbox without /dev/null | 149 | else // the user could run the sandbox without /dev/null |
148 | close(STDIN_FILENO); | 150 | close(STDIN_FILENO); |
149 | } | 151 | } |
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/firemon/interface.c b/src/firemon/interface.c index 71026c7b7..3e0f10d0b 100644 --- a/src/firemon/interface.c +++ b/src/firemon/interface.c | |||
@@ -62,7 +62,7 @@ static void net_ifprint(void) { | |||
62 | // extract mac address | 62 | // extract mac address |
63 | struct ifreq ifr; | 63 | struct ifreq ifr; |
64 | memset(&ifr, 0, sizeof(ifr)); | 64 | memset(&ifr, 0, sizeof(ifr)); |
65 | strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); | 65 | strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ - 1); |
66 | int rv = ioctl (fd, SIOCGIFHWADDR, &ifr); | 66 | int rv = ioctl (fd, SIOCGIFHWADDR, &ifr); |
67 | 67 | ||
68 | if (rv == 0) | 68 | if (rv == 0) |
diff --git a/src/fnet/arp.c b/src/fnet/arp.c index 2b6df6945..794f6c8c8 100644 --- a/src/fnet/arp.c +++ b/src/fnet/arp.c | |||
@@ -60,7 +60,7 @@ void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) { | |||
60 | errExit("socket"); | 60 | errExit("socket"); |
61 | struct ifreq ifr; | 61 | struct ifreq ifr; |
62 | memset(&ifr, 0, sizeof (ifr)); | 62 | memset(&ifr, 0, sizeof (ifr)); |
63 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); | 63 | strncpy(ifr.ifr_name, dev, IFNAMSIZ - 1); |
64 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) | 64 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) |
65 | errExit("ioctl"); | 65 | errExit("ioctl"); |
66 | close(sock); | 66 | close(sock); |
diff --git a/src/fnet/interface.c b/src/fnet/interface.c index f3e9a8993..283c6d312 100644 --- a/src/fnet/interface.c +++ b/src/fnet/interface.c | |||
@@ -58,7 +58,7 @@ void net_bridge_add_interface(const char *bridge, const char *dev) { | |||
58 | errExit("socket"); | 58 | errExit("socket"); |
59 | 59 | ||
60 | memset(&ifr, 0, sizeof(ifr)); | 60 | memset(&ifr, 0, sizeof(ifr)); |
61 | strncpy(ifr.ifr_name, bridge, IFNAMSIZ); | 61 | strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1); |
62 | #ifdef SIOCBRADDIF | 62 | #ifdef SIOCBRADDIF |
63 | ifr.ifr_ifindex = ifindex; | 63 | ifr.ifr_ifindex = ifindex; |
64 | err = ioctl(sock, SIOCBRADDIF, &ifr); | 64 | err = ioctl(sock, SIOCBRADDIF, &ifr); |
@@ -90,7 +90,7 @@ void net_if_up(const char *ifname) { | |||
90 | // get the existing interface flags | 90 | // get the existing interface flags |
91 | struct ifreq ifr; | 91 | struct ifreq ifr; |
92 | memset(&ifr, 0, sizeof(ifr)); | 92 | memset(&ifr, 0, sizeof(ifr)); |
93 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 93 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
94 | ifr.ifr_addr.sa_family = AF_INET; | 94 | ifr.ifr_addr.sa_family = AF_INET; |
95 | 95 | ||
96 | // read the existing flags | 96 | // read the existing flags |
@@ -135,7 +135,7 @@ int net_get_mtu(const char *ifname) { | |||
135 | 135 | ||
136 | memset(&ifr, 0, sizeof(ifr)); | 136 | memset(&ifr, 0, sizeof(ifr)); |
137 | ifr.ifr_addr.sa_family = AF_INET; | 137 | ifr.ifr_addr.sa_family = AF_INET; |
138 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 138 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
139 | if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) | 139 | if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) |
140 | mtu = ifr.ifr_mtu; | 140 | mtu = ifr.ifr_mtu; |
141 | close(s); | 141 | close(s); |
@@ -154,7 +154,7 @@ void net_set_mtu(const char *ifname, int mtu) { | |||
154 | 154 | ||
155 | memset(&ifr, 0, sizeof(ifr)); | 155 | memset(&ifr, 0, sizeof(ifr)); |
156 | ifr.ifr_addr.sa_family = AF_INET; | 156 | ifr.ifr_addr.sa_family = AF_INET; |
157 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 157 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
158 | ifr.ifr_mtu = mtu; | 158 | ifr.ifr_mtu = mtu; |
159 | if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0) { | 159 | if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0) { |
160 | if (!arg_quiet) | 160 | if (!arg_quiet) |
@@ -238,7 +238,7 @@ int net_get_mac(const char *ifname, unsigned char mac[6]) { | |||
238 | errExit("socket"); | 238 | errExit("socket"); |
239 | 239 | ||
240 | memset(&ifr, 0, sizeof(ifr)); | 240 | memset(&ifr, 0, sizeof(ifr)); |
241 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 241 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
242 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; | 242 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; |
243 | 243 | ||
244 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) | 244 | if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) |
@@ -258,7 +258,7 @@ void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) { | |||
258 | 258 | ||
259 | struct ifreq ifr; | 259 | struct ifreq ifr; |
260 | memset(&ifr, 0, sizeof(ifr)); | 260 | memset(&ifr, 0, sizeof(ifr)); |
261 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 261 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
262 | ifr.ifr_addr.sa_family = AF_INET; | 262 | ifr.ifr_addr.sa_family = AF_INET; |
263 | 263 | ||
264 | ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip); | 264 | ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip); |
@@ -292,7 +292,7 @@ int net_if_mac(const char *ifname, const unsigned char mac[6]) { | |||
292 | errExit("socket"); | 292 | errExit("socket"); |
293 | 293 | ||
294 | memset(&ifr, 0, sizeof(ifr)); | 294 | memset(&ifr, 0, sizeof(ifr)); |
295 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 295 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
296 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; | 296 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; |
297 | memcpy(ifr.ifr_hwaddr.sa_data, mac, 6); | 297 | memcpy(ifr.ifr_hwaddr.sa_data, mac, 6); |
298 | 298 | ||
@@ -350,7 +350,7 @@ void net_if_ip6(const char *ifname, const char *addr6) { | |||
350 | // find interface index | 350 | // find interface index |
351 | struct ifreq ifr; | 351 | struct ifreq ifr; |
352 | memset(&ifr, 0, sizeof(ifr)); | 352 | memset(&ifr, 0, sizeof(ifr)); |
353 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ); | 353 | strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); |
354 | ifr.ifr_addr.sa_family = AF_INET; | 354 | ifr.ifr_addr.sa_family = AF_INET; |
355 | if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) { | 355 | if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) { |
356 | perror("ioctl SIOGIFINDEX"); | 356 | perror("ioctl SIOGIFINDEX"); |
diff --git a/src/fsec-optimize/main.c b/src/fsec-optimize/main.c index f4300f350..80ca098cb 100644 --- a/src/fsec-optimize/main.c +++ b/src/fsec-optimize/main.c | |||
@@ -87,7 +87,8 @@ printf("\n"); | |||
87 | 87 | ||
88 | return 0; | 88 | return 0; |
89 | errexit: | 89 | errexit: |
90 | close(fd); | 90 | if (fd != -1) |
91 | close(fd); | ||
91 | fprintf(stderr, "Error: cannot read %s\n", fname); | 92 | fprintf(stderr, "Error: cannot read %s\n", fname); |
92 | exit(1); | 93 | exit(1); |
93 | 94 | ||
diff --git a/src/fsec-print/main.c b/src/fsec-print/main.c index 94c60687f..5a1e34080 100644 --- a/src/fsec-print/main.c +++ b/src/fsec-print/main.c | |||
@@ -74,7 +74,8 @@ printf("\n"); | |||
74 | close(fd); | 74 | close(fd); |
75 | return 0; | 75 | return 0; |
76 | errexit: | 76 | errexit: |
77 | close(fd); | 77 | if (fd != -1) |
78 | close(fd); | ||
78 | fprintf(stderr, "Error: cannot read %s\n", fname); | 79 | fprintf(stderr, "Error: cannot read %s\n", fname); |
79 | exit(1); | 80 | exit(1); |
80 | 81 | ||
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/libpostexecseccomp/libpostexecseccomp.c b/src/libpostexecseccomp/libpostexecseccomp.c index 0ccb74b10..de64d50c5 100644 --- a/src/libpostexecseccomp/libpostexecseccomp.c +++ b/src/libpostexecseccomp/libpostexecseccomp.c | |||
@@ -31,7 +31,9 @@ static void load_seccomp(void) { | |||
31 | if (fd == -1) | 31 | if (fd == -1) |
32 | return; | 32 | return; |
33 | 33 | ||
34 | int size = lseek(fd, 0, SEEK_END); | 34 | off_t size = lseek(fd, 0, SEEK_END); |
35 | if (size <= 0) | ||
36 | return; | ||
35 | unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); | 37 | unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); |
36 | struct sock_filter *filter = MAP_FAILED; | 38 | struct sock_filter *filter = MAP_FAILED; |
37 | if (size != 0) | 39 | if (size != 0) |
@@ -39,7 +41,7 @@ static void load_seccomp(void) { | |||
39 | 41 | ||
40 | close(fd); | 42 | close(fd); |
41 | 43 | ||
42 | if (size == 0 || filter == MAP_FAILED) | 44 | if (filter == MAP_FAILED) |
43 | return; | 45 | return; |
44 | 46 | ||
45 | // install filter | 47 | // install filter |