aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README8
-rw-r--r--RELNOTES4
-rw-r--r--etc/Cryptocat.profile2
-rw-r--r--etc/disable-common.inc8
-rw-r--r--etc/disable-devel.inc3
-rw-r--r--etc/disable-passwdmgr.inc3
-rw-r--r--etc/disable-programs.inc12
-rw-r--r--etc/evolution.profile3
-rw-r--r--etc/uzbl-browser.profile27
-rw-r--r--etc/whitelist-common.inc3
-rw-r--r--src/firejail/firejail.h6
-rw-r--r--src/firejail/fs.c116
-rw-r--r--src/firejail/fs_dev.c3
-rw-r--r--src/firejail/fs_etc.c4
-rw-r--r--src/firejail/fs_home.c148
-rw-r--r--src/firejail/fs_mkdir.c29
-rw-r--r--src/firejail/ls.c8
-rw-r--r--src/firejail/main.c7
-rw-r--r--src/firejail/preproc.c8
-rw-r--r--src/firejail/profile.c5
-rw-r--r--src/firejail/pulseaudio.c3
-rw-r--r--src/firejail/util.c46
-rw-r--r--src/firejail/x11.c19
-rw-r--r--src/man/firejail-profile.txt6
-rw-r--r--src/man/firejail.txt2
25 files changed, 292 insertions, 191 deletions
diff --git a/README b/README
index c94560026..67d9a555f 100644
--- a/README
+++ b/README
@@ -97,6 +97,10 @@ valoq (https://github.com/valoq)
97 - added skanlite, ssh-agent, transmission-cli, tracker, transmission-show, w3m, xfburn, xpra profiles 97 - added skanlite, ssh-agent, transmission-cli, tracker, transmission-show, w3m, xfburn, xpra profiles
98 - added wget profile 98 - added wget profile
99 - disable gnupg and systemd directories under /run/user 99 - disable gnupg and systemd directories under /run/user
100Mike Frysinger (vapier@gentoo.org)
101 - Gentoo compile patch
102Jericho (https://github.com/attritionorg)
103 - spelling
100Pixel Fairy (https://github.com/xahare) 104Pixel Fairy (https://github.com/xahare)
101 - added fjclip.py, fjdisplay.py and fjresize.py in contrib section 105 - added fjclip.py, fjdisplay.py and fjresize.py in contrib section
102pshpsh (https://github.com/pshpsh) 106pshpsh (https://github.com/pshpsh)
@@ -108,6 +112,7 @@ thewisenerd (https://github.com/thewisenerd)
108 - use $SHELL variable if the shell is not specified 112 - use $SHELL variable if the shell is not specified
109SYN-cook (https://github.com/SYN-cook) 113SYN-cook (https://github.com/SYN-cook)
110 - keepass/keepassx browser fixes 114 - keepass/keepassx browser fixes
115 - disable-common.inc fixes
111thewisenerd (https://github.com/thewisenerd) 116thewisenerd (https://github.com/thewisenerd)
112 - appimage: pass commandline arguments 117 - appimage: pass commandline arguments
113KOLANICH (https://github.com/KOLANICH) 118KOLANICH (https://github.com/KOLANICH)
@@ -217,6 +222,8 @@ KellerFuchs (https://github.com/KellerFuchs)
217 - nonewpriv support, extended profiles for this feature 222 - nonewpriv support, extended profiles for this feature
218 - make `restricted-network` prevent use of netfilter 223 - make `restricted-network` prevent use of netfilter
219 - disable-common.inc additions 224 - disable-common.inc additions
225 - make mutt and msmtp's rc files read-only
226 - added support for .local profile files in /etc/firejail
220ValdikSS (https://github.com/ValdikSS) 227ValdikSS (https://github.com/ValdikSS)
221 - Psi+, Corebird, Konversation profiles 228 - Psi+, Corebird, Konversation profiles
222 - various profile fixes 229 - various profile fixes
@@ -296,6 +303,7 @@ Ivan Kozik (https://github.com/ivan)
296 - speed up sandbox exit 303 - speed up sandbox exit
297Christian Stadelmann (https://github.com/genodeftest) 304Christian Stadelmann (https://github.com/genodeftest)
298 - profile fixes 305 - profile fixes
306 - evolution profile fix
299pirate486743186 (https://github.com/pirate486743186) 307pirate486743186 (https://github.com/pirate486743186)
300 - KMail profile 308 - KMail profile
301Kaan Genç (https://github.com/SeriousBug) 309Kaan Genç (https://github.com/SeriousBug)
diff --git a/RELNOTES b/RELNOTES
index a14200a0f..7d0bbaf61 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,12 +1,13 @@
1firejail (0.9.45) baseline; urgency=low 1firejail (0.9.45) baseline; urgency=low
2 * development version, work in progress 2 * development version, work in progress
3 * Gentoo compile patch
3 * security: --bandwidth root shell found by Martin Carpenter (CVE-2017-5207) 4 * security: --bandwidth root shell found by Martin Carpenter (CVE-2017-5207)
4 * security: disabled --allow-debuggers when running on kernel 5 * security: disabled --allow-debuggers when running on kernel
5 versions prior to 4.8; a kernel bug in ptrace system call 6 versions prior to 4.8; a kernel bug in ptrace system call
6 allows a full bypass of seccomp filter; problem reported by Lizzie Dixon 7 allows a full bypass of seccomp filter; problem reported by Lizzie Dixon
7 (CVE-2017-5206) 8 (CVE-2017-5206)
8 * security: overwrite /etc/resolv.conf found by Martin Carpenter (CVE-2016-10118) 9 * security: overwrite /etc/resolv.conf found by Martin Carpenter (CVE-2016-10118)
9 * secuirty: TOCTOU exploit for --get and --put found by Daniel Hodson 10 * security: TOCTOU exploit for --get and --put found by Daniel Hodson
10 * security: invalid environment exploit found by Martin Carpenter (CVE-2016-10122) 11 * security: invalid environment exploit found by Martin Carpenter (CVE-2016-10122)
11 * security: split most of networking code in a separate executable 12 * security: split most of networking code in a separate executable
12 * security: split seccomp filter code configuration in a separate executable 13 * security: split seccomp filter code configuration in a separate executable
@@ -24,6 +25,7 @@ firejail (0.9.45) baseline; urgency=low
24 * feature: --allow-private-blacklist option 25 * feature: --allow-private-blacklist option
25 * feature: allow non-seccomp setup for OverlayFS sandboxes 26 * feature: allow non-seccomp setup for OverlayFS sandboxes
26 * feature: added a number o Python scripts for handling sandboxes 27 * feature: added a number o Python scripts for handling sandboxes
28 * feature: allow local customization using .local files under /etc/firejail
27 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire, 29 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire,
28 * new profiles: mumble, zoom, Guayadeque, qemu, keypass2, xed, pluma, 30 * new profiles: mumble, zoom, Guayadeque, qemu, keypass2, xed, pluma,
29 * new profiles: Cryptocat, Bless, Gnome 2048, Gnome Calculator, 31 * new profiles: Cryptocat, Bless, Gnome 2048, Gnome Calculator,
diff --git a/etc/Cryptocat.profile b/etc/Cryptocat.profile
index 3db34c03c..b61b88f68 100644
--- a/etc/Cryptocat.profile
+++ b/etc/Cryptocat.profile
@@ -1,4 +1,4 @@
1# Firejail profile for 1# Firejail profile for Cryptocat
2noblacklist ${HOME}/.config/Cryptocat 2noblacklist ${HOME}/.config/Cryptocat
3 3
4include /etc/firejail/disable-common.inc 4include /etc/firejail/disable-common.inc
diff --git a/etc/disable-common.inc b/etc/disable-common.inc
index 184885c7f..ac32f07e7 100644
--- a/etc/disable-common.inc
+++ b/etc/disable-common.inc
@@ -1,3 +1,6 @@
1# Local customizations come here
2include /etc/firejail/disable-common.local
3
1# History files in $HOME 4# History files in $HOME
2blacklist-nolog ${HOME}/.history 5blacklist-nolog ${HOME}/.history
3blacklist-nolog ${HOME}/.*_history 6blacklist-nolog ${HOME}/.*_history
@@ -81,6 +84,7 @@ read-only ${HOME}/.profile
81read-only ${HOME}/.antigen 84read-only ${HOME}/.antigen
82read-only ${HOME}/.bash_login 85read-only ${HOME}/.bash_login
83read-only ${HOME}/.bashrc 86read-only ${HOME}/.bashrc
87read-only ${HOME}/.bash_aliases
84read-only ${HOME}/.bash_profile 88read-only ${HOME}/.bash_profile
85read-only ${HOME}/.bash_logout 89read-only ${HOME}/.bash_logout
86read-only ${HOME}/.zsh.d 90read-only ${HOME}/.zsh.d
@@ -101,6 +105,9 @@ read-only ${HOME}/.caffrc
101read-only ${HOME}/.dotfiles 105read-only ${HOME}/.dotfiles
102read-only ${HOME}/dotfiles 106read-only ${HOME}/dotfiles
103read-only ${HOME}/.mailcap 107read-only ${HOME}/.mailcap
108read-only ${HOME}/.muttrc
109read-only ${HOME}/.mutt/muttrc
110read-only ${HOME}/.msmtprc
104read-only ${HOME}/.exrc 111read-only ${HOME}/.exrc
105read-only ${HOME}/_exrc 112read-only ${HOME}/_exrc
106read-only ${HOME}/.vimrc 113read-only ${HOME}/.vimrc
@@ -134,6 +141,7 @@ blacklist ${HOME}/.Private
134blacklist ${HOME}/.ssh 141blacklist ${HOME}/.ssh
135blacklist ${HOME}/.cert 142blacklist ${HOME}/.cert
136blacklist ${HOME}/.gnome2/keyrings 143blacklist ${HOME}/.gnome2/keyrings
144blacklist ${HOME}/.local/share/keyrings
137blacklist ${HOME}/.kde4/share/apps/kwallet 145blacklist ${HOME}/.kde4/share/apps/kwallet
138blacklist ${HOME}/.kde/share/apps/kwallet 146blacklist ${HOME}/.kde/share/apps/kwallet
139blacklist ${HOME}/.local/share/kwalletd 147blacklist ${HOME}/.local/share/kwalletd
diff --git a/etc/disable-devel.inc b/etc/disable-devel.inc
index 2ac367f37..07fc3928c 100644
--- a/etc/disable-devel.inc
+++ b/etc/disable-devel.inc
@@ -1,3 +1,6 @@
1# Local customizations come here
2include /etc/firejail/disable-devel.local
3
1# development tools 4# development tools
2 5
3# GCC 6# GCC
diff --git a/etc/disable-passwdmgr.inc b/etc/disable-passwdmgr.inc
index 045b4d92b..7d129b2e4 100644
--- a/etc/disable-passwdmgr.inc
+++ b/etc/disable-passwdmgr.inc
@@ -1,3 +1,6 @@
1# Local customizations come here
2include /etc/firejail/disable-passwdmgr.local
3
1blacklist ${HOME}/.pki/nssdb 4blacklist ${HOME}/.pki/nssdb
2blacklist ${HOME}/.lastpass 5blacklist ${HOME}/.lastpass
3blacklist ${HOME}/.keepassx 6blacklist ${HOME}/.keepassx
diff --git a/etc/disable-programs.inc b/etc/disable-programs.inc
index e5eb4f857..b307978da 100644
--- a/etc/disable-programs.inc
+++ b/etc/disable-programs.inc
@@ -1,3 +1,6 @@
1# Local customizations come here
2include /etc/firejail/disable-programs.local
3
1blacklist ${HOME}/.*coin 4blacklist ${HOME}/.*coin
2blacklist ${HOME}/.8pecxstudios 5blacklist ${HOME}/.8pecxstudios
3blacklist ${HOME}/.Atom 6blacklist ${HOME}/.Atom
@@ -174,8 +177,17 @@ blacklist ${HOME}/.icedove
174blacklist ${HOME}/.inkscape 177blacklist ${HOME}/.inkscape
175blacklist ${HOME}/.jitsi 178blacklist ${HOME}/.jitsi
176blacklist ${HOME}/.kde/share/apps/gwenview 179blacklist ${HOME}/.kde/share/apps/gwenview
180blacklist ${HOME}/.kde/share/apps/kcookiejar
181blacklist ${HOME}/.kde/share/apps/khtml
182blacklist ${HOME}/.kde/share/apps/konqsidebartng
183blacklist ${HOME}/.kde/share/apps/konqueror
177blacklist ${HOME}/.kde/share/apps/okular 184blacklist ${HOME}/.kde/share/apps/okular
178blacklist ${HOME}/.kde/share/config/gwenviewrc 185blacklist ${HOME}/.kde/share/config/gwenviewrc
186blacklist ${HOME}/.kde/share/config/kcookiejarrc
187blacklist ${HOME}/.kde/share/config/khtmlrc
188blacklist ${HOME}/.kde/share/config/konq_history
189blacklist ${HOME}/.kde/share/config/konqsidebartngrc
190blacklist ${HOME}/.kde/share/config/konquerorrc
179blacklist ${HOME}/.kde/share/config/okularpartrc 191blacklist ${HOME}/.kde/share/config/okularpartrc
180blacklist ${HOME}/.kde/share/config/okularrc 192blacklist ${HOME}/.kde/share/config/okularrc
181blacklist ${HOME}/.killingfloor 193blacklist ${HOME}/.killingfloor
diff --git a/etc/evolution.profile b/etc/evolution.profile
index ab6dd7a4a..1707e562b 100644
--- a/etc/evolution.profile
+++ b/etc/evolution.profile
@@ -6,6 +6,9 @@ noblacklist ~/.pki
6noblacklist ~/.pki/nssdb 6noblacklist ~/.pki/nssdb
7noblacklist ~/.gnupg 7noblacklist ~/.gnupg
8 8
9noblacklist /var/spool/mail
10noblacklist /var/mail
11
9include /etc/firejail/disable-common.inc 12include /etc/firejail/disable-common.inc
10include /etc/firejail/disable-programs.inc 13include /etc/firejail/disable-programs.inc
11include /etc/firejail/disable-devel.inc 14include /etc/firejail/disable-devel.inc
diff --git a/etc/uzbl-browser.profile b/etc/uzbl-browser.profile
new file mode 100644
index 000000000..1346b7fc2
--- /dev/null
+++ b/etc/uzbl-browser.profile
@@ -0,0 +1,27 @@
1# Firejail profile for uzbl-browser
2
3noblacklist ~/.config/uzbl
4noblacklist ~/.cache/uzbl
5include /etc/firejail/disable-common.inc
6include /etc/firejail/disable-programs.inc
7include /etc/firejail/disable-devel.inc
8include /etc/firejail/disable-passwdmgr.inc
9
10caps.drop all
11netfilter
12nonewprivs
13noroot
14protocol unix,inet,inet6
15seccomp
16tracelog
17
18mkdir ~/.config/uzbl
19whitelist ~/.config/uzbl
20mkdir ~/.cache/uzbl
21whitelist ~/.cache/uzbl
22mkdir ~/.local/share/uzbl
23whitelist ~/.local/share/uzbl
24
25whitelist ${DOWNLOADS}
26
27include /etc/firejail/whitelist-common.inc
diff --git a/etc/whitelist-common.inc b/etc/whitelist-common.inc
index d4e69948e..cf7797100 100644
--- a/etc/whitelist-common.inc
+++ b/etc/whitelist-common.inc
@@ -1,3 +1,6 @@
1# Local customizations come here
2include /etc/firejail/whitelist-common.local
3
1# common whitelist for all profiles 4# common whitelist for all profiles
2 5
3whitelist ~/.XCompose 6whitelist ~/.XCompose
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 36cf47435..722d5c05e 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -105,7 +105,7 @@
105#define ASSERT_PERMS_FD(fd, uid, gid, mode) \ 105#define ASSERT_PERMS_FD(fd, uid, gid, mode) \
106 do { \ 106 do { \
107 struct stat s;\ 107 struct stat s;\
108 if (stat(fd, &s) == -1) errExit("stat");\ 108 if (fstat(fd, &s) == -1) errExit("fstat");\
109 assert(s.st_uid == uid);\ 109 assert(s.st_uid == uid);\
110 assert(s.st_gid == gid);\ 110 assert(s.st_gid == gid);\
111 assert((s.st_mode & 07777) == (mode));\ 111 assert((s.st_mode & 07777) == (mode));\
@@ -403,7 +403,7 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse);
403void fs_overlayfs(void); 403void fs_overlayfs(void);
404// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf 404// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf
405void fs_chroot(const char *rootdir); 405void fs_chroot(const char *rootdir);
406int fs_check_chroot_dir(const char *rootdir); 406void fs_check_chroot_dir(const char *rootdir);
407 407
408// profile.c 408// profile.c
409// find and read the profile specified by name from dir directory 409// find and read the profile specified by name from dir directory
@@ -450,6 +450,8 @@ void logmsg(const char *msg);
450void logargs(int argc, char **argv) ; 450void logargs(int argc, char **argv) ;
451void logerr(const char *msg); 451void logerr(const char *msg);
452int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode); 452int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode);
453void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode);
454void touch_file_as_user(const char *fname, uid_t uid, gid_t gid, mode_t mode);
453int is_dir(const char *fname); 455int is_dir(const char *fname);
454int is_link(const char *fname); 456int is_link(const char *fname);
455char *line_remove_spaces(const char *buf); 457char *line_remove_spaces(const char *buf);
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index e2fc09533..0da4cc111 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -711,10 +711,36 @@ char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) {
711 // create ~/.firejail directory 711 // create ~/.firejail directory
712 if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) 712 if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1)
713 errExit("asprintf"); 713 errExit("asprintf");
714
715 if (is_link(dirname)) {
716 fprintf(stderr, "Error: invalid ~/.firejail directory\n");
717 exit(1);
718 }
714 if (stat(dirname, &s) == -1) { 719 if (stat(dirname, &s) == -1) {
715 mkdir_attr(dirname, 0700, 0, 0); 720 // create directory
721 pid_t child = fork();
722 if (child < 0)
723 errExit("fork");
724 if (child == 0) {
725 // drop privileges
726 drop_privs(0);
727
728 // create directory
729 if (mkdir(dirname, 0700))
730 errExit("mkdir");
731 if (chmod(dirname, 0700) == -1)
732 errExit("chmod");
733 ASSERT_PERMS(dirname, getuid(), getgid(), 0700);
734 _exit(0);
735 }
736 // wait for the child to finish
737 waitpid(child, NULL, 0);
738 if (stat(dirname, &s) == -1) {
739 fprintf(stderr, "Error: cannot create ~/.firejail directory\n");
740 exit(1);
741 }
716 } 742 }
717 else if (is_link(dirname)) { 743 else if (s.st_uid != getuid()) {
718 fprintf(stderr, "Error: invalid ~/.firejail directory\n"); 744 fprintf(stderr, "Error: invalid ~/.firejail directory\n");
719 exit(1); 745 exit(1);
720 } 746 }
@@ -994,20 +1020,25 @@ void fs_overlayfs(void) {
994 1020
995#ifdef HAVE_CHROOT 1021#ifdef HAVE_CHROOT
996// return 1 if error 1022// return 1 if error
997int fs_check_chroot_dir(const char *rootdir) { 1023void fs_check_chroot_dir(const char *rootdir) {
998 EUID_ASSERT(); 1024 EUID_ASSERT();
999 assert(rootdir); 1025 assert(rootdir);
1000 struct stat s; 1026 struct stat s;
1001 char *name; 1027 char *name;
1002 1028
1029 if (strcmp(rootdir, "/tmp") == 0 || strcmp(rootdir, "/var/tmp") == 0) {
1030 fprintf(stderr, "Error: invalid chroot directory\n");
1031 exit(1);
1032 }
1033
1003 // rootdir has to be owned by root 1034 // rootdir has to be owned by root
1004 if (stat(rootdir, &s) != 0) { 1035 if (stat(rootdir, &s) != 0) {
1005 fprintf(stderr, "Error: cannot find chroot directory\n"); 1036 fprintf(stderr, "Error: cannot find chroot directory\n");
1006 return 1; 1037 exit(1);
1007 } 1038 }
1008 if (s.st_uid != 0) { 1039 if (s.st_uid != 0) {
1009 fprintf(stderr, "Error: chroot directory should be owned by root\n"); 1040 fprintf(stderr, "Error: chroot directory should be owned by root\n");
1010 return 1; 1041 exit(1);
1011 } 1042 }
1012 1043
1013 // check /dev 1044 // check /dev
@@ -1015,7 +1046,11 @@ int fs_check_chroot_dir(const char *rootdir) {
1015 errExit("asprintf"); 1046 errExit("asprintf");
1016 if (stat(name, &s) == -1) { 1047 if (stat(name, &s) == -1) {
1017 fprintf(stderr, "Error: cannot find /dev in chroot directory\n"); 1048 fprintf(stderr, "Error: cannot find /dev in chroot directory\n");
1018 return 1; 1049 exit(1);
1050 }
1051 if (s.st_uid != 0) {
1052 fprintf(stderr, "Error: chroot /dev directory should be owned by root\n");
1053 exit(1);
1019 } 1054 }
1020 free(name); 1055 free(name);
1021 1056
@@ -1024,7 +1059,11 @@ int fs_check_chroot_dir(const char *rootdir) {
1024 errExit("asprintf"); 1059 errExit("asprintf");
1025 if (stat(name, &s) == -1) { 1060 if (stat(name, &s) == -1) {
1026 fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n"); 1061 fprintf(stderr, "Error: cannot find /var/tmp in chroot directory\n");
1027 return 1; 1062 exit(1);
1063 }
1064 if (s.st_uid != 0) {
1065 fprintf(stderr, "Error: chroot /var/tmp directory should be owned by root\n");
1066 exit(1);
1028 } 1067 }
1029 free(name); 1068 free(name);
1030 1069
@@ -1033,7 +1072,11 @@ int fs_check_chroot_dir(const char *rootdir) {
1033 errExit("asprintf"); 1072 errExit("asprintf");
1034 if (stat(name, &s) == -1) { 1073 if (stat(name, &s) == -1) {
1035 fprintf(stderr, "Error: cannot find /proc in chroot directory\n"); 1074 fprintf(stderr, "Error: cannot find /proc in chroot directory\n");
1036 return 1; 1075 exit(1);
1076 }
1077 if (s.st_uid != 0) {
1078 fprintf(stderr, "Error: chroot /proc directory should be owned by root\n");
1079 exit(1);
1037 } 1080 }
1038 free(name); 1081 free(name);
1039 1082
@@ -1042,18 +1085,41 @@ int fs_check_chroot_dir(const char *rootdir) {
1042 errExit("asprintf"); 1085 errExit("asprintf");
1043 if (stat(name, &s) == -1) { 1086 if (stat(name, &s) == -1) {
1044 fprintf(stderr, "Error: cannot find /tmp in chroot directory\n"); 1087 fprintf(stderr, "Error: cannot find /tmp in chroot directory\n");
1045 return 1; 1088 exit(1);
1089 }
1090 if (s.st_uid != 0) {
1091 fprintf(stderr, "Error: chroot /tmp directory should be owned by root\n");
1092 exit(1);
1093 }
1094 free(name);
1095
1096 // check /etc
1097 if (asprintf(&name, "%s/etc", rootdir) == -1)
1098 errExit("asprintf");
1099 if (stat(name, &s) == -1) {
1100 fprintf(stderr, "Error: cannot find /etc in chroot directory\n");
1101 exit(1);
1102 }
1103 if (s.st_uid != 0) {
1104 fprintf(stderr, "Error: chroot /etc directory should be owned by root\n");
1105 exit(1);
1046 } 1106 }
1047 free(name); 1107 free(name);
1048 1108
1049 // check /bin/bash 1109 // check /etc/resolv.conf
1050// if (asprintf(&name, "%s/bin/bash", rootdir) == -1) 1110 if (asprintf(&name, "%s/etc/resolv.conf", rootdir) == -1)
1051// errExit("asprintf"); 1111 errExit("asprintf");
1052// if (stat(name, &s) == -1) { 1112 if (stat(name, &s) == 0) {
1053// fprintf(stderr, "Error: cannot find /bin/bash in chroot directory\n"); 1113 if (s.st_uid != 0) {
1054// return 1; 1114 fprintf(stderr, "Error: chroot /etc/resolv.conf should be owned by root\n");
1055// } 1115 exit(1);
1056// free(name); 1116 }
1117 }
1118 if (is_link(name)) {
1119 fprintf(stderr, "Error: invalid %s file\n", name);
1120 exit(1);
1121 }
1122 free(name);
1057 1123
1058 // check x11 socket directory 1124 // check x11 socket directory
1059 if (getenv("FIREJAIL_X11")) { 1125 if (getenv("FIREJAIL_X11")) {
@@ -1063,12 +1129,14 @@ int fs_check_chroot_dir(const char *rootdir) {
1063 errExit("asprintf"); 1129 errExit("asprintf");
1064 if (stat(name, &s) == -1) { 1130 if (stat(name, &s) == -1) {
1065 fprintf(stderr, "Error: cannot find /tmp/.X11-unix in chroot directory\n"); 1131 fprintf(stderr, "Error: cannot find /tmp/.X11-unix in chroot directory\n");
1066 return 1; 1132 exit(1);
1133 }
1134 if (s.st_uid != 0) {
1135 fprintf(stderr, "Error: chroot /tmp/.X11-unix directory should be owned by root\n");
1136 exit(1);
1067 } 1137 }
1068 free(name); 1138 free(name);
1069 } 1139 }
1070
1071 return 0;
1072} 1140}
1073 1141
1074// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf 1142// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf
@@ -1099,10 +1167,16 @@ void fs_chroot(const char *rootdir) {
1099 free(newx11); 1167 free(newx11);
1100 } 1168 }
1101 1169
1170 // some older distros don't have a /run directory
1171 // create one by default
1102 // create /run/firejail directory in chroot 1172 // create /run/firejail directory in chroot
1103 char *rundir; 1173 char *rundir;
1104 if (asprintf(&rundir, "%s/run", rootdir) == -1) 1174 if (asprintf(&rundir, "%s/run", rootdir) == -1)
1105 errExit("asprintf"); 1175 errExit("asprintf");
1176 if (is_link(rundir)) {
1177 fprintf(stderr, "Error: invalid run directory inside chroot\n");
1178 exit(1);
1179 }
1106 create_empty_dir_as_root(rundir, 0755); 1180 create_empty_dir_as_root(rundir, 0755);
1107 free(rundir); 1181 free(rundir);
1108 if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1) 1182 if (asprintf(&rundir, "%s/run/firejail", rootdir) == -1)
@@ -1129,7 +1203,7 @@ void fs_chroot(const char *rootdir) {
1129 fprintf(stderr, "Error: invalid %s file\n", fname); 1203 fprintf(stderr, "Error: invalid %s file\n", fname);
1130 exit(1); 1204 exit(1);
1131 } 1205 }
1132 if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) 1206 if (copy_file("/etc/resolv.conf", fname, 0, 0, 0644) == -1) // root needed
1133 fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n"); 1207 fprintf(stderr, "Warning: /etc/resolv.conf not initialized\n");
1134 } 1208 }
1135 1209
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index d710e98f2..bd9b9e828 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -28,6 +28,7 @@
28#ifndef _BSD_SOURCE 28#ifndef _BSD_SOURCE
29#define _BSD_SOURCE 29#define _BSD_SOURCE
30#endif 30#endif
31#include <sys/sysmacros.h>
31#include <sys/types.h> 32#include <sys/types.h>
32 33
33typedef struct { 34typedef struct {
@@ -51,7 +52,7 @@ static DevEntry dev[] = {
51 {"/dev/nvidia8", RUN_DEV_DIR "/nvidia8", 0, 1}, 52 {"/dev/nvidia8", RUN_DEV_DIR "/nvidia8", 0, 1},
52 {"/dev/nvidia9", RUN_DEV_DIR "/nvidia9", 0, 1}, 53 {"/dev/nvidia9", RUN_DEV_DIR "/nvidia9", 0, 1},
53 {"/dev/nvidiactl", RUN_DEV_DIR "/nvidiactl", 0, 1}, 54 {"/dev/nvidiactl", RUN_DEV_DIR "/nvidiactl", 0, 1},
54 {"/dev/nvidia-modset", RUN_DEV_DIR "/nvidia-modset", 0, 1}, 55 {"/dev/nvidia-modeset", RUN_DEV_DIR "/nvidia-modeset", 0, 1},
55 {"/dev/nvidia-uvm", RUN_DEV_DIR "/nvidia-uvm", 0, 1}, 56 {"/dev/nvidia-uvm", RUN_DEV_DIR "/nvidia-uvm", 0, 1},
56 {NULL, NULL, 0, 0} 57 {NULL, NULL, 0, 0}
57}; 58};
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index 479383af2..f14e90deb 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -31,8 +31,8 @@ void fs_machineid(void) {
31 uint32_t u32[4]; 31 uint32_t u32[4];
32 } mid; 32 } mid;
33 33
34 // if --machine-id flag is active, do nothing 34 // if --machine-id flag is inactive, do nothing
35 if (arg_machineid) 35 if (arg_machineid == 0)
36 return; 36 return;
37 37
38 // init random number generator 38 // init random number generator
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 4de082b06..8a52314ed 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -42,19 +42,17 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
42 // don't copy it if we already have the file 42 // don't copy it if we already have the file
43 if (stat(fname, &s) == 0) 43 if (stat(fname, &s) == 0)
44 return; 44 return;
45 if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat
46 fprintf(stderr, "Error: invalid %s file\n", fname);
47 exit(1);
48 }
45 if (stat("/etc/skel/.zshrc", &s) == 0) { 49 if (stat("/etc/skel/.zshrc", &s) == 0) {
46 if (copy_file("/etc/skel/.zshrc", fname, u, g, 0644) == 0) { 50 copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user
47 fs_logger("clone /etc/skel/.zshrc"); 51 fs_logger("clone /etc/skel/.zshrc");
48 }
49 } 52 }
50 else { // 53 else {
51 FILE *fp = fopen(fname, "w"); 54 touch_file_as_user(fname, u, g, 0644);
52 if (fp) { 55 fs_logger2("touch", fname);
53 fprintf(fp, "\n");
54 SET_PERMS_STREAM(fp, u, g, S_IRUSR | S_IWUSR);
55 fclose(fp);
56 fs_logger2("touch", fname);
57 }
58 } 56 }
59 free(fname); 57 free(fname);
60 } 58 }
@@ -64,23 +62,21 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
64 if (asprintf(&fname, "%s/.cshrc", homedir) == -1) 62 if (asprintf(&fname, "%s/.cshrc", homedir) == -1)
65 errExit("asprintf"); 63 errExit("asprintf");
66 struct stat s; 64 struct stat s;
65
67 // don't copy it if we already have the file 66 // don't copy it if we already have the file
68 if (stat(fname, &s) == 0) 67 if (stat(fname, &s) == 0)
69 return; 68 return;
69 if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat
70 fprintf(stderr, "Error: invalid %s file\n", fname);
71 exit(1);
72 }
70 if (stat("/etc/skel/.cshrc", &s) == 0) { 73 if (stat("/etc/skel/.cshrc", &s) == 0) {
71 if (copy_file("/etc/skel/.cshrc", fname, u, g, 0644) == 0) { 74 copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user
72 fs_logger("clone /etc/skel/.cshrc"); 75 fs_logger("clone /etc/skel/.cshrc");
73 }
74 } 76 }
75 else { // 77 else {
76 /* coverity[toctou] */ 78 touch_file_as_user(fname, u, g, 0644);
77 FILE *fp = fopen(fname, "w"); 79 fs_logger2("touch", fname);
78 if (fp) {
79 fprintf(fp, "\n");
80 SET_PERMS_STREAM(fp, u, g, S_IRUSR | S_IWUSR);
81 fclose(fp);
82 fs_logger2("touch", fname);
83 }
84 } 80 }
85 free(fname); 81 free(fname);
86 } 82 }
@@ -93,10 +89,13 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
93 // don't copy it if we already have the file 89 // don't copy it if we already have the file
94 if (stat(fname, &s) == 0) 90 if (stat(fname, &s) == 0)
95 return; 91 return;
92 if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat
93 fprintf(stderr, "Error: invalid %s file\n", fname);
94 exit(1);
95 }
96 if (stat("/etc/skel/.bashrc", &s) == 0) { 96 if (stat("/etc/skel/.bashrc", &s) == 0) {
97 if (copy_file("/etc/skel/.bashrc", fname, u, g, 0644) == 0) { 97 copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user
98 fs_logger("clone /etc/skel/.bashrc"); 98 fs_logger("clone /etc/skel/.bashrc");
99 }
100 } 99 }
101 free(fname); 100 free(fname);
102 } 101 }
@@ -106,7 +105,7 @@ static int store_xauthority(void) {
106 // put a copy of .Xauthority in XAUTHORITY_FILE 105 // put a copy of .Xauthority in XAUTHORITY_FILE
107 char *src; 106 char *src;
108 char *dest = RUN_XAUTHORITY_FILE; 107 char *dest = RUN_XAUTHORITY_FILE;
109 // create an empty file 108 // create an empty file as root, and change ownership to user
110 FILE *fp = fopen(dest, "w"); 109 FILE *fp = fopen(dest, "w");
111 if (fp) { 110 if (fp) {
112 fprintf(fp, "\n"); 111 fprintf(fp, "\n");
@@ -124,27 +123,8 @@ static int store_xauthority(void) {
124 return 0; 123 return 0;
125 } 124 }
126 125
127 pid_t child = fork(); 126 copy_file_as_user(src, dest, getuid(), getgid(), 0600); // regular user
128 if (child < 0) 127 fs_logger2("clone", dest);
129 errExit("fork");
130 if (child == 0) {
131 // drop privileges
132 drop_privs(0);
133
134 // copy, set permissions and ownership
135 int rv = copy_file(src, dest, getuid(), getgid(), 0600);
136 if (rv)
137 fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n");
138 else {
139 fs_logger2("clone", dest);
140 }
141#ifdef HAVE_GCOV
142 __gcov_flush();
143#endif
144 _exit(0);
145 }
146 // wait for the child to finish
147 waitpid(child, NULL, 0);
148 return 1; // file copied 128 return 1; // file copied
149 } 129 }
150 130
@@ -152,9 +132,10 @@ static int store_xauthority(void) {
152} 132}
153 133
154static int store_asoundrc(void) { 134static int store_asoundrc(void) {
135 // put a copy of .Xauthority in XAUTHORITY_FILE
155 char *src; 136 char *src;
156 char *dest = RUN_ASOUNDRC_FILE; 137 char *dest = RUN_ASOUNDRC_FILE;
157 // create an empty file 138 // create an empty file as root, and change ownership to user
158 FILE *fp = fopen(dest, "w"); 139 FILE *fp = fopen(dest, "w");
159 if (fp) { 140 if (fp) {
160 fprintf(fp, "\n"); 141 fprintf(fp, "\n");
@@ -182,27 +163,8 @@ static int store_asoundrc(void) {
182 free(rp); 163 free(rp);
183 } 164 }
184 165
185 pid_t child = fork(); 166 copy_file_as_user(src, dest, getuid(), getgid(), 0644); // regular user
186 if (child < 0) 167 fs_logger2("clone", dest);
187 errExit("fork");
188 if (child == 0) {
189 // drop privileges
190 drop_privs(0);
191
192 // copy, set permissions and ownership
193 int rv = copy_file(src, dest, getuid(), getgid(), 0644);
194 if (rv)
195 fprintf(stderr, "Warning: cannot transfer .asoundrc in private home directory\n");
196 else {
197 fs_logger2("clone", dest);
198 }
199#ifdef HAVE_GCOV
200 __gcov_flush();
201#endif
202 _exit(0);
203 }
204 // wait for the child to finish
205 waitpid(child, NULL, 0);
206 return 1; // file copied 168 return 1; // file copied
207 } 169 }
208 170
@@ -222,27 +184,8 @@ static void copy_xauthority(void) {
222 exit(1); 184 exit(1);
223 } 185 }
224 186
225 pid_t child = fork(); 187 copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user
226 if (child < 0) 188 fs_logger2("clone", dest);
227 errExit("fork");
228 if (child == 0) {
229 // drop privileges
230 drop_privs(0);
231
232 // copy, set permissions and ownership
233 int rv = copy_file(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR);
234 if (rv)
235 fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n");
236 else {
237 fs_logger2("clone", dest);
238 }
239#ifdef HAVE_GCOV
240 __gcov_flush();
241#endif
242 _exit(0);
243 }
244 // wait for the child to finish
245 waitpid(child, NULL, 0);
246 189
247 // delete the temporary file 190 // delete the temporary file
248 unlink(src); 191 unlink(src);
@@ -261,27 +204,8 @@ static void copy_asoundrc(void) {
261 exit(1); 204 exit(1);
262 } 205 }
263 206
264 pid_t child = fork(); 207 copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user
265 if (child < 0) 208 fs_logger2("clone", dest);
266 errExit("fork");
267 if (child == 0) {
268 // drop privileges
269 drop_privs(0);
270
271 // copy, set permissions and ownership
272 int rv = copy_file(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR);
273 if (rv)
274 fprintf(stderr, "Warning: cannot transfer .asoundrc in private home directory\n");
275 else {
276 fs_logger2("clone", dest);
277 }
278#ifdef HAVE_GCOV
279 __gcov_flush();
280#endif
281 _exit(0);
282 }
283 // wait for the child to finish
284 waitpid(child, NULL, 0);
285 209
286 // delete the temporary file 210 // delete the temporary file
287 unlink(src); 211 unlink(src);
diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c
index 5b6ceae90..d29f58a58 100644
--- a/src/firejail/fs_mkdir.c
+++ b/src/firejail/fs_mkdir.c
@@ -112,33 +112,8 @@ void fs_mkfile(const char *name) {
112 } 112 }
113 113
114 // create file 114 // create file
115 pid_t child = fork(); 115 touch_file_as_user(expanded, getuid(), getgid(), 0600);
116 if (child < 0) 116
117 errExit("fork");
118 if (child == 0) {
119 // drop privileges
120 drop_privs(0);
121
122 /* coverity[toctou] */
123 FILE *fp = fopen(expanded, "w");
124 if (!fp)
125 fprintf(stderr, "Warning: cannot create %s file\n", expanded);
126 else {
127 int fd = fileno(fp);
128 if (fd == -1)
129 errExit("fileno");
130 int rv = fchmod(fd, 0600);
131 (void) rv;
132 fclose(fp);
133 }
134#ifdef HAVE_GCOV
135 __gcov_flush();
136#endif
137 _exit(0);
138 }
139 // wait for the child to finish
140 waitpid(child, NULL, 0);
141
142doexit: 117doexit:
143 free(expanded); 118 free(expanded);
144} 119}
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index 77eb35f97..1af56751a 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -336,7 +336,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
336 drop_privs(0); 336 drop_privs(0);
337 337
338 // copy the file 338 // copy the file
339 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) 339 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) // already a regular user
340 _exit(1); 340 _exit(1);
341#ifdef HAVE_GCOV 341#ifdef HAVE_GCOV
342 __gcov_flush(); 342 __gcov_flush();
@@ -362,7 +362,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
362 drop_privs(0); 362 drop_privs(0);
363 363
364 // copy the file 364 // copy the file
365 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) 365 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) // already a regular user
366 _exit(1); 366 _exit(1);
367#ifdef HAVE_GCOV 367#ifdef HAVE_GCOV
368 __gcov_flush(); 368 __gcov_flush();
@@ -411,7 +411,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
411 drop_privs(0); 411 drop_privs(0);
412 412
413 // copy the file 413 // copy the file
414 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) 414 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) // already a regular user
415 _exit(1); 415 _exit(1);
416#ifdef HAVE_GCOV 416#ifdef HAVE_GCOV
417 __gcov_flush(); 417 __gcov_flush();
@@ -443,7 +443,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
443 drop_privs(0); 443 drop_privs(0);
444 444
445 // copy the file 445 // copy the file
446 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) 446 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) // already a regular user
447 _exit(1); 447 _exit(1);
448#ifdef HAVE_GCOV 448#ifdef HAVE_GCOV
449 __gcov_flush(); 449 __gcov_flush();
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 3a347b3d9..84bf5e8e6 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -1468,13 +1468,10 @@ int main(int argc, char **argv) {
1468 fprintf(stderr, "Error: invalid chroot directory\n"); 1468 fprintf(stderr, "Error: invalid chroot directory\n");
1469 exit(1); 1469 exit(1);
1470 } 1470 }
1471 free(rpath); 1471 cfg.chrootdir = rpath;
1472 1472
1473 // check chroot directory structure 1473 // check chroot directory structure
1474 if (fs_check_chroot_dir(cfg.chrootdir)) { 1474 fs_check_chroot_dir(cfg.chrootdir);
1475 fprintf(stderr, "Error: invalid chroot\n");
1476 exit(1);
1477 }
1478 } 1475 }
1479 else 1476 else
1480 exit_err_feature("chroot"); 1477 exit_err_feature("chroot");
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c
index d2db7d3dd..e17f39caa 100644
--- a/src/firejail/preproc.c
+++ b/src/firejail/preproc.c
@@ -76,12 +76,12 @@ void preproc_mount_mnt_dir(void) {
76 fs_logger2("tmpfs", RUN_MNT_DIR); 76 fs_logger2("tmpfs", RUN_MNT_DIR);
77 77
78 //copy defaultl seccomp files 78 //copy defaultl seccomp files
79 copy_file(PATH_SECCOMP_I386, RUN_SECCOMP_I386, getuid(), getgid(), 0644); 79 copy_file(PATH_SECCOMP_I386, RUN_SECCOMP_I386, getuid(), getgid(), 0644); // root needed
80 copy_file(PATH_SECCOMP_AMD64, RUN_SECCOMP_AMD64, getuid(), getgid(), 0644); 80 copy_file(PATH_SECCOMP_AMD64, RUN_SECCOMP_AMD64, getuid(), getgid(), 0644); // root needed
81 if (arg_allow_debuggers) 81 if (arg_allow_debuggers)
82 copy_file(PATH_SECCOMP_DEFAULT_DEBUG, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); 82 copy_file(PATH_SECCOMP_DEFAULT_DEBUG, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed
83 else 83 else
84 copy_file(PATH_SECCOMP_DEFAULT, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); 84 copy_file(PATH_SECCOMP_DEFAULT, RUN_SECCOMP_CFG, getuid(), getgid(), 0644); // root needed
85 85
86 // as root, create an empty RUN_SECCOMP_PROTOCOL file 86 // as root, create an empty RUN_SECCOMP_PROTOCOL file
87 create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644); 87 create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644);
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index fab4f1efa..33b6eab91 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -1017,6 +1017,11 @@ void profile_read(const char *fname) {
1017 // open profile file: 1017 // open profile file:
1018 FILE *fp = fopen(fname, "r"); 1018 FILE *fp = fopen(fname, "r");
1019 if (fp == NULL) { 1019 if (fp == NULL) {
1020 // if the file ends in ".local", do not exit
1021 char *ptr = strstr(fname, ".local");
1022 if (ptr && strlen(ptr) == 6)
1023 return;
1024
1020 fprintf(stderr, "Error: cannot open profile file %s\n", fname); 1025 fprintf(stderr, "Error: cannot open profile file %s\n", fname);
1021 exit(1); 1026 exit(1);
1022 } 1027 }
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index 14a7f03dd..4ec84ec61 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -22,6 +22,7 @@
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <sys/mount.h> 23#include <sys/mount.h>
24#include <dirent.h> 24#include <dirent.h>
25#include <sys/wait.h>
25 26
26static void disable_file(const char *path, const char *file) { 27static void disable_file(const char *path, const char *file) {
27 assert(file); 28 assert(file);
@@ -113,7 +114,7 @@ void pulseaudio_init(void) {
113 char *pulsecfg = NULL; 114 char *pulsecfg = NULL;
114 if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1) 115 if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1)
115 errExit("asprintf"); 116 errExit("asprintf");
116 if (copy_file("/etc/pulse/client.conf", pulsecfg, -1, -1, 0644)) 117 if (copy_file("/etc/pulse/client.conf", pulsecfg, -1, -1, 0644)) // root needed
117 errExit("copy_file"); 118 errExit("copy_file");
118 FILE *fp = fopen(pulsecfg, "a+"); 119 FILE *fp = fopen(pulsecfg, "a+");
119 if (!fp) 120 if (!fp)
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 5b94aa288..10000e912 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -28,6 +28,7 @@
28#include <grp.h> 28#include <grp.h>
29#include <sys/ioctl.h> 29#include <sys/ioctl.h>
30#include <termios.h> 30#include <termios.h>
31#include <sys/wait.h>
31 32
32#define MAX_GROUPS 1024 33#define MAX_GROUPS 1024
33// drop privileges 34// drop privileges
@@ -218,6 +219,51 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m
218 return 0; 219 return 0;
219} 220}
220 221
222// return -1 if error, 0 if no error
223void copy_file_as_user(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) {
224 pid_t child = fork();
225 if (child < 0)
226 errExit("fork");
227 if (child == 0) {
228 // drop privileges
229 drop_privs(0);
230
231 // copy, set permissions and ownership
232 int rv = copy_file(srcname, destname, uid, gid, mode); // already a regular user
233 if (rv)
234 fprintf(stderr, "Warning: cannot copy %s\n", srcname);
235#ifdef HAVE_GCOV
236 __gcov_flush();
237#endif
238 _exit(0);
239 }
240 // wait for the child to finish
241 waitpid(child, NULL, 0);
242}
243
244// return -1 if error, 0 if no error
245void touch_file_as_user(const char *fname, uid_t uid, gid_t gid, mode_t mode) {
246 pid_t child = fork();
247 if (child < 0)
248 errExit("fork");
249 if (child == 0) {
250 // drop privileges
251 drop_privs(0);
252
253 FILE *fp = fopen(fname, "w");
254 if (fp) {
255 fprintf(fp, "\n");
256 SET_PERMS_STREAM(fp, uid, gid, mode);
257 fclose(fp);
258 }
259#ifdef HAVE_GCOV
260 __gcov_flush();
261#endif
262 _exit(0);
263 }
264 // wait for the child to finish
265 waitpid(child, NULL, 0);
266}
221 267
222// return 1 if the file is a directory 268// return 1 if the file is a directory
223int is_dir(const char *fname) { 269int is_dir(const char *fname) {
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 91017237d..4e0b46fb8 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -653,11 +653,7 @@ void x11_xorg(void) {
653 struct stat s; 653 struct stat s;
654 if (stat(dest, &s) == -1) { 654 if (stat(dest, &s) == -1) {
655 // create an .Xauthority file 655 // create an .Xauthority file
656 FILE *fp = fopen(dest, "w"); 656 touch_file_as_user(dest, getuid(), getgid(), 0600);
657 if (!fp)
658 errExit("fopen");
659 SET_PERMS_STREAM(fp, getuid(), getgid(), 0600);
660 fclose(fp);
661 } 657 }
662 658
663 // check xauth utility is present in the system 659 // check xauth utility is present in the system
@@ -666,6 +662,10 @@ void x11_xorg(void) {
666 exit(1); 662 exit(1);
667 } 663 }
668 664
665 // temporarily mount a tempfs on top of /tmp directory
666 if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0)
667 errExit("mounting /tmp");
668
669 // create a temporary .Xauthority file 669 // create a temporary .Xauthority file
670 char tmpfname[] = "/tmp/.tmpXauth-XXXXXX"; 670 char tmpfname[] = "/tmp/.tmpXauth-XXXXXX";
671 int fd = mkstemp(tmpfname); 671 int fd = mkstemp(tmpfname);
@@ -673,9 +673,9 @@ void x11_xorg(void) {
673 fprintf(stderr, "Error: cannot create .Xauthority file\n"); 673 fprintf(stderr, "Error: cannot create .Xauthority file\n");
674 exit(1); 674 exit(1);
675 } 675 }
676 close(fd); 676 if (fchown(fd, getuid(), getgid()) == -1)
677 if (chown(tmpfname, getuid(), getgid()) == -1)
678 errExit("chown"); 677 errExit("chown");
678 close(fd);
679 679
680 pid_t child = fork(); 680 pid_t child = fork();
681 if (child < 0) 681 if (child < 0)
@@ -713,7 +713,7 @@ void x11_xorg(void) {
713 713
714 // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted 714 // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted
715 // automatically when the sandbox is closed 715 // automatically when the sandbox is closed
716 if (copy_file(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600)) { 716 if (copy_file(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600)) { // root needed
717 fprintf(stderr, "Error: cannot create the new .Xauthority file\n"); 717 fprintf(stderr, "Error: cannot create the new .Xauthority file\n");
718 exit(1); 718 exit(1);
719 } 719 }
@@ -730,5 +730,8 @@ void x11_xorg(void) {
730 if (set_perms(dest, getuid(), getgid(), 0600)) 730 if (set_perms(dest, getuid(), getgid(), 0600))
731 errExit("set_perms"); 731 errExit("set_perms");
732 free(dest); 732 free(dest);
733
734 // unmount /tmp
735 umount("/tmp");
733#endif 736#endif
734} 737}
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index fa522c154..ecb8be139 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -86,6 +86,10 @@ file in user home directory.
86 86
87Example: "include ${HOME}/myprofiles/profile1" will load "~/myprofiles/profile1" file. 87Example: "include ${HOME}/myprofiles/profile1" will load "~/myprofiles/profile1" file.
88 88
89If the file is not found, and the file name does not end in ".local", the sandbox exist immediately
90with an error printed on stderr. ".local" files can be used to customize the global configuration
91in /etc/firejail directory. These files are not overwritten during software install.
92
89.TP 93.TP
90\fBnoblacklist file_name 94\fBnoblacklist file_name
91If the file name matches file_name, the file will not be blacklisted in any blacklist commands that follow. 95If the file name matches file_name, the file will not be blacklisted in any blacklist commands that follow.
@@ -448,7 +452,7 @@ Assign MAC addresses to the last network interface defined by a net command.
448 452
449.TP 453.TP
450\fBmachine-id 454\fBmachine-id
451Preserve id number in /etc/machine-id file. By default a new random id is generated inside the sandbox. 455Spoof id number in /etc/machine-id file - a new random id is generated inside the sandbox.
452 456
453.TP 457.TP
454\fBmtu number 458\fBmtu number
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 69d28c788..69ed2a8dc 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -678,7 +678,7 @@ $ firejail \-\-net=eth0 \-\-mac=00:11:22:33:44:55 firefox
678 678
679.TP 679.TP
680\fB\-\-machine-id 680\fB\-\-machine-id
681Preserve id number in /etc/machine-id file. By default a new random id is generated inside the sandbox. 681Spoof id number in /etc/machine-id file - a new random id is generated inside the sandbox.
682.br 682.br
683 683
684.br 684.br