diff options
Diffstat (limited to 'src/firejail/fs.c')
-rw-r--r-- | src/firejail/fs.c | 47 |
1 files changed, 36 insertions, 11 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index eaf23e603..01182bd2c 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -57,6 +57,7 @@ static char *opstr[] = { | |||
57 | static void disable_file(OPERATION op, const char *filename) { | 57 | static void disable_file(OPERATION op, const char *filename) { |
58 | assert(filename); | 58 | assert(filename); |
59 | assert(op <OPERATION_MAX); | 59 | assert(op <OPERATION_MAX); |
60 | EUID_ASSERT(); | ||
60 | 61 | ||
61 | // Resolve all symlinks | 62 | // Resolve all symlinks |
62 | char* fname = realpath(filename, NULL); | 63 | char* fname = realpath(filename, NULL); |
@@ -74,9 +75,11 @@ static void disable_file(OPERATION op, const char *filename) { | |||
74 | return; | 75 | return; |
75 | } | 76 | } |
76 | 77 | ||
78 | EUID_ROOT(); | ||
77 | int err = bind_mount_path_to_fd(RUN_RO_DIR, fd); | 79 | int err = bind_mount_path_to_fd(RUN_RO_DIR, fd); |
78 | if (err < 0) | 80 | if (err < 0) |
79 | err = bind_mount_path_to_fd(RUN_RO_FILE, fd); | 81 | err = bind_mount_path_to_fd(RUN_RO_FILE, fd); |
82 | EUID_USER(); | ||
80 | close(fd); | 83 | close(fd); |
81 | 84 | ||
82 | if (err == 0) { | 85 | if (err == 0) { |
@@ -142,6 +145,7 @@ static void disable_file(OPERATION op, const char *filename) { | |||
142 | free(fname); | 145 | free(fname); |
143 | return; | 146 | return; |
144 | } | 147 | } |
148 | EUID_ROOT(); | ||
145 | if (S_ISDIR(s.st_mode)) { | 149 | if (S_ISDIR(s.st_mode)) { |
146 | if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0) | 150 | if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0) |
147 | errExit("disable file"); | 151 | errExit("disable file"); |
@@ -150,6 +154,7 @@ static void disable_file(OPERATION op, const char *filename) { | |||
150 | if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0) | 154 | if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0) |
151 | errExit("disable file"); | 155 | errExit("disable file"); |
152 | } | 156 | } |
157 | EUID_USER(); | ||
153 | close(fd); | 158 | close(fd); |
154 | 159 | ||
155 | if (op == BLACKLIST_FILE) | 160 | if (op == BLACKLIST_FILE) |
@@ -170,8 +175,10 @@ static void disable_file(OPERATION op, const char *filename) { | |||
170 | exit(1); | 175 | exit(1); |
171 | } | 176 | } |
172 | } | 177 | } |
178 | // fs_tmpfs returns with EUID 0 | ||
173 | fs_tmpfs(fname, getuid()); | 179 | fs_tmpfs(fname, getuid()); |
174 | selinux_relabel_path(fname, fname); | 180 | selinux_relabel_path(fname, fname); |
181 | EUID_USER(); | ||
175 | } | 182 | } |
176 | else | 183 | else |
177 | fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); | 184 | fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); |
@@ -191,6 +198,7 @@ static int *nbcheck = NULL; | |||
191 | // Treat pattern as a shell glob pattern and blacklist matching files | 198 | // Treat pattern as a shell glob pattern and blacklist matching files |
192 | static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len) { | 199 | static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len) { |
193 | assert(pattern); | 200 | assert(pattern); |
201 | EUID_ASSERT(); | ||
194 | 202 | ||
195 | #ifdef TEST_NO_BLACKLIST_MATCHING | 203 | #ifdef TEST_NO_BLACKLIST_MATCHING |
196 | if (nbcheck_start == 0) { | 204 | if (nbcheck_start == 0) { |
@@ -264,6 +272,7 @@ void fs_blacklist(void) { | |||
264 | if (noblacklist == NULL) | 272 | if (noblacklist == NULL) |
265 | errExit("failed allocating memory for noblacklist entries"); | 273 | errExit("failed allocating memory for noblacklist entries"); |
266 | 274 | ||
275 | EUID_USER(); | ||
267 | while (entry) { | 276 | while (entry) { |
268 | OPERATION op = OPERATION_MAX; | 277 | OPERATION op = OPERATION_MAX; |
269 | char *ptr; | 278 | char *ptr; |
@@ -294,11 +303,13 @@ void fs_blacklist(void) { | |||
294 | if (arg_debug) | 303 | if (arg_debug) |
295 | printf("Mount-bind %s on top of %s\n", dname1, dname2); | 304 | printf("Mount-bind %s on top of %s\n", dname1, dname2); |
296 | // preserve dname2 mode and ownership | 305 | // preserve dname2 mode and ownership |
306 | // EUID_ROOT(); - option not accessible to non-root users | ||
297 | if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) | 307 | if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) |
298 | errExit("mount bind"); | 308 | errExit("mount bind"); |
299 | /* coverity[toctou] */ | 309 | /* coverity[toctou] */ |
300 | if (set_perms(dname2, s.st_uid, s.st_gid,s.st_mode)) | 310 | if (set_perms(dname2, s.st_uid, s.st_gid,s.st_mode)) |
301 | errExit("set_perms"); | 311 | errExit("set_perms"); |
312 | // EUID_USER(); | ||
302 | 313 | ||
303 | entry = entry->next; | 314 | entry = entry->next; |
304 | continue; | 315 | continue; |
@@ -376,16 +387,12 @@ void fs_blacklist(void) { | |||
376 | op = MOUNT_TMPFS; | 387 | op = MOUNT_TMPFS; |
377 | } | 388 | } |
378 | else if (strncmp(entry->data, "mkdir ", 6) == 0) { | 389 | else if (strncmp(entry->data, "mkdir ", 6) == 0) { |
379 | EUID_USER(); | ||
380 | fs_mkdir(entry->data + 6); | 390 | fs_mkdir(entry->data + 6); |
381 | EUID_ROOT(); | ||
382 | entry = entry->next; | 391 | entry = entry->next; |
383 | continue; | 392 | continue; |
384 | } | 393 | } |
385 | else if (strncmp(entry->data, "mkfile ", 7) == 0) { | 394 | else if (strncmp(entry->data, "mkfile ", 7) == 0) { |
386 | EUID_USER(); | ||
387 | fs_mkfile(entry->data + 7); | 395 | fs_mkfile(entry->data + 7); |
388 | EUID_ROOT(); | ||
389 | entry = entry->next; | 396 | entry = entry->next; |
390 | continue; | 397 | continue; |
391 | } | 398 | } |
@@ -441,6 +448,8 @@ void fs_blacklist(void) { | |||
441 | for (i = 0; i < noblacklist_c; i++) | 448 | for (i = 0; i < noblacklist_c; i++) |
442 | free(noblacklist[i]); | 449 | free(noblacklist[i]); |
443 | free(noblacklist); | 450 | free(noblacklist); |
451 | |||
452 | EUID_ROOT(); | ||
444 | } | 453 | } |
445 | 454 | ||
446 | //*********************************************** | 455 | //*********************************************** |
@@ -449,6 +458,7 @@ void fs_blacklist(void) { | |||
449 | 458 | ||
450 | // mount a writable tmpfs on directory; requires a resolved path | 459 | // mount a writable tmpfs on directory; requires a resolved path |
451 | void fs_tmpfs(const char *dir, unsigned check_owner) { | 460 | void fs_tmpfs(const char *dir, unsigned check_owner) { |
461 | EUID_USER(); | ||
452 | assert(dir); | 462 | assert(dir); |
453 | if (arg_debug) | 463 | if (arg_debug) |
454 | printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no"); | 464 | printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no"); |
@@ -473,6 +483,7 @@ void fs_tmpfs(const char *dir, unsigned check_owner) { | |||
473 | errExit("fstatvfs"); | 483 | errExit("fstatvfs"); |
474 | unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND); | 484 | unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND); |
475 | // mount via the symbolic link in /proc/self/fd | 485 | // mount via the symbolic link in /proc/self/fd |
486 | EUID_ROOT(); | ||
476 | char *proc; | 487 | char *proc; |
477 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) | 488 | if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) |
478 | errExit("asprintf"); | 489 | errExit("asprintf"); |
@@ -490,6 +501,7 @@ void fs_tmpfs(const char *dir, unsigned check_owner) { | |||
490 | 501 | ||
491 | // remount path, preserving other mount flags; requires a resolved path | 502 | // remount path, preserving other mount flags; requires a resolved path |
492 | static void fs_remount_simple(const char *path, OPERATION op) { | 503 | static void fs_remount_simple(const char *path, OPERATION op) { |
504 | EUID_ASSERT(); | ||
493 | assert(path); | 505 | assert(path); |
494 | 506 | ||
495 | // open path without following symbolic links | 507 | // open path without following symbolic links |
@@ -555,7 +567,9 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
555 | 567 | ||
556 | // make path a mount point: | 568 | // make path a mount point: |
557 | // mount --bind path path | 569 | // mount --bind path path |
570 | EUID_ROOT(); | ||
558 | int err = bind_mount_by_fd(fd, fd); | 571 | int err = bind_mount_by_fd(fd, fd); |
572 | EUID_USER(); | ||
559 | if (err) { | 573 | if (err) { |
560 | close(fd); | 574 | close(fd); |
561 | goto out; | 575 | goto out; |
@@ -575,7 +589,9 @@ static void fs_remount_simple(const char *path, OPERATION op) { | |||
575 | if (s.st_dev != s2.st_dev || s.st_ino != s2.st_ino) | 589 | if (s.st_dev != s2.st_dev || s.st_ino != s2.st_ino) |
576 | errLogExit("invalid %s mount", opstr[op]); | 590 | errLogExit("invalid %s mount", opstr[op]); |
577 | 591 | ||
592 | EUID_ROOT(); | ||
578 | err = remount_by_fd(fd2, flags); | 593 | err = remount_by_fd(fd2, flags); |
594 | EUID_USER(); | ||
579 | close(fd2); | 595 | close(fd2); |
580 | if (err) | 596 | if (err) |
581 | goto out; | 597 | goto out; |
@@ -599,7 +615,9 @@ out: | |||
599 | 615 | ||
600 | // remount recursively; requires a resolved path | 616 | // remount recursively; requires a resolved path |
601 | static void fs_remount_rec(const char *dir, OPERATION op) { | 617 | static void fs_remount_rec(const char *dir, OPERATION op) { |
618 | EUID_ASSERT(); | ||
602 | assert(dir); | 619 | assert(dir); |
620 | |||
603 | struct stat s; | 621 | struct stat s; |
604 | if (stat(dir, &s) != 0) | 622 | if (stat(dir, &s) != 0) |
605 | return; | 623 | return; |
@@ -637,6 +655,9 @@ static void fs_remount_rec(const char *dir, OPERATION op) { | |||
637 | // resolve a path and remount it | 655 | // resolve a path and remount it |
638 | void fs_remount(const char *path, OPERATION op, int rec) { | 656 | void fs_remount(const char *path, OPERATION op, int rec) { |
639 | assert(path); | 657 | assert(path); |
658 | assert(geteuid() == 0); | ||
659 | EUID_USER(); | ||
660 | |||
640 | char *rpath = realpath(path, NULL); | 661 | char *rpath = realpath(path, NULL); |
641 | if (rpath) { | 662 | if (rpath) { |
642 | if (rec) | 663 | if (rec) |
@@ -645,10 +666,12 @@ void fs_remount(const char *path, OPERATION op, int rec) { | |||
645 | fs_remount_simple(rpath, op); | 666 | fs_remount_simple(rpath, op); |
646 | free(rpath); | 667 | free(rpath); |
647 | } | 668 | } |
669 | EUID_ROOT(); | ||
648 | } | 670 | } |
649 | 671 | ||
650 | // Disable /mnt, /media, /run/mount and /run/media access | 672 | // Disable /mnt, /media, /run/mount and /run/media access |
651 | void fs_mnt(const int enforce) { | 673 | void fs_mnt(const int enforce) { |
674 | EUID_USER(); | ||
652 | if (enforce) { | 675 | if (enforce) { |
653 | // disable-mnt set in firejail.config | 676 | // disable-mnt set in firejail.config |
654 | // overriding with noblacklist is not possible in this case | 677 | // overriding with noblacklist is not possible in this case |
@@ -658,13 +681,12 @@ void fs_mnt(const int enforce) { | |||
658 | disable_file(BLACKLIST_FILE, "/run/media"); | 681 | disable_file(BLACKLIST_FILE, "/run/media"); |
659 | } | 682 | } |
660 | else { | 683 | else { |
661 | EUID_USER(); | ||
662 | profile_add("blacklist /mnt"); | 684 | profile_add("blacklist /mnt"); |
663 | profile_add("blacklist /media"); | 685 | profile_add("blacklist /media"); |
664 | profile_add("blacklist /run/mount"); | 686 | profile_add("blacklist /run/mount"); |
665 | profile_add("blacklist /run/media"); | 687 | profile_add("blacklist /run/media"); |
666 | EUID_ROOT(); | ||
667 | } | 688 | } |
689 | EUID_ROOT(); | ||
668 | } | 690 | } |
669 | 691 | ||
670 | 692 | ||
@@ -679,7 +701,6 @@ void fs_proc_sys_dev_boot(void) { | |||
679 | errExit("mounting /proc/sys"); | 701 | errExit("mounting /proc/sys"); |
680 | fs_logger("read-only /proc/sys"); | 702 | fs_logger("read-only /proc/sys"); |
681 | 703 | ||
682 | |||
683 | /* Mount a version of /sys that describes the network namespace */ | 704 | /* Mount a version of /sys that describes the network namespace */ |
684 | if (arg_debug) | 705 | if (arg_debug) |
685 | printf("Remounting /sys directory\n"); | 706 | printf("Remounting /sys directory\n"); |
@@ -694,13 +715,13 @@ void fs_proc_sys_dev_boot(void) { | |||
694 | else | 715 | else |
695 | fs_logger("remount /sys"); | 716 | fs_logger("remount /sys"); |
696 | 717 | ||
718 | EUID_USER(); | ||
719 | |||
697 | disable_file(BLACKLIST_FILE, "/sys/firmware"); | 720 | disable_file(BLACKLIST_FILE, "/sys/firmware"); |
698 | disable_file(BLACKLIST_FILE, "/sys/hypervisor"); | 721 | disable_file(BLACKLIST_FILE, "/sys/hypervisor"); |
699 | { // allow user access to some directories in /sys/ by specifying 'noblacklist' option | 722 | { // allow user access to some directories in /sys/ by specifying 'noblacklist' option |
700 | EUID_USER(); | ||
701 | profile_add("blacklist /sys/fs"); | 723 | profile_add("blacklist /sys/fs"); |
702 | profile_add("blacklist /sys/module"); | 724 | profile_add("blacklist /sys/module"); |
703 | EUID_ROOT(); | ||
704 | } | 725 | } |
705 | disable_file(BLACKLIST_FILE, "/sys/power"); | 726 | disable_file(BLACKLIST_FILE, "/sys/power"); |
706 | disable_file(BLACKLIST_FILE, "/sys/kernel/debug"); | 727 | disable_file(BLACKLIST_FILE, "/sys/kernel/debug"); |
@@ -744,8 +765,6 @@ void fs_proc_sys_dev_boot(void) { | |||
744 | // disable /dev/port | 765 | // disable /dev/port |
745 | disable_file(BLACKLIST_FILE, "/dev/port"); | 766 | disable_file(BLACKLIST_FILE, "/dev/port"); |
746 | 767 | ||
747 | |||
748 | |||
749 | // disable various ipc sockets in /run/user | 768 | // disable various ipc sockets in /run/user |
750 | if (!arg_writable_run_user) { | 769 | if (!arg_writable_run_user) { |
751 | char *fname; | 770 | char *fname; |
@@ -778,10 +797,13 @@ void fs_proc_sys_dev_boot(void) { | |||
778 | disable_file(BLACKLIST_FILE, "/dev/kmsg"); | 797 | disable_file(BLACKLIST_FILE, "/dev/kmsg"); |
779 | disable_file(BLACKLIST_FILE, "/proc/kmsg"); | 798 | disable_file(BLACKLIST_FILE, "/proc/kmsg"); |
780 | } | 799 | } |
800 | |||
801 | EUID_ROOT(); | ||
781 | } | 802 | } |
782 | 803 | ||
783 | // disable firejail configuration in ~/.config/firejail | 804 | // disable firejail configuration in ~/.config/firejail |
784 | void disable_config(void) { | 805 | void disable_config(void) { |
806 | EUID_USER(); | ||
785 | char *fname; | 807 | char *fname; |
786 | if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1) | 808 | if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1) |
787 | errExit("asprintf"); | 809 | errExit("asprintf"); |
@@ -794,6 +816,7 @@ void disable_config(void) { | |||
794 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NAME_DIR); | 816 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NAME_DIR); |
795 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); | 817 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR); |
796 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); | 818 | disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR); |
819 | EUID_ROOT(); | ||
797 | } | 820 | } |
798 | 821 | ||
799 | 822 | ||
@@ -855,6 +878,7 @@ void fs_basic_fs(void) { | |||
855 | #ifdef HAVE_OVERLAYFS | 878 | #ifdef HAVE_OVERLAYFS |
856 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | 879 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { |
857 | assert(subdirname); | 880 | assert(subdirname); |
881 | EUID_ASSERT(); | ||
858 | struct stat s; | 882 | struct stat s; |
859 | char *dirname; | 883 | char *dirname; |
860 | 884 | ||
@@ -1214,6 +1238,7 @@ void fs_overlayfs(void) { | |||
1214 | 1238 | ||
1215 | // this function is called from sandbox.c before blacklist/whitelist functions | 1239 | // this function is called from sandbox.c before blacklist/whitelist functions |
1216 | void fs_private_tmp(void) { | 1240 | void fs_private_tmp(void) { |
1241 | EUID_ASSERT(); | ||
1217 | if (arg_debug) | 1242 | if (arg_debug) |
1218 | printf("Generate private-tmp whitelist commands\n"); | 1243 | printf("Generate private-tmp whitelist commands\n"); |
1219 | 1244 | ||