summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in6
-rw-r--r--README14
-rw-r--r--README.md2
-rw-r--r--RELNOTES25
-rwxr-xr-xcontrib/fix_private-bin.py157
-rw-r--r--contrib/fix_private-bin_for_symlinked_sh.py68
-rwxr-xr-xcontrib/fjclip.py35
-rwxr-xr-xcontrib/fjdisplay.py43
-rwxr-xr-xcontrib/fjresize.py25
-rw-r--r--etc/Cryptocat.profile2
-rw-r--r--etc/FossaMail.profile2
-rw-r--r--etc/disable-common.inc6
-rw-r--r--etc/disable-devel.inc3
-rw-r--r--etc/disable-passwdmgr.inc3
-rw-r--r--etc/disable-programs.inc3
-rw-r--r--etc/evolution.profile3
-rw-r--r--etc/fossamail.profile15
-rw-r--r--etc/gpa.profile2
-rw-r--r--etc/gpg-agent.profile4
-rw-r--r--etc/gpg.profile5
-rw-r--r--etc/uzbl-browser.profile27
-rw-r--r--etc/whitelist-common.inc3
-rw-r--r--platform/debian/conffiles2
-rw-r--r--src/fcopy/main.c2
-rw-r--r--src/firecfg/firecfg.config2
-rw-r--r--src/firejail/bandwidth.c9
-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.c112
-rw-r--r--src/firejail/fs_mkdir.c29
-rw-r--r--src/firejail/ls.c8
-rw-r--r--src/firejail/main.c29
-rw-r--r--src/firejail/preproc.c8
-rw-r--r--src/firejail/profile.c5
-rw-r--r--src/firejail/pulseaudio.c63
-rw-r--r--src/firejail/sandbox.c11
-rw-r--r--src/firejail/util.c50
-rw-r--r--src/firejail/x11.c19
-rw-r--r--src/man/firejail-profile.txt6
-rw-r--r--src/man/firejail.txt6
42 files changed, 695 insertions, 248 deletions
diff --git a/Makefile.in b/Makefile.in
index 8251f9882..fb6460dfd 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -91,6 +91,10 @@ realinstall:
91 install -c -m 0644 seccomp.debug $(DESTDIR)/$(libdir)/firejail/. 91 install -c -m 0644 seccomp.debug $(DESTDIR)/$(libdir)/firejail/.
92 install -c -m 0644 seccomp.i386 $(DESTDIR)/$(libdir)/firejail/. 92 install -c -m 0644 seccomp.i386 $(DESTDIR)/$(libdir)/firejail/.
93 install -c -m 0644 seccomp.amd64 $(DESTDIR)/$(libdir)/firejail/. 93 install -c -m 0644 seccomp.amd64 $(DESTDIR)/$(libdir)/firejail/.
94 install -c -m 0755 contrib/fix_private-bin.py $(DESTDIR)/$(libdir)/firejail/.
95 install -c -m 0755 contrib/fjclip.py $(DESTDIR)/$(libdir)/firejail/.
96 install -c -m 0755 contrib/fjdisplay.py $(DESTDIR)/$(libdir)/firejail/.
97 install -c -m 0755 contrib/fjresize.py $(DESTDIR)/$(libdir)/firejail/.
94 # documents 98 # documents
95 install -m 0755 -d $(DESTDIR)/$(DOCDIR) 99 install -m 0755 -d $(DESTDIR)/$(DOCDIR)
96 install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/. 100 install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/.
@@ -158,7 +162,7 @@ uninstall:
158 rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firemon 162 rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firemon
159 rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firecfg 163 rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firecfg
160 164
161DISTFILES = "src etc platform configure configure.ac Makefile.in install.sh mkman.sh mketc.sh mkdeb.sh mkuid.sh COPYING README RELNOTES" 165DISTFILES = "src etc platform contrib configure configure.ac Makefile.in install.sh mkman.sh mketc.sh mkdeb.sh mkuid.sh COPYING README RELNOTES"
162DISTFILES_TEST = "test/apps test/apps-x11 test/apps-x11-xorg test/root test/fcopy test/environment test/profiles test/utils test/compile test/filters test/network test/arguments test/fs test/sysutils" 166DISTFILES_TEST = "test/apps test/apps-x11 test/apps-x11-xorg test/root test/fcopy test/environment test/profiles test/utils test/compile test/filters test/network test/arguments test/fs test/sysutils"
163 167
164dist: 168dist:
diff --git a/README b/README
index 751480868..67d9a555f 100644
--- a/README
+++ b/README
@@ -97,6 +97,14 @@ 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
104Pixel Fairy (https://github.com/xahare)
105 - added fjclip.py, fjdisplay.py and fjresize.py in contrib section
106pshpsh (https://github.com/pshpsh)
107 - added FossaMail profile
100eventyrer (https://github.com/eventyrer) 108eventyrer (https://github.com/eventyrer)
101 - update gnome-mplayer.profile 109 - update gnome-mplayer.profile
102thewisenerd (https://github.com/thewisenerd) 110thewisenerd (https://github.com/thewisenerd)
@@ -104,10 +112,11 @@ thewisenerd (https://github.com/thewisenerd)
104 - use $SHELL variable if the shell is not specified 112 - use $SHELL variable if the shell is not specified
105SYN-cook (https://github.com/SYN-cook) 113SYN-cook (https://github.com/SYN-cook)
106 - keepass/keepassx browser fixes 114 - keepass/keepassx browser fixes
115 - disable-common.inc fixes
107thewisenerd (https://github.com/thewisenerd) 116thewisenerd (https://github.com/thewisenerd)
108 - appimage: pass commandline arguments 117 - appimage: pass commandline arguments
109KOLANICH (https://github.com/KOLANICH) 118KOLANICH (https://github.com/KOLANICH)
110 - added symlink fixer 119 - added symlink fixer fix_private-bin.py in contrib section
111Jesse Smith (https://github.com/slicer69) 120Jesse Smith (https://github.com/slicer69)
112 - added QupZilla profile 121 - added QupZilla profile
113Lari Rauno (https://github.com/tuutti) 122Lari Rauno (https://github.com/tuutti)
@@ -213,6 +222,8 @@ KellerFuchs (https://github.com/KellerFuchs)
213 - nonewpriv support, extended profiles for this feature 222 - nonewpriv support, extended profiles for this feature
214 - make `restricted-network` prevent use of netfilter 223 - make `restricted-network` prevent use of netfilter
215 - 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
216ValdikSS (https://github.com/ValdikSS) 227ValdikSS (https://github.com/ValdikSS)
217 - Psi+, Corebird, Konversation profiles 228 - Psi+, Corebird, Konversation profiles
218 - various profile fixes 229 - various profile fixes
@@ -292,6 +303,7 @@ Ivan Kozik (https://github.com/ivan)
292 - speed up sandbox exit 303 - speed up sandbox exit
293Christian Stadelmann (https://github.com/genodeftest) 304Christian Stadelmann (https://github.com/genodeftest)
294 - profile fixes 305 - profile fixes
306 - evolution profile fix
295pirate486743186 (https://github.com/pirate486743186) 307pirate486743186 (https://github.com/pirate486743186)
296 - KMail profile 308 - KMail profile
297Kaan Genç (https://github.com/SeriousBug) 309Kaan Genç (https://github.com/SeriousBug)
diff --git a/README.md b/README.md
index 9057a9a88..f4fa7282f 100644
--- a/README.md
+++ b/README.md
@@ -98,5 +98,5 @@ gjs, gnome-books, gnome-clocks, gnome-documents, gnome-maps, gnome-music, gnome-
98goobox, gpa, gpg, gpg-agent, highlight, img2txt, k3b, kate, lynx, mediainfo, nautilus, odt2txt, pdftotext, 98goobox, gpa, gpg, gpg-agent, highlight, img2txt, k3b, kate, lynx, mediainfo, nautilus, odt2txt, pdftotext,
99simple-scan, skanlite, ssh-agent, tracker, transmission-cli, transmission-show, w3m, xfburn, xpra, wget, 99simple-scan, skanlite, ssh-agent, tracker, transmission-cli, transmission-show, w3m, xfburn, xpra, wget,
100xed, pluma, Cryptocat, Bless, Gnome 2048, Gnome Calculator, Gnome Contacts, JD-GUI, Lollypop, MultiMC5, 100xed, pluma, Cryptocat, Bless, Gnome 2048, Gnome Calculator, Gnome Contacts, JD-GUI, Lollypop, MultiMC5,
101PDFSam, Pithos, Xonotic, wireshark, keepassx2, QupZilla 101PDFSam, Pithos, Xonotic, wireshark, keepassx2, QupZilla, FossaMail
102 102
diff --git a/RELNOTES b/RELNOTES
index 2d57b1a88..7d0bbaf61 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,11 +1,18 @@
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 * security: overwrite /etc/resolv.conf found by Martin Carpenter 3 * Gentoo compile patch
4 * secuirty: TOCTOU exploit for --get and --put found by Daniel Hodson 4 * security: --bandwidth root shell found by Martin Carpenter (CVE-2017-5207)
5 * security: invalid environment exploit found by Martin Carpenter 5 * security: disabled --allow-debuggers when running on kernel
6 versions prior to 4.8; a kernel bug in ptrace system call
7 allows a full bypass of seccomp filter; problem reported by Lizzie Dixon
8 (CVE-2017-5206)
9 * security: overwrite /etc/resolv.conf found by Martin Carpenter (CVE-2016-10118)
10 * security: TOCTOU exploit for --get and --put found by Daniel Hodson
11 * security: invalid environment exploit found by Martin Carpenter (CVE-2016-10122)
6 * security: split most of networking code in a separate executable 12 * security: split most of networking code in a separate executable
7 * security: split seccomp filter code configuration in a separate executable 13 * security: split seccomp filter code configuration in a separate executable
8 * security: split file copying in private option in a separate executable 14 * security: split file copying in private option in a separate executable
15 * security: root exploit found by Sebastian Krahmer (CVE-2017-5180)
9 * feature: disable gnupg and systemd directories under /run/user 16 * feature: disable gnupg and systemd directories under /run/user
10 * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm) 17 * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm)
11 * feature: AppImage type 2 support 18 * feature: AppImage type 2 support
@@ -16,16 +23,19 @@ firejail (0.9.45) baseline; urgency=low
16 * feature: config support for firejail prompt in terminals 23 * feature: config support for firejail prompt in terminals
17 * feature: pass command line arguments to appimages 24 * feature: pass command line arguments to appimages
18 * feature: --allow-private-blacklist option 25 * feature: --allow-private-blacklist option
26 * feature: allow non-seccomp setup for OverlayFS sandboxes
27 * feature: added a number o Python scripts for handling sandboxes
28 * feature: allow local customization using .local files under /etc/firejail
19 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire, 29 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire,
20 * new profiles: mumble, zoom, Guayadeque, qemu, keypass2, xed, pluma, 30 * new profiles: mumble, zoom, Guayadeque, qemu, keypass2, xed, pluma,
21 * new profiles: Cryptocat, Bless, Gnome 2048, Gnome Calculator, 31 * new profiles: Cryptocat, Bless, Gnome 2048, Gnome Calculator,
22 * new profiles: Gnome Contacts, JD-GUI, Lollypop, MultiMC5, PDFSam, Pithos, 32 * new profiles: Gnome Contacts, JD-GUI, Lollypop, MultiMC5, PDFSam, Pithos,
23 * new profies: Xonotic, wireshark, keepassx2, QupZilla 33 * new profies: Xonotic, wireshark, keepassx2, QupZilla, FossaMail
24 * bugfixes 34 * bugfixes
25 -- netblue30 <netblue30@yahoo.com> Sun, 23 Oct 2016 08:00:00 -0500 35 -- netblue30 <netblue30@yahoo.com> Sun, 23 Oct 2016 08:00:00 -0500
26 36
27firejail (0.9.44) baseline; urgency=low 37firejail (0.9.44) baseline; urgency=low
28 * CVE-2016-7545 submitted by Aleksey Manevich 38 * CVE-2016-9016 submitted by Aleksey Manevich
29 * modifs: removed man firejail-config 39 * modifs: removed man firejail-config
30 * modifs: --private-tmp whitelists /tmp/.X11-unix directory 40 * modifs: --private-tmp whitelists /tmp/.X11-unix directory
31 * modifs: Nvidia drivers added to --private-dev 41 * modifs: Nvidia drivers added to --private-dev
@@ -142,11 +152,12 @@ firejail (0.9.38) baseline; urgency=low
142 * added KMail, Seamonkey, Telegram, Mathematica, uGet, 152 * added KMail, Seamonkey, Telegram, Mathematica, uGet,
143 * and mupen64plus profiles 153 * and mupen64plus profiles
144 * --chroot in user mode allowed only if seccomp support is available 154 * --chroot in user mode allowed only if seccomp support is available
145 * in current Linux kernel 155 * in current Linux kernel (CVE-2016-10123)
146 * deprecated --private-home feature 156 * deprecated --private-home feature
147 * the first protocol list installed takes precedence 157 * the first protocol list installed takes precedence
148 * --tmpfs option allowed only running as root 158 * --tmpfs option allowed only running as root (CVE-2016-10117)
149 * added --private-tmp option 159 * added --private-tmp option
160 * weak permissions (CVE-2016-10119, CVE-2016-10120, CVE-2016-10121)
150 * bugfixes 161 * bugfixes
151 -- netblue30 <netblue30@yahoo.com> Tue, 2 Feb 2016 10:00:00 -0500 162 -- netblue30 <netblue30@yahoo.com> Tue, 2 Feb 2016 10:00:00 -0500
152 163
diff --git a/contrib/fix_private-bin.py b/contrib/fix_private-bin.py
new file mode 100755
index 000000000..270c758a2
--- /dev/null
+++ b/contrib/fix_private-bin.py
@@ -0,0 +1,157 @@
1#!/usr/bin/python3
2
3__author__ = "KOLANICH"
4__copyright__ = """This is free and unencumbered software released into the public domain.
5
6Anyone is free to copy, modify, publish, use, compile, sell, or
7distribute this software, either in source code form or as a compiled
8binary, for any purpose, commercial or non-commercial, and by any
9means.
10
11In jurisdictions that recognize copyright laws, the author or authors
12of this software dedicate any and all copyright interest in the
13software to the public domain. We make this dedication for the benefit
14of the public at large and to the detriment of our heirs and
15successors. We intend this dedication to be an overt act of
16relinquishment in perpetuity of all present and future rights to this
17software under copyright law.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25OTHER DEALINGS IN THE SOFTWARE.
26
27For more information, please refer to <http://unlicense.org/>"""
28__license__ = "Unlicense"
29
30import sys, os, glob, re
31
32privRx=re.compile("^(?:#\s*)?private-bin")
33
34def fixSymlinkedBins(files, replMap):
35 """
36 Used to add filenames to private-bin directives of files if the ones present are mentioned in replMap
37 replMap is a dict where key is the marker filename and value is the filename to add
38 """
39
40 rxs=dict()
41 for (old,new) in replMap.items():
42 rxs[old]=re.compile("\\b"+old+"\\b")
43 rxs[new]=re.compile("\\b"+new+"\\b")
44 #print(rxs)
45
46 for filename in files:
47 lines=None
48 with open(filename,"r") as file:
49 lines=file.readlines()
50
51 shouldUpdate=False
52 for (i,line) in enumerate(lines):
53 if privRx.search(line):
54 for (old,new) in replMap.items():
55 if rxs[old].search(line) and not rxs[new].search(line):
56 lines[i]=rxs[old].sub(old+","+new, line)
57 shouldUpdate=True
58 print(lines[i])
59
60 if shouldUpdate:
61 with open(filename,"w") as file:
62 file.writelines(lines)
63 pass
64
65def createSetOfBinaries(files):
66 """
67 Creates a set of binaries mentioned in private-bin directives of files.
68 """
69 s=set()
70 for filename in files:
71 lines=None
72 with open(filename,"r") as file:
73 for line in file:
74 if privRx.search(line):
75 bins=line.split(",")
76 bins[0]=bins[0].split(" ")[-1]
77 bins = [n.strip() for n in bins]
78 s=s|set(bins)
79 return s
80
81def createSymlinkTable(binDirs, binariesSet):
82 """
83 creates a dict of symlinked binaries in the system where a key is a symlink name and value is a symlinked binary.
84 binDirs are folders to look into for binaries symlinks
85 binariesSet is a set of binaries to be checked if they are actually a symlinks
86 """
87 m=dict()
88 toProcess=binariesSet
89 while len(toProcess)!=0:
90 additional=set()
91 for sh in toProcess:
92 for bD in binDirs:
93 p=bD+os.path.sep+sh
94 if os.path.exists(p):
95 if os.path.islink(p):
96 m[sh]=os.readlink(p)
97 additional.add(m[sh].split(" ")[0])
98 else:
99 pass
100 break
101 toProcess=additional
102 return m
103
104def doTheFixes(profilesPath, binDirs):
105 """
106 Fixes private-bin in .profiles for firejail. The pipeline is as follows:
107 discover files -> discover mentioned binaries ->
108 discover the ones which are symlinks ->
109 make a look-up table for fix ->
110 filter the ones can be fixed (we cannot fix the ones which are not in directories for binaries) ->
111 apply fix
112 """
113 files=glob.glob(profilesPath+os.path.sep+"*.profile")
114 bins=createSetOfBinaries(files)
115 #print("The binaries used are:")
116 #print(bins)
117 stbl=createSymlinkTable(binDirs,bins)
118 print("The replacement table is:")
119 print(stbl)
120 stbl={a[0]:a[1] for a in stbl.items() if a[0].find(os.path.sep) < 0 and a[1].find(os.path.sep)<0}
121 print("Filtered replacement table is:")
122 print(stbl)
123 fixSymlinkedBins(files,stbl)
124
125def printHelp():
126 print("python3 "+os.path.basename(__file__)+" <dir with .profile files>\nThe default dir is "+defaultProfilesPath+"\n"+doTheFixes.__doc__)
127
128def main():
129 """The main function. Parses the commandline args, shows messages and calles the function actually doing the work."""
130 print(repr(sys.argv))
131 defaultProfilesPath="../etc"
132 if len(sys.argv)>2 or (len(sys.argv)==2 and (sys.argv[1] == '-h' or sys.argv[1] == '--help') ):
133 printHelp()
134 exit(1)
135
136 profilesPath=None
137 if len(sys.argv)==2:
138 if os.path.isdir(sys.argv[1]):
139 profilesPath=os.path.abspath(sys.argv[1])
140 else:
141 if os.path.exists(sys.argv[1]):
142 print(sys.argv[1]+" is not a dir")
143 else:
144 print(sys.argv[1]+" does not exist")
145 printHelp()
146 exit(1)
147 else:
148 print("Using default profiles dir: " + defaultProfilesPath)
149 profilesPath=defaultProfilesPath
150
151 binDirs=["/bin","/usr/bin","/usr/sbin","/usr/local/bin","/usr/local/sbin"]
152 print("Binaries dirs are:")
153 print(binDirs)
154 doTheFixes(profilesPath, binDirs)
155
156if __name__ == "__main__":
157 main()
diff --git a/contrib/fix_private-bin_for_symlinked_sh.py b/contrib/fix_private-bin_for_symlinked_sh.py
deleted file mode 100644
index 705e46e46..000000000
--- a/contrib/fix_private-bin_for_symlinked_sh.py
+++ /dev/null
@@ -1,68 +0,0 @@
1#!/usr/bin/python3
2
3import sys, os, glob, re
4
5privRx=re.compile("^(?:#\s*)?private-bin")
6
7def fixSymlinkedBins(files, replMap):
8 rxs=dict()
9 for (old,new) in replMap.items():
10 rxs[old]=re.compile("\\b"+old+"\\b")
11 rxs[new]=re.compile("\\b"+new+"\\b")
12 print(rxs)
13
14 for filename in files:
15 lines=None
16 with open(filename,"r") as file:
17 lines=file.readlines()
18
19 shouldUpdate=False
20 for (i,line) in enumerate(lines):
21 if privRx.search(line):
22 for (old,new) in replMap.items():
23 if rxs[old].search(line) and not rxs[new].search(line):
24 lines[i]=rxs[old].sub(old+","+new, line)
25 shouldUpdate=True
26 print(lines[i])
27
28 if shouldUpdate:
29 with open(filename,"w") as file:
30 file.writelines(lines)
31 pass
32
33def createListOfBinaries(files):
34 s=set()
35 for filename in files:
36 lines=None
37 with open(filename,"r") as file:
38 for line in file:
39 if privRx.search(line):
40 bins=line.split(",")
41 bins[0]=bins[0].split(" ")[-1]
42 bins = [n.strip() for n in bins]
43 s=s|set(bins)
44 return s
45
46def createSymlinkTable(binDirs, binariesSet):
47 m=dict()
48 for sh in binariesSet:
49 for bD in binDirs:
50 p=bD+os.path.sep+sh
51 if os.path.exists(p):
52 if os.path.islink(p):
53 m[sh]=os.readlink(p)
54 else:
55 pass
56 break
57 return m
58
59
60sh="sh"
61binDirs=["/bin","/usr/bin","/usr/sbin","/usr/local/bin","/usr/local/sbin"]
62profilesPath="."
63files=glob.glob(profilesPath+os.path.sep+"*.profile")
64
65bins=createListOfBinaries(files)
66stbl=createSymlinkTable(binDirs,bins)
67print(stbl)
68fixSymlinkedBins(files,{a[0]:a[1] for a in stbl.items() if a[0].find("/") < 0 and a[1].find("/")<0})
diff --git a/contrib/fjclip.py b/contrib/fjclip.py
new file mode 100755
index 000000000..cd12cd289
--- /dev/null
+++ b/contrib/fjclip.py
@@ -0,0 +1,35 @@
1#!/usr/bin/env python
2
3import re
4import sys
5import subprocess
6import fjdisplay
7
8usage = """fjclip.py src dest. src or dest can be named firejails or - for stdin or stdout.
9firemon --x11 to see available running x11 firejails. firejail names can be shortened
10to least ambiguous. for example 'work-libreoffice' can be shortened to 'work' if no
11other firejails name starts with 'work'.
12warning: browsers are dangerous. clipboards from browsers are dangerous. see
13https://github.com/dxa4481/Pastejacking
14fjclip.py strips whitespace from both
15ends, but does nothing else to protect you. use a simple gui text editor like
16gedit if you want to see what your pasting."""
17
18if len(sys.argv) != 3 or sys.argv == '-h' or sys.argv == '--help':
19 print(usage)
20 exit(1)
21
22if sys.argv[1] == '-':
23 clipin_raw = sys.stdin.read()
24else:
25 display = fjdisplay.getdisplay(sys.argv[1])
26 clipin_raw = subprocess.check_output(['xsel','-b','--display',display])
27
28clipin = clipin_raw.strip()
29
30if sys.argv[2] == '-':
31 print(clipin)
32else:
33 display = fjdisplay.getdisplay(sys.argv[2])
34 clipout = subprocess.Popen(['xsel','-b','-i','--display',display],stdin=subprocess.PIPE)
35 clipout.communicate(clipin) \ No newline at end of file
diff --git a/contrib/fjdisplay.py b/contrib/fjdisplay.py
new file mode 100755
index 000000000..0e0ef01ec
--- /dev/null
+++ b/contrib/fjdisplay.py
@@ -0,0 +1,43 @@
1#!/usr/bin/env python
2
3import re
4import sys
5import subprocess
6
7usage = """fjdisplay.py name-of-firejail
8returns the display in the form of ':NNN'
9"""
10
11def getfirejails():
12 output = subprocess.check_output(['firemon','--x11'])
13 firejails = {}
14 name = ''
15 for line in output.split('\n'):
16 namematch = re.search('--name=(\w+\S*)',line)
17 if namematch:
18 name = namematch.group(1)
19 displaymatch = re.search('DISPLAY (:\d+)',line)
20 if displaymatch:
21 firejails[name] = displaymatch.group(1)
22 return firejails
23
24def getdisplay(name):
25 firejails = getfirejails()
26 fjlist = '\n'.join(firejails.keys())
27 namere = re.compile('^'+name+'.*', re.MULTILINE)
28 matchingjails = namere.findall(fjlist)
29 if len(matchingjails) == 1:
30 return firejails[matchingjails[0]]
31 if len(matchingjails) == 0:
32 raise NameError("firejail {} does not exist".format(name))
33 else:
34 raise NameError("ambiguous firejail name")
35
36if __name__ == '__main__':
37 if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) > 2:
38 print(usage)
39 exit()
40 if len(sys.argv) == 1:
41 print(getfirejails())
42 if len(sys.argv) == 2:
43 print (getdisplay(sys.argv[1])) \ No newline at end of file
diff --git a/contrib/fjresize.py b/contrib/fjresize.py
new file mode 100755
index 000000000..52b289159
--- /dev/null
+++ b/contrib/fjresize.py
@@ -0,0 +1,25 @@
1#!/usr/bin/env python
2
3import sys
4import fjdisplay
5import subprocess
6
7usage = """usage: fjresize.py firejail-name displaysize
8resize firejail xephyr windows.
9fjdisplay.py with no other arguments will list running named firejails with displays.
10fjresize.py with only a firejail name will list valid resolutions.
11names can be shortend as long its unambiguous.
12note: you may need to move the xephyr window for the resize to take effect
13example:
14 fjresize.py browser 1280x800
15"""
16
17
18if len(sys.argv) == 2:
19 out = subprocess.check_output(['xrandr','--display',fjdisplay.getdisplay(sys.argv[1])])
20 print(out)
21elif len(sys.argv) == 3:
22 out = subprocess.check_output(['xrandr','--display',fjdisplay.getdisplay(sys.argv[1]),'--output','default','--mode',sys.argv[2]])
23 print(out)
24else:
25 print(usage) \ No newline at end of file
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/FossaMail.profile b/etc/FossaMail.profile
new file mode 100644
index 000000000..0da235467
--- /dev/null
+++ b/etc/FossaMail.profile
@@ -0,0 +1,2 @@
1# Firejail profile for FossaMail
2include /etc/firejail/fossamail.profile
diff --git a/etc/disable-common.inc b/etc/disable-common.inc
index 22f54604a..6f21b9681 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
@@ -102,6 +105,9 @@ read-only ${HOME}/.caffrc
102read-only ${HOME}/.dotfiles 105read-only ${HOME}/.dotfiles
103read-only ${HOME}/dotfiles 106read-only ${HOME}/dotfiles
104read-only ${HOME}/.mailcap 107read-only ${HOME}/.mailcap
108read-only ${HOME}/.muttrc
109read-only ${HOME}/.mutt/muttrc
110read-only ${HOME}/.msmtprc
105read-only ${HOME}/.exrc 111read-only ${HOME}/.exrc
106read-only ${HOME}/_exrc 112read-only ${HOME}/_exrc
107read-only ${HOME}/.vimrc 113read-only ${HOME}/.vimrc
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 69f0a2e1b..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
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/fossamail.profile b/etc/fossamail.profile
new file mode 100644
index 000000000..a0dc8ae59
--- /dev/null
+++ b/etc/fossamail.profile
@@ -0,0 +1,15 @@
1# Firejail profile for FossaMail
2
3noblacklist ~/.gnupg
4mkdir ~/.gnupg
5whitelist ~/.gnupg
6
7noblacklist ~/.fossamail
8mkdir ~/.fossamail
9whitelist ~/.fossamail
10
11noblacklist ~/.cache/fossamail
12mkdir ~/.cache/fossamail
13whitelist ~/.cache/fossamail
14
15include /etc/firejail/firefox.profile
diff --git a/etc/gpa.profile b/etc/gpa.profile
index 7d7277190..9da750f9e 100644
--- a/etc/gpa.profile
+++ b/etc/gpa.profile
@@ -18,6 +18,4 @@ shell none
18tracelog 18tracelog
19 19
20# private-bin gpa,gpg 20# private-bin gpa,gpg
21private-tmp
22private-dev 21private-dev
23# private-etc none
diff --git a/etc/gpg-agent.profile b/etc/gpg-agent.profile
index 59c7383d7..f587f0d53 100644
--- a/etc/gpg-agent.profile
+++ b/etc/gpg-agent.profile
@@ -11,7 +11,7 @@ nogroups
11nonewprivs 11nonewprivs
12noroot 12noroot
13nosound 13nosound
14protocol unix 14protocol unix,inet,inet6
15seccomp 15seccomp
16netfilter 16netfilter
17no3d 17no3d
@@ -21,6 +21,4 @@ tracelog
21blacklist /tmp/.X11-unix 21blacklist /tmp/.X11-unix
22 22
23# private-bin gpg-agent,gpg 23# private-bin gpg-agent,gpg
24private-tmp
25private-dev 24private-dev
26# private-etc none
diff --git a/etc/gpg.profile b/etc/gpg.profile
index d711c6f3e..963ff5ed7 100644
--- a/etc/gpg.profile
+++ b/etc/gpg.profile
@@ -11,10 +11,9 @@ nogroups
11nonewprivs 11nonewprivs
12noroot 12noroot
13nosound 13nosound
14protocol unix 14protocol unix,inet,inet6
15seccomp 15seccomp
16netfilter 16netfilter
17net none
18no3d 17no3d
19shell none 18shell none
20tracelog 19tracelog
@@ -22,6 +21,4 @@ tracelog
22blacklist /tmp/.X11-unix 21blacklist /tmp/.X11-unix
23 22
24# private-bin gpg,gpg-agent 23# private-bin gpg,gpg-agent
25private-tmp
26private-dev 24private-dev
27# private-etc none
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/platform/debian/conffiles b/platform/debian/conffiles
index 9afe42be8..56a5c8e7e 100644
--- a/platform/debian/conffiles
+++ b/platform/debian/conffiles
@@ -240,3 +240,5 @@
240/etc/firejail/xonotic.profile 240/etc/firejail/xonotic.profile
241/etc/firejail/VirtualBox.profile 241/etc/firejail/VirtualBox.profile
242/etc/firejail/qupzilla.profile 242/etc/firejail/qupzilla.profile
243/etc/firejail/FossaMail.profile
244/etc/firejail/fossamail.profile
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
index b1e2813db..a4f5ace11 100644
--- a/src/fcopy/main.c
+++ b/src/fcopy/main.c
@@ -41,7 +41,7 @@ static void copy_file(const char *srcname, const char *destname, mode_t mode, ui
41 // open source 41 // open source
42 int src = open(srcname, O_RDONLY); 42 int src = open(srcname, O_RDONLY);
43 if (src < 0) { 43 if (src < 0) {
44 fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname); 44 fprintf(stderr, "Warning fcopy: cannot open %s, file not copied\n", srcname);
45 return; 45 return;
46 } 46 }
47 47
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index fe65a5077..4e4e5488a 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -184,8 +184,6 @@ eog
184# other 184# other
185atom 185atom
186atom-beta 186atom-beta
187gpa
188gpg
189ranger 187ranger
190keepass 188keepass
191keepass2 189keepass2
diff --git a/src/firejail/bandwidth.c b/src/firejail/bandwidth.c
index 5e9002f22..84c9dc53a 100644
--- a/src/firejail/bandwidth.c
+++ b/src/firejail/bandwidth.c
@@ -435,15 +435,8 @@ void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, in
435 if (setregid(0, 0)) 435 if (setregid(0, 0))
436 errExit("setregid"); 436 errExit("setregid");
437 437
438 if (!cfg.shell)
439 cfg.shell = guess_shell();
440 if (!cfg.shell) {
441 fprintf(stderr, "Error: no POSIX shell found, please use --shell command line option\n");
442 exit(1);
443 }
444
445 char *arg[4]; 438 char *arg[4];
446 arg[0] = cfg.shell; 439 arg[0] = "/bin/sh";
447 arg[1] = "-c"; 440 arg[1] = "-c";
448 arg[2] = cmd; 441 arg[2] = cmd;
449 arg[3] = NULL; 442 arg[3] = NULL;
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 0872bf0d0..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,6 +105,14 @@ 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;
108 // create an empty file as root, and change ownership to user
109 FILE *fp = fopen(dest, "w");
110 if (fp) {
111 fprintf(fp, "\n");
112 SET_PERMS_STREAM(fp, getuid(), getgid(), 0600);
113 fclose(fp);
114 }
115
109 if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1) 116 if (asprintf(&src, "%s/.Xauthority", cfg.homedir) == -1)
110 errExit("asprintf"); 117 errExit("asprintf");
111 118
@@ -115,12 +122,9 @@ static int store_xauthority(void) {
115 fprintf(stderr, "Warning: invalid .Xauthority file\n"); 122 fprintf(stderr, "Warning: invalid .Xauthority file\n");
116 return 0; 123 return 0;
117 } 124 }
118 125
119 int rv = copy_file(src, dest, -1, -1, 0600); 126 copy_file_as_user(src, dest, getuid(), getgid(), 0600); // regular user
120 if (rv) { 127 fs_logger2("clone", dest);
121 fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n");
122 return 0;
123 }
124 return 1; // file copied 128 return 1; // file copied
125 } 129 }
126 130
@@ -128,8 +132,17 @@ static int store_xauthority(void) {
128} 132}
129 133
130static int store_asoundrc(void) { 134static int store_asoundrc(void) {
135 // put a copy of .Xauthority in XAUTHORITY_FILE
131 char *src; 136 char *src;
132 char *dest = RUN_ASOUNDRC_FILE; 137 char *dest = RUN_ASOUNDRC_FILE;
138 // create an empty file as root, and change ownership to user
139 FILE *fp = fopen(dest, "w");
140 if (fp) {
141 fprintf(fp, "\n");
142 SET_PERMS_STREAM(fp, getuid(), getgid(), 0644);
143 fclose(fp);
144 }
145
133 if (asprintf(&src, "%s/.asoundrc", cfg.homedir) == -1) 146 if (asprintf(&src, "%s/.asoundrc", cfg.homedir) == -1)
134 errExit("asprintf"); 147 errExit("asprintf");
135 148
@@ -150,11 +163,8 @@ static int store_asoundrc(void) {
150 free(rp); 163 free(rp);
151 } 164 }
152 165
153 int rv = copy_file(src, dest, -1, -1, -0644); 166 copy_file_as_user(src, dest, getuid(), getgid(), 0644); // regular user
154 if (rv) { 167 fs_logger2("clone", dest);
155 fprintf(stderr, "Warning: cannot transfer .asoundrc in private home directory\n");
156 return 0;
157 }
158 return 1; // file copied 168 return 1; // file copied
159 } 169 }
160 170
@@ -167,13 +177,15 @@ static void copy_xauthority(void) {
167 char *dest; 177 char *dest;
168 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) 178 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
169 errExit("asprintf"); 179 errExit("asprintf");
170 // copy, set permissions and ownership 180
171 int rv = copy_file(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); 181 // if destination is a symbolic link, exit the sandbox!!!
172 if (rv) 182 if (is_link(dest)) {
173 fprintf(stderr, "Warning: cannot transfer .Xauthority in private home directory\n"); 183 fprintf(stderr, "Error: %s is a symbolic link\n", dest);
174 else { 184 exit(1);
175 fs_logger2("clone", dest);
176 } 185 }
186
187 copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user
188 fs_logger2("clone", dest);
177 189
178 // delete the temporary file 190 // delete the temporary file
179 unlink(src); 191 unlink(src);
@@ -185,14 +197,16 @@ static void copy_asoundrc(void) {
185 char *dest; 197 char *dest;
186 if (asprintf(&dest, "%s/.asoundrc", cfg.homedir) == -1) 198 if (asprintf(&dest, "%s/.asoundrc", cfg.homedir) == -1)
187 errExit("asprintf"); 199 errExit("asprintf");
188 // copy, set permissions and ownership 200
189 int rv = copy_file(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); 201 // if destination is a symbolic link, exit the sandbox!!!
190 if (rv) 202 if (is_link(dest)) {
191 fprintf(stderr, "Warning: cannot transfer .asoundrc in private home directory\n"); 203 fprintf(stderr, "Error: %s is a symbolic link\n", dest);
192 else { 204 exit(1);
193 fs_logger2("clone", dest);
194 } 205 }
195 206
207 copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user
208 fs_logger2("clone", dest);
209
196 // delete the temporary file 210 // delete the temporary file
197 unlink(src); 211 unlink(src);
198} 212}
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 e70e20eec..84bf5e8e6 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -35,6 +35,7 @@
35#include <signal.h> 35#include <signal.h>
36#include <time.h> 36#include <time.h>
37#include <net/if.h> 37#include <net/if.h>
38#include <sys/utsname.h>
38 39
39#if 0 40#if 0
40#include <sys/times.h> 41#include <sys/times.h>
@@ -817,8 +818,27 @@ int main(int argc, char **argv) {
817 818
818 if (check_arg(argc, argv, "--quiet")) 819 if (check_arg(argc, argv, "--quiet"))
819 arg_quiet = 1; 820 arg_quiet = 1;
820 if (check_arg(argc, argv, "--allow-debuggers")) 821 if (check_arg(argc, argv, "--allow-debuggers")) {
822 // check kernel version
823 struct utsname u;
824 int rv = uname(&u);
825 if (rv != 0)
826 errExit("uname");
827 int major;
828 int minor;
829 if (2 != sscanf(u.release, "%d.%d", &major, &minor)) {
830 fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version);
831 exit(1);
832 }
833 if (major < 4 || (major == 4 && minor < 8)) {
834 fprintf(stderr, "Error: --allow-debuggers is disabled on Linux kernels prior to 4.8. "
835 "A bug in ptrace call allows a full bypass of the seccomp filter. "
836 "Your current kernel version is %d.%d.\n", major, minor);
837 exit(1);
838 }
839
821 arg_allow_debuggers = 1; 840 arg_allow_debuggers = 1;
841 }
822 842
823 // drop permissions by default and rise them when required 843 // drop permissions by default and rise them when required
824 EUID_INIT(); 844 EUID_INIT();
@@ -1448,13 +1468,10 @@ int main(int argc, char **argv) {
1448 fprintf(stderr, "Error: invalid chroot directory\n"); 1468 fprintf(stderr, "Error: invalid chroot directory\n");
1449 exit(1); 1469 exit(1);
1450 } 1470 }
1451 free(rpath); 1471 cfg.chrootdir = rpath;
1452 1472
1453 // check chroot directory structure 1473 // check chroot directory structure
1454 if (fs_check_chroot_dir(cfg.chrootdir)) { 1474 fs_check_chroot_dir(cfg.chrootdir);
1455 fprintf(stderr, "Error: invalid chroot\n");
1456 exit(1);
1457 }
1458 } 1475 }
1459 else 1476 else
1460 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 f890dd534..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)
@@ -127,21 +128,63 @@ void pulseaudio_init(void) {
127 if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1) 128 if (asprintf(&dir1, "%s/.config", cfg.homedir) == -1)
128 errExit("asprintf"); 129 errExit("asprintf");
129 if (stat(dir1, &s) == -1) { 130 if (stat(dir1, &s) == -1) {
130 int rv = mkdir(dir1, 0755); 131 pid_t child = fork();
131 if (rv == 0) { 132 if (child < 0)
132 if (set_perms(dir1, getuid(), getgid(), 0755)) 133 errExit("fork");
133 {;} // do nothing 134 if (child == 0) {
135 // drop privileges
136 drop_privs(0);
137
138 int rv = mkdir(dir1, 0755);
139 if (rv == 0) {
140 if (set_perms(dir1, getuid(), getgid(), 0755))
141 {;} // do nothing
142 }
143#ifdef HAVE_GCOV
144 __gcov_flush();
145#endif
146 _exit(0);
147 }
148 // wait for the child to finish
149 waitpid(child, NULL, 0);
150 }
151 else {
152 // make sure the directory is owned by the user
153 if (s.st_uid != getuid()) {
154 fprintf(stderr, "Error: user .config directory is not owned by the current user\n");
155 exit(1);
134 } 156 }
135 } 157 }
136 free(dir1); 158 free(dir1);
159
137 if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1) 160 if (asprintf(&dir1, "%s/.config/pulse", cfg.homedir) == -1)
138 errExit("asprintf"); 161 errExit("asprintf");
139 if (stat(dir1, &s) == -1) { 162 if (stat(dir1, &s) == -1) {
140 /* coverity[toctou] */ 163 pid_t child = fork();
141 int rv = mkdir(dir1, 0700); 164 if (child < 0)
142 if (rv == 0) { 165 errExit("fork");
143 if (set_perms(dir1, getuid(), getgid(), 0700)) 166 if (child == 0) {
144 {;} // do nothing 167 // drop privileges
168 drop_privs(0);
169
170 int rv = mkdir(dir1, 0700);
171 if (rv == 0) {
172 if (set_perms(dir1, getuid(), getgid(), 0700))
173 {;} // do nothing
174 }
175#ifdef HAVE_GCOV
176 __gcov_flush();
177#endif
178 _exit(0);
179 }
180 // wait for the child to finish
181 waitpid(child, NULL, 0);
182 }
183 else {
184 // make sure the directory is owned by the user
185 if (s.st_uid != getuid()) {
186 fprintf(stderr, "Error: user .config/pulse directory is not owned by the current user\n");
187 exit(1);
145 } 188 }
146 } 189 }
147 free(dir1); 190 free(dir1);
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 50fcd6ed0..493877db3 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -616,19 +616,10 @@ int sandbox(void* sandbox_arg) {
616 fs_trace_preload(); 616 fs_trace_preload();
617 } 617 }
618 else 618 else
619#endif 619#endif
620#ifdef HAVE_OVERLAYFS 620#ifdef HAVE_OVERLAYFS
621 if (arg_overlay) { 621 if (arg_overlay) {
622 fs_overlayfs(); 622 fs_overlayfs();
623 // force caps and seccomp if not started as root
624 if (getuid() != 0) {
625 enforce_filters();
626#ifdef HAVE_SECCOMP
627 enforce_seccomp = 1;
628#endif
629 }
630 else
631 arg_seccomp = 1;
632 } 623 }
633 else 624 else
634#endif 625#endif
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 75f2acdb9..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
@@ -177,14 +178,14 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m
177 // open source 178 // open source
178 int src = open(srcname, O_RDONLY); 179 int src = open(srcname, O_RDONLY);
179 if (src < 0) { 180 if (src < 0) {
180 fprintf(stderr, "Warning: cannot open %s, file not copied\n", srcname); 181 fprintf(stderr, "Warning: cannot open source file %s, file not copied\n", srcname);
181 return -1; 182 return -1;
182 } 183 }
183 184
184 // open destination 185 // open destination
185 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 186 int dst = open(destname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
186 if (dst < 0) { 187 if (dst < 0) {
187 fprintf(stderr, "Warning: cannot open %s, file not copied\n", destname); 188 fprintf(stderr, "Warning: cannot open destination file %s, file not copied\n", destname);
188 close(src); 189 close(src);
189 return -1; 190 return -1;
190 } 191 }
@@ -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 60c21cbc1..69ed2a8dc 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -76,7 +76,9 @@ $ firejail [OPTIONS] firefox # starting Mozilla Firefox
76Signal the end of options and disables further option processing. 76Signal the end of options and disables further option processing.
77.TP 77.TP
78\fB\-\-allow-debuggers 78\fB\-\-allow-debuggers
79Allow tools such as strace and gdb inside the sandbox. 79Allow tools such as strace and gdb inside the sandbox. This option is only available
80when running on Linux kernels 4.8 or newer - a kernel bug in ptrace system call allows a full
81bypass of the seccomp filter.
80.br 82.br
81 83
82.br 84.br
@@ -676,7 +678,7 @@ $ firejail \-\-net=eth0 \-\-mac=00:11:22:33:44:55 firefox
676 678
677.TP 679.TP
678\fB\-\-machine-id 680\fB\-\-machine-id
679Preserve 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.
680.br 682.br
681 683
682.br 684.br