diff options
-rw-r--r-- | src/firejail/checkcfg.c | 3 | ||||
-rw-r--r-- | src/firejail/chroot.c | 2 | ||||
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/fs.c | 47 | ||||
-rw-r--r-- | src/firejail/fs_dev.c | 2 | ||||
-rw-r--r-- | src/firejail/fs_home.c | 41 | ||||
-rw-r--r-- | src/firejail/fs_lib.c | 7 | ||||
-rw-r--r-- | src/firejail/fs_whitelist.c | 1 | ||||
-rw-r--r-- | src/firejail/macros.c | 1 | ||||
-rw-r--r-- | src/firejail/mountinfo.c | 5 | ||||
-rw-r--r-- | src/firejail/paths.c | 2 | ||||
-rw-r--r-- | src/firejail/sbox.c | 2 | ||||
-rw-r--r-- | src/firejail/util.c | 89 | ||||
-rw-r--r-- | src/firejail/x11.c | 15 |
14 files changed, 165 insertions, 55 deletions
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index d7690a4fc..f3ab0a6d8 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -134,8 +134,7 @@ int checkcfg(int val) { | |||
134 | *end = '\0'; | 134 | *end = '\0'; |
135 | 135 | ||
136 | // is the file present? | 136 | // is the file present? |
137 | struct stat s; | 137 | if (access(fname, F_OK) == -1) { |
138 | if (stat(fname, &s) == -1) { | ||
139 | fprintf(stderr, "Error: netfilter-default file %s not available\n", fname); | 138 | fprintf(stderr, "Error: netfilter-default file %s not available\n", fname); |
140 | exit(1); | 139 | exit(1); |
141 | } | 140 | } |
diff --git a/src/firejail/chroot.c b/src/firejail/chroot.c index 4125a4130..05d89a866 100644 --- a/src/firejail/chroot.c +++ b/src/firejail/chroot.c | |||
@@ -219,7 +219,7 @@ void fs_chroot(const char *rootdir) { | |||
219 | exit(1); | 219 | exit(1); |
220 | } | 220 | } |
221 | if (bind_mount_by_fd(src, dst)) | 221 | if (bind_mount_by_fd(src, dst)) |
222 | errExit("mounting pulseaudio") | 222 | errExit("mounting pulseaudio"); |
223 | close(src); | 223 | close(src); |
224 | close(dst); | 224 | close(dst); |
225 | free(pulse); | 225 | free(pulse); |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index ab6e44a8a..10133142a 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -503,6 +503,9 @@ void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_ | |||
503 | void touch_file_as_user(const char *fname, mode_t mode); | 503 | void touch_file_as_user(const char *fname, mode_t mode); |
504 | int is_dir(const char *fname); | 504 | int is_dir(const char *fname); |
505 | int is_link(const char *fname); | 505 | int is_link(const char *fname); |
506 | char *realpath_as_user(const char *fname); | ||
507 | int stat_as_user(const char *fname, struct stat *s); | ||
508 | int lstat_as_user(const char *fname, struct stat *s); | ||
506 | void trim_trailing_slash_or_dot(char *path); | 509 | void trim_trailing_slash_or_dot(char *path); |
507 | char *line_remove_spaces(const char *buf); | 510 | char *line_remove_spaces(const char *buf); |
508 | char *split_comma(char *str); | 511 | char *split_comma(char *str); |
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 | ||
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c index 8c2870a4d..8cc3ecc62 100644 --- a/src/firejail/fs_dev.c +++ b/src/firejail/fs_dev.c | |||
@@ -187,8 +187,10 @@ static void mount_dev_shm(void) { | |||
187 | static void process_dev_shm(void) { | 187 | static void process_dev_shm(void) { |
188 | // Jack audio keeps an Unix socket under (/dev/shm/jack_default_1000_0 or /dev/shm/jack/...) | 188 | // Jack audio keeps an Unix socket under (/dev/shm/jack_default_1000_0 or /dev/shm/jack/...) |
189 | // looking for jack socket | 189 | // looking for jack socket |
190 | EUID_USER(); | ||
190 | glob_t globbuf; | 191 | glob_t globbuf; |
191 | int globerr = glob(RUN_DEV_DIR "/shm/jack*", GLOB_NOSORT, NULL, &globbuf); | 192 | int globerr = glob(RUN_DEV_DIR "/shm/jack*", GLOB_NOSORT, NULL, &globbuf); |
193 | EUID_ROOT(); | ||
192 | if (globerr && !arg_keep_dev_shm) { | 194 | if (globerr && !arg_keep_dev_shm) { |
193 | empty_dev_shm(); | 195 | empty_dev_shm(); |
194 | return; | 196 | return; |
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index ec6dab947..eab952eb8 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -42,15 +42,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
42 | // copy skel files | 42 | // copy skel files |
43 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) | 43 | if (asprintf(&fname, "%s/.zshrc", homedir) == -1) |
44 | errExit("asprintf"); | 44 | errExit("asprintf"); |
45 | struct stat s; | ||
46 | // don't copy it if we already have the file | 45 | // don't copy it if we already have the file |
47 | if (stat(fname, &s) == 0) | 46 | if (access(fname, F_OK) == 0) |
48 | return; | 47 | return; |
49 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 48 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
50 | fprintf(stderr, "Error: invalid %s file\n", fname); | 49 | fprintf(stderr, "Error: invalid %s file\n", fname); |
51 | exit(1); | 50 | exit(1); |
52 | } | 51 | } |
53 | if (stat("/etc/skel/.zshrc", &s) == 0) { | 52 | if (access("/etc/skel/.zshrc", R_OK) == 0) { |
54 | copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user | 53 | copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user |
55 | fs_logger("clone /etc/skel/.zshrc"); | 54 | fs_logger("clone /etc/skel/.zshrc"); |
56 | fs_logger2("clone", fname); | 55 | fs_logger2("clone", fname); |
@@ -67,16 +66,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
67 | // copy skel files | 66 | // copy skel files |
68 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) | 67 | if (asprintf(&fname, "%s/.cshrc", homedir) == -1) |
69 | errExit("asprintf"); | 68 | errExit("asprintf"); |
70 | struct stat s; | ||
71 | |||
72 | // don't copy it if we already have the file | 69 | // don't copy it if we already have the file |
73 | if (stat(fname, &s) == 0) | 70 | if (access(fname, F_OK) == 0) |
74 | return; | 71 | return; |
75 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 72 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
76 | fprintf(stderr, "Error: invalid %s file\n", fname); | 73 | fprintf(stderr, "Error: invalid %s file\n", fname); |
77 | exit(1); | 74 | exit(1); |
78 | } | 75 | } |
79 | if (stat("/etc/skel/.cshrc", &s) == 0) { | 76 | if (access("/etc/skel/.cshrc", R_OK) == 0) { |
80 | copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user | 77 | copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user |
81 | fs_logger("clone /etc/skel/.cshrc"); | 78 | fs_logger("clone /etc/skel/.cshrc"); |
82 | fs_logger2("clone", fname); | 79 | fs_logger2("clone", fname); |
@@ -93,15 +90,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) { | |||
93 | // copy skel files | 90 | // copy skel files |
94 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) | 91 | if (asprintf(&fname, "%s/.bashrc", homedir) == -1) |
95 | errExit("asprintf"); | 92 | errExit("asprintf"); |
96 | struct stat s; | ||
97 | // don't copy it if we already have the file | 93 | // don't copy it if we already have the file |
98 | if (stat(fname, &s) == 0) | 94 | if (access(fname, F_OK) == 0) |
99 | return; | 95 | return; |
100 | if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat | 96 | if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat |
101 | fprintf(stderr, "Error: invalid %s file\n", fname); | 97 | fprintf(stderr, "Error: invalid %s file\n", fname); |
102 | exit(1); | 98 | exit(1); |
103 | } | 99 | } |
104 | if (stat("/etc/skel/.bashrc", &s) == 0) { | 100 | if (access("/etc/skel/.bashrc", R_OK) == 0) { |
105 | copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user | 101 | copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user |
106 | fs_logger("clone /etc/skel/.bashrc"); | 102 | fs_logger("clone /etc/skel/.bashrc"); |
107 | fs_logger2("clone", fname); | 103 | fs_logger2("clone", fname); |
@@ -122,8 +118,8 @@ static int store_xauthority(void) { | |||
122 | errExit("asprintf"); | 118 | errExit("asprintf"); |
123 | 119 | ||
124 | struct stat s; | 120 | struct stat s; |
125 | if (stat(src, &s) == 0) { | 121 | if (lstat_as_user(src, &s) == 0) { |
126 | if (is_link(src)) { | 122 | if (S_ISLNK(s.st_mode)) { |
127 | fwarning("invalid .Xauthority file\n"); | 123 | fwarning("invalid .Xauthority file\n"); |
128 | free(src); | 124 | free(src); |
129 | return 0; | 125 | return 0; |
@@ -161,11 +157,11 @@ static int store_asoundrc(void) { | |||
161 | errExit("asprintf"); | 157 | errExit("asprintf"); |
162 | 158 | ||
163 | struct stat s; | 159 | struct stat s; |
164 | if (stat(src, &s) == 0) { | 160 | if (lstat_as_user(src, &s) == 0) { |
165 | if (is_link(src)) { | 161 | if (S_ISLNK(s.st_mode)) { |
166 | // make sure the real path of the file is inside the home directory | 162 | // make sure the real path of the file is inside the home directory |
167 | /* coverity[toctou] */ | 163 | /* coverity[toctou] */ |
168 | char* rp = realpath(src, NULL); | 164 | char *rp = realpath_as_user(src); |
169 | if (!rp) { | 165 | if (!rp) { |
170 | fprintf(stderr, "Error: Cannot access %s\n", src); | 166 | fprintf(stderr, "Error: Cannot access %s\n", src); |
171 | exit(1); | 167 | exit(1); |
@@ -263,6 +259,7 @@ void fs_private_homedir(void) { | |||
263 | if (arg_debug) | 259 | if (arg_debug) |
264 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); | 260 | printf("Mount-bind %s on top of %s\n", private_homedir, homedir); |
265 | // get file descriptors for homedir and private_homedir, fails if there is any symlink | 261 | // get file descriptors for homedir and private_homedir, fails if there is any symlink |
262 | EUID_USER(); | ||
266 | int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | 263 | int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); |
267 | if (src == -1) | 264 | if (src == -1) |
268 | errExit("opening private directory"); | 265 | errExit("opening private directory"); |
@@ -287,6 +284,7 @@ void fs_private_homedir(void) { | |||
287 | exit(1); | 284 | exit(1); |
288 | } | 285 | } |
289 | // mount via the links in /proc/self/fd | 286 | // mount via the links in /proc/self/fd |
287 | EUID_ROOT(); | ||
290 | if (bind_mount_by_fd(src, dst)) | 288 | if (bind_mount_by_fd(src, dst)) |
291 | errExit("mount bind"); | 289 | errExit("mount bind"); |
292 | 290 | ||
@@ -433,6 +431,7 @@ void fs_check_private_cwd(const char *dir) { | |||
433 | // --private-home | 431 | // --private-home |
434 | //*********************************************************************************** | 432 | //*********************************************************************************** |
435 | static char *check_dir_or_file(const char *name) { | 433 | static char *check_dir_or_file(const char *name) { |
434 | EUID_ASSERT(); | ||
436 | assert(name); | 435 | assert(name); |
437 | 436 | ||
438 | // basic checks | 437 | // basic checks |
@@ -493,6 +492,7 @@ errexit: | |||
493 | } | 492 | } |
494 | 493 | ||
495 | static void duplicate(char *name) { | 494 | static void duplicate(char *name) { |
495 | EUID_ASSERT(); | ||
496 | char *fname = check_dir_or_file(name); | 496 | char *fname = check_dir_or_file(name); |
497 | 497 | ||
498 | if (arg_debug) | 498 | if (arg_debug) |
@@ -548,10 +548,10 @@ void fs_private_home_list(void) { | |||
548 | selinux_relabel_path(RUN_HOME_DIR, homedir); | 548 | selinux_relabel_path(RUN_HOME_DIR, homedir); |
549 | fs_logger_print(); // save the current log | 549 | fs_logger_print(); // save the current log |
550 | 550 | ||
551 | // copy the list of files in the new home directory | ||
552 | EUID_USER(); | ||
551 | if (arg_debug) | 553 | if (arg_debug) |
552 | printf("Copying files in the new home:\n"); | 554 | printf("Copying files in the new home:\n"); |
553 | |||
554 | // copy the list of files in the new home directory | ||
555 | char *dlist = strdup(cfg.home_private_keep); | 555 | char *dlist = strdup(cfg.home_private_keep); |
556 | if (!dlist) | 556 | if (!dlist) |
557 | errExit("strdup"); | 557 | errExit("strdup"); |
@@ -584,6 +584,7 @@ void fs_private_home_list(void) { | |||
584 | exit(1); | 584 | exit(1); |
585 | } | 585 | } |
586 | // mount using the file descriptor | 586 | // mount using the file descriptor |
587 | EUID_ROOT(); | ||
587 | if (bind_mount_path_to_fd(RUN_HOME_DIR, fd)) | 588 | if (bind_mount_path_to_fd(RUN_HOME_DIR, fd)) |
588 | errExit("mount bind"); | 589 | errExit("mount bind"); |
589 | close(fd); | 590 | close(fd); |
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c index 8369e6259..9d7a17cf3 100644 --- a/src/firejail/fs_lib.c +++ b/src/firejail/fs_lib.c | |||
@@ -178,8 +178,7 @@ void fslib_mount(const char *full_path) { | |||
178 | 178 | ||
179 | if (*full_path == '\0' || | 179 | if (*full_path == '\0' || |
180 | !valid_full_path(full_path) || | 180 | !valid_full_path(full_path) || |
181 | access(full_path, F_OK) != 0 || | 181 | stat_as_user(full_path, &s) != 0 || |
182 | stat(full_path, &s) != 0 || | ||
183 | s.st_uid != 0) | 182 | s.st_uid != 0) |
184 | return; | 183 | return; |
185 | 184 | ||
@@ -246,7 +245,7 @@ static void load_library(const char *fname) { | |||
246 | 245 | ||
247 | // existing file owned by root | 246 | // existing file owned by root |
248 | struct stat s; | 247 | struct stat s; |
249 | if (!access(fname, F_OK) && stat(fname, &s) == 0 && s.st_uid == 0) { | 248 | if (stat_as_user(fname, &s) == 0 && s.st_uid == 0) { |
250 | // load directories, regular 64 bit libraries, and 64 bit executables | 249 | // load directories, regular 64 bit libraries, and 64 bit executables |
251 | if (S_ISDIR(s.st_mode)) | 250 | if (S_ISDIR(s.st_mode)) |
252 | fslib_mount(fname); | 251 | fslib_mount(fname); |
@@ -286,12 +285,14 @@ static void install_list_entry(const char *lib) { | |||
286 | #define DO_GLOBBING | 285 | #define DO_GLOBBING |
287 | #ifdef DO_GLOBBING | 286 | #ifdef DO_GLOBBING |
288 | // globbing | 287 | // globbing |
288 | EUID_USER(); | ||
289 | glob_t globbuf; | 289 | glob_t globbuf; |
290 | int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf); | 290 | int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf); |
291 | if (globerr) { | 291 | if (globerr) { |
292 | fprintf(stderr, "Error: failed to glob private-lib pattern %s\n", fname); | 292 | fprintf(stderr, "Error: failed to glob private-lib pattern %s\n", fname); |
293 | exit(1); | 293 | exit(1); |
294 | } | 294 | } |
295 | EUID_ROOT(); | ||
295 | size_t j; | 296 | size_t j; |
296 | for (j = 0; j < globbuf.gl_pathc; j++) { | 297 | for (j = 0; j < globbuf.gl_pathc; j++) { |
297 | assert(globbuf.gl_pathv[j]); | 298 | assert(globbuf.gl_pathv[j]); |
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index ec3fe4c5b..370035a4d 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -257,6 +257,7 @@ static void whitelist_symlink(const char *link, const char *target) { | |||
257 | } | 257 | } |
258 | 258 | ||
259 | static void globbing(const char *pattern) { | 259 | static void globbing(const char *pattern) { |
260 | EUID_ASSERT(); | ||
260 | assert(pattern); | 261 | assert(pattern); |
261 | 262 | ||
262 | // globbing | 263 | // globbing |
diff --git a/src/firejail/macros.c b/src/firejail/macros.c index bcac1feb4..cd29d8f85 100644 --- a/src/firejail/macros.c +++ b/src/firejail/macros.c | |||
@@ -149,6 +149,7 @@ static char *resolve_xdg(const char *var) { | |||
149 | 149 | ||
150 | // returns mallocated memory | 150 | // returns mallocated memory |
151 | static char *resolve_hardcoded(char *entries[]) { | 151 | static char *resolve_hardcoded(char *entries[]) { |
152 | EUID_ASSERT(); | ||
152 | char *fname; | 153 | char *fname; |
153 | struct stat s; | 154 | struct stat s; |
154 | 155 | ||
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c index a700729d3..64a94bd84 100644 --- a/src/firejail/mountinfo.c +++ b/src/firejail/mountinfo.c | |||
@@ -22,7 +22,7 @@ | |||
22 | 22 | ||
23 | #include <fcntl.h> | 23 | #include <fcntl.h> |
24 | #ifndef O_PATH | 24 | #ifndef O_PATH |
25 | # define O_PATH 010000000 | 25 | #define O_PATH 010000000 |
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | #define MAX_BUF 4096 | 28 | #define MAX_BUF 4096 |
@@ -153,6 +153,7 @@ MountData *get_last_mount(void) { | |||
153 | 153 | ||
154 | // Extract the mount id from /proc/self/fdinfo and return it. | 154 | // Extract the mount id from /proc/self/fdinfo and return it. |
155 | int get_mount_id(const char *path) { | 155 | int get_mount_id(const char *path) { |
156 | EUID_ASSERT(); | ||
156 | assert(path); | 157 | assert(path); |
157 | 158 | ||
158 | int fd = open(path, O_PATH|O_CLOEXEC); | 159 | int fd = open(path, O_PATH|O_CLOEXEC); |
@@ -162,7 +163,9 @@ int get_mount_id(const char *path) { | |||
162 | char *fdinfo; | 163 | char *fdinfo; |
163 | if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) | 164 | if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) |
164 | errExit("asprintf"); | 165 | errExit("asprintf"); |
166 | EUID_ROOT(); | ||
165 | FILE *fp = fopen(fdinfo, "re"); | 167 | FILE *fp = fopen(fdinfo, "re"); |
168 | EUID_USER(); | ||
166 | free(fdinfo); | 169 | free(fdinfo); |
167 | if (!fp) | 170 | if (!fp) |
168 | goto errexit; | 171 | goto errexit; |
diff --git a/src/firejail/paths.c b/src/firejail/paths.c index b800fa944..d58a9d272 100644 --- a/src/firejail/paths.c +++ b/src/firejail/paths.c | |||
@@ -136,7 +136,7 @@ int program_in_path(const char *program) { | |||
136 | // ('x' permission means something different for directories). | 136 | // ('x' permission means something different for directories). |
137 | // exec follows symlinks, so use stat, not lstat. | 137 | // exec follows symlinks, so use stat, not lstat. |
138 | struct stat st; | 138 | struct stat st; |
139 | if (stat(scratch, &st)) { | 139 | if (stat_as_user(scratch, &st)) { |
140 | perror(scratch); | 140 | perror(scratch); |
141 | exit(1); | 141 | exit(1); |
142 | } | 142 | } |
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c index d2c0bcc19..37111324a 100644 --- a/src/firejail/sbox.c +++ b/src/firejail/sbox.c | |||
@@ -265,7 +265,6 @@ int sbox_run(unsigned filtermask, int num, ...) { | |||
265 | } | 265 | } |
266 | 266 | ||
267 | int sbox_run_v(unsigned filtermask, char * const arg[]) { | 267 | int sbox_run_v(unsigned filtermask, char * const arg[]) { |
268 | EUID_ROOT(); | ||
269 | assert(arg); | 268 | assert(arg); |
270 | 269 | ||
271 | if (arg_debug) { | 270 | if (arg_debug) { |
@@ -285,6 +284,7 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) { | |||
285 | if (child < 0) | 284 | if (child < 0) |
286 | errExit("fork"); | 285 | errExit("fork"); |
287 | if (child == 0) { | 286 | if (child == 0) { |
287 | EUID_ROOT(); | ||
288 | sbox_do_exec_v(filtermask, arg); | 288 | sbox_do_exec_v(filtermask, arg); |
289 | } | 289 | } |
290 | 290 | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c index 44f1cbd02..b8643ff60 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -417,6 +417,13 @@ int is_dir(const char *fname) { | |||
417 | if (*fname == '\0') | 417 | if (*fname == '\0') |
418 | return 0; | 418 | return 0; |
419 | 419 | ||
420 | int called_as_root = 0; | ||
421 | if (geteuid() == 0) | ||
422 | called_as_root = 1; | ||
423 | |||
424 | if (called_as_root) | ||
425 | EUID_USER(); | ||
426 | |||
420 | // if fname doesn't end in '/', add one | 427 | // if fname doesn't end in '/', add one |
421 | int rv; | 428 | int rv; |
422 | struct stat s; | 429 | struct stat s; |
@@ -432,6 +439,9 @@ int is_dir(const char *fname) { | |||
432 | free(tmp); | 439 | free(tmp); |
433 | } | 440 | } |
434 | 441 | ||
442 | if (called_as_root) | ||
443 | EUID_ROOT(); | ||
444 | |||
435 | if (rv == -1) | 445 | if (rv == -1) |
436 | return 0; | 446 | return 0; |
437 | 447 | ||
@@ -447,6 +457,14 @@ int is_link(const char *fname) { | |||
447 | if (*fname == '\0') | 457 | if (*fname == '\0') |
448 | return 0; | 458 | return 0; |
449 | 459 | ||
460 | int called_as_root = 0; | ||
461 | if (geteuid() == 0) | ||
462 | called_as_root = 1; | ||
463 | |||
464 | if (called_as_root) | ||
465 | EUID_USER(); | ||
466 | |||
467 | // remove trailing '/' if any | ||
450 | char *tmp = strdup(fname); | 468 | char *tmp = strdup(fname); |
451 | if (!tmp) | 469 | if (!tmp) |
452 | errExit("strdup"); | 470 | errExit("strdup"); |
@@ -456,9 +474,66 @@ int is_link(const char *fname) { | |||
456 | ssize_t rv = readlink(tmp, &c, 1); | 474 | ssize_t rv = readlink(tmp, &c, 1); |
457 | free(tmp); | 475 | free(tmp); |
458 | 476 | ||
477 | if (called_as_root) | ||
478 | EUID_ROOT(); | ||
479 | |||
459 | return (rv != -1); | 480 | return (rv != -1); |
460 | } | 481 | } |
461 | 482 | ||
483 | char *realpath_as_user(const char *fname) { | ||
484 | assert(fname); | ||
485 | |||
486 | int called_as_root = 0; | ||
487 | if (geteuid() == 0) | ||
488 | called_as_root = 1; | ||
489 | |||
490 | if (called_as_root) | ||
491 | EUID_USER(); | ||
492 | |||
493 | char *rv = realpath(fname, NULL); | ||
494 | |||
495 | if (called_as_root) | ||
496 | EUID_ROOT(); | ||
497 | |||
498 | return rv; | ||
499 | } | ||
500 | |||
501 | int stat_as_user(const char *fname, struct stat *s) { | ||
502 | assert(fname); | ||
503 | |||
504 | int called_as_root = 0; | ||
505 | if (geteuid() == 0) | ||
506 | called_as_root = 1; | ||
507 | |||
508 | if (called_as_root) | ||
509 | EUID_USER(); | ||
510 | |||
511 | int rv = stat(fname, s); | ||
512 | |||
513 | if (called_as_root) | ||
514 | EUID_ROOT(); | ||
515 | |||
516 | return rv; | ||
517 | } | ||
518 | |||
519 | int lstat_as_user(const char *fname, struct stat *s) { | ||
520 | assert(fname); | ||
521 | |||
522 | int called_as_root = 0; | ||
523 | if (geteuid() == 0) | ||
524 | called_as_root = 1; | ||
525 | |||
526 | if (called_as_root) | ||
527 | EUID_USER(); | ||
528 | |||
529 | int rv = lstat(fname, s); | ||
530 | |||
531 | if (called_as_root) | ||
532 | EUID_ROOT(); | ||
533 | |||
534 | return rv; | ||
535 | } | ||
536 | |||
462 | // remove all slashes and single dots from the end of a path | 537 | // remove all slashes and single dots from the end of a path |
463 | // for example /foo/bar///././. -> /foo/bar | 538 | // for example /foo/bar///././. -> /foo/bar |
464 | void trim_trailing_slash_or_dot(char *path) { | 539 | void trim_trailing_slash_or_dot(char *path) { |
@@ -891,14 +966,13 @@ static int remove_callback(const char *fpath, const struct stat *sb, int typefla | |||
891 | 966 | ||
892 | int remove_overlay_directory(void) { | 967 | int remove_overlay_directory(void) { |
893 | EUID_ASSERT(); | 968 | EUID_ASSERT(); |
894 | struct stat s; | ||
895 | sleep(1); | 969 | sleep(1); |
896 | 970 | ||
897 | char *path; | 971 | char *path; |
898 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | 972 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) |
899 | errExit("asprintf"); | 973 | errExit("asprintf"); |
900 | 974 | ||
901 | if (lstat(path, &s) == 0) { | 975 | if (access(path, F_OK) == 0) { |
902 | pid_t child = fork(); | 976 | pid_t child = fork(); |
903 | if (child < 0) | 977 | if (child < 0) |
904 | errExit("fork"); | 978 | errExit("fork"); |
@@ -909,6 +983,7 @@ int remove_overlay_directory(void) { | |||
909 | fprintf(stderr, "Error: cannot open %s\n", path); | 983 | fprintf(stderr, "Error: cannot open %s\n", path); |
910 | _exit(1); | 984 | _exit(1); |
911 | } | 985 | } |
986 | struct stat s; | ||
912 | if (fstat(fd, &s) == -1) | 987 | if (fstat(fd, &s) == -1) |
913 | errExit("fstat"); | 988 | errExit("fstat"); |
914 | if (!S_ISDIR(s.st_mode)) { | 989 | if (!S_ISDIR(s.st_mode)) { |
@@ -944,7 +1019,7 @@ int remove_overlay_directory(void) { | |||
944 | // wait for the child to finish | 1019 | // wait for the child to finish |
945 | waitpid(child, NULL, 0); | 1020 | waitpid(child, NULL, 0); |
946 | // check if ~/.firejail was deleted | 1021 | // check if ~/.firejail was deleted |
947 | if (stat(path, &s) == 0) | 1022 | if (access(path, F_OK) == 0) |
948 | return 1; | 1023 | return 1; |
949 | } | 1024 | } |
950 | return 0; | 1025 | return 0; |
@@ -977,9 +1052,8 @@ void flush_stdin(void) { | |||
977 | int create_empty_dir_as_user(const char *dir, mode_t mode) { | 1052 | int create_empty_dir_as_user(const char *dir, mode_t mode) { |
978 | assert(dir); | 1053 | assert(dir); |
979 | mode &= 07777; | 1054 | mode &= 07777; |
980 | struct stat s; | ||
981 | 1055 | ||
982 | if (stat(dir, &s)) { | 1056 | if (access(dir, F_OK) != 0) { |
983 | if (arg_debug) | 1057 | if (arg_debug) |
984 | printf("Creating empty %s directory\n", dir); | 1058 | printf("Creating empty %s directory\n", dir); |
985 | pid_t child = fork(); | 1059 | pid_t child = fork(); |
@@ -1001,7 +1075,7 @@ int create_empty_dir_as_user(const char *dir, mode_t mode) { | |||
1001 | _exit(0); | 1075 | _exit(0); |
1002 | } | 1076 | } |
1003 | waitpid(child, NULL, 0); | 1077 | waitpid(child, NULL, 0); |
1004 | if (stat(dir, &s) == 0) | 1078 | if (access(dir, F_OK) == 0) |
1005 | return 1; | 1079 | return 1; |
1006 | } | 1080 | } |
1007 | return 0; | 1081 | return 0; |
@@ -1113,8 +1187,11 @@ unsigned extract_timeout(const char *str) { | |||
1113 | 1187 | ||
1114 | void disable_file_or_dir(const char *fname) { | 1188 | void disable_file_or_dir(const char *fname) { |
1115 | assert(fname); | 1189 | assert(fname); |
1190 | assert(geteuid() == 0); | ||
1116 | 1191 | ||
1192 | EUID_USER(); | ||
1117 | int fd = open(fname, O_PATH|O_CLOEXEC); | 1193 | int fd = open(fname, O_PATH|O_CLOEXEC); |
1194 | EUID_ROOT(); | ||
1118 | if (fd < 0) | 1195 | if (fd < 0) |
1119 | return; | 1196 | return; |
1120 | 1197 | ||
diff --git a/src/firejail/x11.c b/src/firejail/x11.c index afe77e246..09956b903 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c | |||
@@ -204,7 +204,6 @@ static int random_display_number(void) { | |||
204 | void x11_start_xvfb(int argc, char **argv) { | 204 | void x11_start_xvfb(int argc, char **argv) { |
205 | EUID_ASSERT(); | 205 | EUID_ASSERT(); |
206 | int i; | 206 | int i; |
207 | struct stat s; | ||
208 | pid_t jail = 0; | 207 | pid_t jail = 0; |
209 | pid_t server = 0; | 208 | pid_t server = 0; |
210 | 209 | ||
@@ -348,7 +347,7 @@ void x11_start_xvfb(int argc, char **argv) { | |||
348 | // wait for x11 server to start | 347 | // wait for x11 server to start |
349 | while (++n < 10) { | 348 | while (++n < 10) { |
350 | sleep(1); | 349 | sleep(1); |
351 | if (stat(fname, &s) == 0) | 350 | if (access(fname, F_OK) == 0) |
352 | break; | 351 | break; |
353 | }; | 352 | }; |
354 | 353 | ||
@@ -427,7 +426,6 @@ static char *extract_setting(int argc, char **argv, const char *argument) { | |||
427 | void x11_start_xephyr(int argc, char **argv) { | 426 | void x11_start_xephyr(int argc, char **argv) { |
428 | EUID_ASSERT(); | 427 | EUID_ASSERT(); |
429 | int i; | 428 | int i; |
430 | struct stat s; | ||
431 | pid_t jail = 0; | 429 | pid_t jail = 0; |
432 | pid_t server = 0; | 430 | pid_t server = 0; |
433 | 431 | ||
@@ -586,7 +584,7 @@ void x11_start_xephyr(int argc, char **argv) { | |||
586 | // wait for x11 server to start | 584 | // wait for x11 server to start |
587 | while (++n < 10) { | 585 | while (++n < 10) { |
588 | sleep(1); | 586 | sleep(1); |
589 | if (stat(fname, &s) == 0) | 587 | if (access(fname, F_OK) == 0) |
590 | break; | 588 | break; |
591 | }; | 589 | }; |
592 | 590 | ||
@@ -701,7 +699,6 @@ static char * get_title_arg_str() { | |||
701 | static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, int display, char *display_str) { | 699 | static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, int display, char *display_str) { |
702 | EUID_ASSERT(); | 700 | EUID_ASSERT(); |
703 | int i; | 701 | int i; |
704 | struct stat s; | ||
705 | pid_t client = 0; | 702 | pid_t client = 0; |
706 | pid_t server = 0; | 703 | pid_t server = 0; |
707 | 704 | ||
@@ -818,7 +815,7 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, | |||
818 | // wait for x11 server to start | 815 | // wait for x11 server to start |
819 | while (++n < 10) { | 816 | while (++n < 10) { |
820 | sleep(1); | 817 | sleep(1); |
821 | if (stat(fname, &s) == 0) | 818 | if (access(fname, F_OK) == 0) |
822 | break; | 819 | break; |
823 | } | 820 | } |
824 | 821 | ||
@@ -1231,9 +1228,9 @@ void x11_xorg(void) { | |||
1231 | char *dest; | 1228 | char *dest; |
1232 | if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) | 1229 | if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) |
1233 | errExit("asprintf"); | 1230 | errExit("asprintf"); |
1234 | if (lstat(dest, &s) == -1) { | 1231 | if (access(dest, F_OK) == -1) { |
1235 | touch_file_as_user(dest, 0600); | 1232 | touch_file_as_user(dest, 0600); |
1236 | if (stat(dest, &s) == -1) { | 1233 | if (access(dest, F_OK) == -1) { |
1237 | fprintf(stderr, "Error: cannot create %s\n", dest); | 1234 | fprintf(stderr, "Error: cannot create %s\n", dest); |
1238 | exit(1); | 1235 | exit(1); |
1239 | } | 1236 | } |
@@ -1292,7 +1289,7 @@ void x11_xorg(void) { | |||
1292 | // blacklist user .Xauthority file if it is not masked already | 1289 | // blacklist user .Xauthority file if it is not masked already |
1293 | const char *envar = env_get("XAUTHORITY"); | 1290 | const char *envar = env_get("XAUTHORITY"); |
1294 | if (envar) { | 1291 | if (envar) { |
1295 | char *rp = realpath(envar, NULL); | 1292 | char *rp = realpath_as_user(envar); |
1296 | if (rp) { | 1293 | if (rp) { |
1297 | if (strcmp(rp, dest) != 0) | 1294 | if (strcmp(rp, dest) != 0) |
1298 | disable_file_or_dir(rp); | 1295 | disable_file_or_dir(rp); |