aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Reiner Herrmann <reiner@reiner-h.de>2021-06-21 23:10:09 +0200
committerLibravatar Reiner Herrmann <reiner@reiner-h.de>2021-06-21 23:10:09 +0200
commit0f0325459e211ff31895ed7cbbbaae6c2c6ae9a2 (patch)
tree0875693a6ceef54818511972601d587a09a1aab4
parentstyle: grammer and codestyle improvements (diff)
parentcreating alpine.profile (#4350) (diff)
downloadfirejail-0f0325459e211ff31895ed7cbbbaae6c2c6ae9a2.tar.gz
firejail-0f0325459e211ff31895ed7cbbbaae6c2c6ae9a2.tar.zst
firejail-0f0325459e211ff31895ed7cbbbaae6c2c6ae9a2.zip
Merge branch 'master' into kuesji/master
-rw-r--r--Makefile.in2
-rw-r--r--README42
-rw-r--r--README.md15
-rw-r--r--RELNOTES8
-rwxr-xr-xconfigure102
-rw-r--r--configure.ac93
-rwxr-xr-xcontrib/jail_prober.py28
-rw-r--r--contrib/vim/ftdetect/firejail.vim12
-rw-r--r--contrib/vim/syntax/firejail.vim27
-rw-r--r--etc/firejail.config22
-rw-r--r--etc/inc/disable-programs.inc13
-rw-r--r--etc/profile-a-l/0ad.profile2
-rw-r--r--etc/profile-a-l/alpine.profile104
-rw-r--r--etc/profile-a-l/alpinef.profile14
-rw-r--r--etc/profile-a-l/apostrophe.profile1
-rw-r--r--etc/profile-a-l/bijiben.profile1
-rw-r--r--etc/profile-a-l/celluloid.profile2
-rw-r--r--etc/profile-a-l/chromium-browser-privacy.profile2
-rw-r--r--etc/profile-a-l/ddgr.profile13
-rw-r--r--etc/profile-a-l/elinks.profile38
-rw-r--r--etc/profile-a-l/eo-common.profile2
-rw-r--r--etc/profile-a-l/etr.profile2
-rw-r--r--etc/profile-a-l/evince.profile2
-rw-r--r--etc/profile-a-l/file-roller.profile1
-rw-r--r--etc/profile-a-l/firefox.profile2
-rw-r--r--etc/profile-a-l/frogatto.profile1
-rw-r--r--etc/profile-a-l/gapplication.profile1
-rw-r--r--etc/profile-a-l/gfeeds.profile1
-rw-r--r--etc/profile-a-l/gnome-maps.profile2
-rw-r--r--etc/profile-a-l/gnome-passwordsafe.profile2
-rw-r--r--etc/profile-a-l/googler-common.profile62
-rw-r--r--etc/profile-a-l/googler.profile13
-rw-r--r--etc/profile-a-l/gunzip.profile2
-rw-r--r--etc/profile-a-l/hexchat.profile5
-rw-r--r--etc/profile-a-l/keepassxc.profile2
-rw-r--r--etc/profile-a-l/kodi.profile4
-rw-r--r--etc/profile-a-l/libreoffice.profile2
-rw-r--r--etc/profile-a-l/links-common.profile63
-rw-r--r--etc/profile-a-l/links.profile54
-rw-r--r--etc/profile-a-l/links2.profile18
-rw-r--r--etc/profile-m-z/marker.profile1
-rw-r--r--etc/profile-m-z/mcomix.profile74
-rw-r--r--etc/profile-m-z/megaglest.profile1
-rw-r--r--etc/profile-m-z/meld.profile2
-rw-r--r--etc/profile-m-z/minecraft-launcher.profile1
-rw-r--r--etc/profile-m-z/mpv.profile2
-rw-r--r--etc/profile-m-z/mrrescue.profile2
-rw-r--r--etc/profile-m-z/pingus.profile2
-rw-r--r--etc/profile-m-z/qcomicbook.profile68
-rw-r--r--etc/profile-m-z/rtin.profile8
-rw-r--r--etc/profile-m-z/scorched3d.profile1
-rw-r--r--etc/profile-m-z/seahorse-adventures.profile6
-rw-r--r--etc/profile-m-z/slack.profile4
-rw-r--r--etc/profile-m-z/supertux2.profile1
-rw-r--r--etc/profile-m-z/supertuxkart.profile3
-rw-r--r--etc/profile-m-z/telegram-desktop.profile2
-rw-r--r--etc/profile-m-z/tin.profile69
-rw-r--r--etc/profile-m-z/tuxguitar.profile6
-rw-r--r--etc/profile-m-z/w3m.profile24
-rw-r--r--etc/profile-m-z/weechat.profile1
-rw-r--r--etc/profile-m-z/xlinks.profile1
-rw-r--r--etc/profile-m-z/xlinks220
-rw-r--r--etc/profile-m-z/yelp.profile1
-rw-r--r--etc/profile-m-z/zathura.profile3
-rw-r--r--etc/templates/profile.template21
-rw-r--r--platform/rpm/firejail.spec2
-rw-r--r--src/fcopy/main.c19
-rw-r--r--src/firecfg/firecfg.config8
-rw-r--r--src/firejail/appimage.c35
-rw-r--r--src/firejail/checkcfg.c13
-rw-r--r--src/firejail/chroot.c43
-rw-r--r--src/firejail/cmdline.c32
-rw-r--r--src/firejail/dbus.c18
-rw-r--r--src/firejail/dhcp.c12
-rw-r--r--src/firejail/firejail.h35
-rw-r--r--src/firejail/fs.c253
-rw-r--r--src/firejail/fs_dev.c2
-rw-r--r--src/firejail/fs_home.c63
-rw-r--r--src/firejail/fs_lib.c13
-rw-r--r--src/firejail/fs_mkdir.c3
-rw-r--r--src/firejail/fs_trace.c6
-rw-r--r--src/firejail/fs_var.c4
-rw-r--r--src/firejail/fs_whitelist.c39
-rw-r--r--src/firejail/join.c2
-rw-r--r--src/firejail/ls.c4
-rw-r--r--src/firejail/macros.c1
-rw-r--r--src/firejail/main.c152
-rw-r--r--src/firejail/mountinfo.c5
-rw-r--r--src/firejail/no_sandbox.c2
-rw-r--r--src/firejail/paths.c2
-rw-r--r--src/firejail/profile.c82
-rw-r--r--src/firejail/pulseaudio.c68
-rw-r--r--src/firejail/restrict_users.c22
-rw-r--r--src/firejail/rlimit.c4
-rw-r--r--src/firejail/sandbox.c3
-rw-r--r--src/firejail/sbox.c4
-rw-r--r--src/firejail/selinux.c10
-rw-r--r--src/firejail/shutdown.c6
-rw-r--r--src/firejail/util.c258
-rw-r--r--src/firejail/x11.c98
-rw-r--r--src/firemon/interface.c4
-rw-r--r--src/firemon/netstats.c4
-rw-r--r--src/firemon/procevent.c4
-rw-r--r--src/firemon/top.c4
-rw-r--r--src/include/rundefs.h4
-rw-r--r--src/jailcheck/access.c2
-rw-r--r--src/jailcheck/jailcheck.h2
-rw-r--r--src/jailcheck/main.c23
-rw-r--r--src/jailcheck/network.c56
-rw-r--r--src/jailcheck/sysfiles.c2
-rw-r--r--src/lib/ldd_utils.c2
-rw-r--r--src/man/firejail-profile.txt7
-rw-r--r--src/man/firejail.txt10
-rw-r--r--src/man/jailcheck.txt12
-rwxr-xr-xtest/fs/fscheck-tmpfs.exp2
115 files changed, 1775 insertions, 792 deletions
diff --git a/Makefile.in b/Makefile.in
index 6be62cb6e..17bd76464 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -31,7 +31,7 @@ SBOX_APPS_NON_DUMPABLE = src/fcopy/fcopy src/fldd/fldd src/fnet/fnet src/fnetfil
31MYDIRS = src/lib $(MAN_SRC) $(COMPLETIONDIRS) 31MYDIRS = src/lib $(MAN_SRC) $(COMPLETIONDIRS)
32MYLIBS = src/libpostexecseccomp/libpostexecseccomp.so src/libtrace/libtrace.so src/libtracelog/libtracelog.so 32MYLIBS = src/libpostexecseccomp/libpostexecseccomp.so src/libtrace/libtrace.so src/libtracelog/libtracelog.so
33COMPLETIONS = src/zsh_completion/_firejail src/bash_completion/firejail.bash_completion 33COMPLETIONS = src/zsh_completion/_firejail src/bash_completion/firejail.bash_completion
34MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 firejail-users.5 jailcheck.5 34MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 firejail-users.5 jailcheck.1
35SBOX_APPS_NON_DUMPABLE += src/fsec-optimize/fsec-optimize src/fsec-print/fsec-print src/fseccomp/fseccomp 35SBOX_APPS_NON_DUMPABLE += src/fsec-optimize/fsec-optimize src/fsec-print/fsec-print src/fseccomp/fseccomp
36SECCOMP_FILTERS = seccomp seccomp.debug seccomp.32 seccomp.block_secondary seccomp.mdwx seccomp.mdwx.32 36SECCOMP_FILTERS = seccomp seccomp.debug seccomp.32 seccomp.block_secondary seccomp.mdwx seccomp.mdwx.32
37ALL_ITEMS = $(APPS) $(SBOX_APPS) $(SBOX_APPS_NON_DUMPABLE) $(MYLIBS) 37ALL_ITEMS = $(APPS) $(SBOX_APPS) $(SBOX_APPS_NON_DUMPABLE) $(MYLIBS)
diff --git a/README b/README
index 522fdc34a..b8c0aef44 100644
--- a/README
+++ b/README
@@ -109,6 +109,7 @@ Amin Vakil (https://github.com/aminvakil)
109 - whois profile fix 109 - whois profile fix
110 - added profile for strawberry 110 - added profile for strawberry
111 - w3m profile fix 111 - w3m profile fix
112 - disable seccomp in wireshark profile
112Andreas Hunkeler (https://github.com/Karneades) 113Andreas Hunkeler (https://github.com/Karneades)
113 - Add profile for offical Linux Teams application 114 - Add profile for offical Linux Teams application
114Andrey Alekseenko (https://github.com/al42and) 115Andrey Alekseenko (https://github.com/al42and)
@@ -203,6 +204,7 @@ Bundy01 (https://github.com/Bundy01)
203 - fixup geary 204 - fixup geary
204 - add gradio profile 205 - add gradio profile
205 - update virtualbox.profile 206 - update virtualbox.profile
207 - Quodlibet profile
206BytesTuner (https://github.com/BytesTuner) 208BytesTuner (https://github.com/BytesTuner)
207 - provided keepassxc profile 209 - provided keepassxc profile
208caoliver (https://github.com/caoliver) 210caoliver (https://github.com/caoliver)
@@ -435,6 +437,8 @@ hamzadis (https://github.com/hamzadis)
435 - added --overlay-named=name and --overlay-path=path 437 - added --overlay-named=name and --overlay-path=path
436Hans-Christoph Steiner (https://github.com/eighthave) 438Hans-Christoph Steiner (https://github.com/eighthave)
437 - added xournal profile 439 - added xournal profile
440Harald Kubota (https://github.com/haraldkubota)
441 - zsh completion
438hawkey116477 (https://github.com/hawkeye116477) 442hawkey116477 (https://github.com/hawkeye116477)
439 - added Waterfox profile 443 - added Waterfox profile
440 - updated Cyberfox profile 444 - updated Cyberfox profile
@@ -496,6 +500,7 @@ Jean-Philippe Eisenbarth (https://github.com/jpeisenbarth)
496 - fixed spotify.profile 500 - fixed spotify.profile
497Jeff Squyres (https://github.com/jsquyres) 501Jeff Squyres (https://github.com/jsquyres)
498 - various manpage fixes 502 - various manpage fixes
503 - cmdline.c: optionally quote the resulting command line
499Jericho (https://github.com/attritionorg) 504Jericho (https://github.com/attritionorg)
500 - spelling 505 - spelling
501Jesse Smith (https://github.com/slicer69) 506Jesse Smith (https://github.com/slicer69)
@@ -520,6 +525,7 @@ Jose Riha (https://github.com/jose1711)
520 - Add davfs2 secrets file to blacklist 525 - Add davfs2 secrets file to blacklist
521 - Add profile for udiskie 526 - Add profile for udiskie
522 - fix udiskie.profile 527 - fix udiskie.profile
528 - improve hints for allowing browser access to Gnome extensions connector
523jrabe (https://github.com/jrabe) 529jrabe (https://github.com/jrabe)
524 - disallow access to kdbx files 530 - disallow access to kdbx files
525 - Epiphany profile 531 - Epiphany profile
@@ -555,6 +561,7 @@ Kishore96in (https://github.com/Kishore96in)
555 - jitsi-meet-desktop profile 561 - jitsi-meet-desktop profile
556 - konversatin profile fix 562 - konversatin profile fix
557 - added Neochat profile 563 - added Neochat profile
564 - added whitelist-1793-workaround.inc
558KOLANICH (https://github.com/KOLANICH) 565KOLANICH (https://github.com/KOLANICH)
559 - added symlink fixer fix_private-bin.py in contrib section 566 - added symlink fixer fix_private-bin.py in contrib section
560 - update fix_private-bin.py 567 - update fix_private-bin.py
@@ -610,6 +617,8 @@ Mattias Wadman (https://github.com/wader)
610 - seccomp errno filter support 617 - seccomp errno filter support
611Matthew Gyurgyik (https://github.com/pyther) 618Matthew Gyurgyik (https://github.com/pyther)
612 - rpm spec and several fixes 619 - rpm spec and several fixes
620Matthew Cline (https://github.com/matthew-cline)
621 - steam profile and dropbox profile fixes
613matu3ba (https://github.com/matu3ba) 622matu3ba (https://github.com/matu3ba)
614 - evince hardening, dbus removed 623 - evince hardening, dbus removed
615 - fix dia profile 624 - fix dia profile
@@ -649,12 +658,20 @@ Nick Fox (https://github.com/njfox)
649 - fix wire-desktop.profile on arch 658 - fix wire-desktop.profile on arch
650NickMolloy (https://github.com/NickMolloy) 659NickMolloy (https://github.com/NickMolloy)
651 - ARP address length fix 660 - ARP address length fix
661Nico (https://github.com/dr460nf1r3)
662 - added FireDragon profile
663Nicola Davide Mannarelli (https://github.com/nidamanx)
664 - fix "Could not create AF_NETLINK socket"
665 - added nextcloud profiles
666 - Firefox, KeepassXC, Telegram fixes
652Niklas Haas (https://github.com/haasn) 667Niklas Haas (https://github.com/haasn)
653 - blacklisting for keybase.io's client 668 - blacklisting for keybase.io's client
654Niklas Goerke (https://github.com/Niklas974) 669Niklas Goerke (https://github.com/Niklas974)
655 - update QOwnNotes profile 670 - update QOwnNotes profile
656Nikos Chantziaras (https://github.com/realnc) 671Nikos Chantziaras (https://github.com/realnc)
657 - fix audio support for Discord 672 - fix audio support for Discord
673nolanl (https://github.com/nolanl)
674 - added localtime to signal-desktop's profile
658nyancat18 (https://github.com/nyancat18) 675nyancat18 (https://github.com/nyancat18)
659 - added ardour4, dooble, karbon, krita profiles 676 - added ardour4, dooble, karbon, krita profiles
660Ondra Nekola (https://github.com/satai) 677Ondra Nekola (https://github.com/satai)
@@ -702,6 +719,8 @@ Petter Reinholdtsen (pere@hungry.com)
702PharmaceuticalCobweb (https://github.com/PharmaceuticalCobweb) 719PharmaceuticalCobweb (https://github.com/PharmaceuticalCobweb)
703 - fix quiterss profile 720 - fix quiterss profile
704 - added profile for gnome-ring 721 - added profile for gnome-ring
722pholodniak (https://github.com/pholodniak)
723 - profstats fixes
705pianoslum (https://github.com/pianoslum) 724pianoslum (https://github.com/pianoslum)
706 - nodbus breaking evince two-page-view warning 725 - nodbus breaking evince two-page-view warning
707pirate486743186 (https://github.com/pirate486743186) 726pirate486743186 (https://github.com/pirate486743186)
@@ -709,6 +728,17 @@ pirate486743186 (https://github.com/pirate486743186)
709 - mpsyt profile 728 - mpsyt profile
710 - fix youtube-dl and mpv 729 - fix youtube-dl and mpv
711 - fix gnome-mpv profile 730 - fix gnome-mpv profile
731 - fix gunzip profile
732 - reorganizing youtube-viewers
733 - fix pluma profile
734 - whitelist /var/lib/aspell
735 - mcomix fixes
736 - fixing engrampa profile
737 - adding qcomicbook and pipe-viewer in disable-programs
738 - newsboat/newsbeuter profiles
739 - fix atril profile
740 - rtv profile
741 - reorganizing links browsers
712Pixel Fairy (https://github.com/xahare) 742Pixel Fairy (https://github.com/xahare)
713 - added fjclip.py, fjdisplay.py and fjresize.py in contrib section 743 - added fjclip.py, fjdisplay.py and fjresize.py in contrib section
714PizzaDude (https://github.com/pizzadude) 744PizzaDude (https://github.com/pizzadude)
@@ -745,6 +775,7 @@ Rahul Golam (https://github.com/technoLord)
745RandomVoid (https://github.com/RandomVoid) 775RandomVoid (https://github.com/RandomVoid)
746 - fix building C# projects in Godot 776 - fix building C# projects in Godot
747 - fix Lutris profile 777 - fix Lutris profile
778 - fix running games with enabled Feral GameMode in Lutris
748Raphaël Droz (https://github.com/drzraf) 779Raphaël Droz (https://github.com/drzraf)
749 - zoom profile fixes 780 - zoom profile fixes
750realaltffour (https://github.com/realaltffour) 781realaltffour (https://github.com/realaltffour)
@@ -786,6 +817,8 @@ rusty-snake (https://github.com/rusty-snake)
786 - some typo fixes 817 - some typo fixes
787 - added profile templates 818 - added profile templates
788 - added sort.py to contrib 819 - added sort.py to contrib
820sak96 (https://github.com/sak96)
821 - discord profile fixes
789Salvo 'LtWorf' Tomaselli (https://github.com/ltworf) 822Salvo 'LtWorf' Tomaselli (https://github.com/ltworf)
790 - fixed ktorrent profile 823 - fixed ktorrent profile
791sarneaud (https://github.com/sarneaud) 824sarneaud (https://github.com/sarneaud)
@@ -814,6 +847,8 @@ sinkuu (https://github.com/sinkuu)
814 - fix symlink invocation for programs placing symlinks in $PATH 847 - fix symlink invocation for programs placing symlinks in $PATH
815Simo Piiroinen (https://github.com/spiiroin) 848Simo Piiroinen (https://github.com/spiiroin)
816 - Jolla/SailfishOS patches 849 - Jolla/SailfishOS patches
850slowpeek (https://github.com/slowpeek)
851 - refine appimage example in docs
817smitsohu (https://github.com/smitsohu) 852smitsohu (https://github.com/smitsohu)
818 - read-only kde4 services directory 853 - read-only kde4 services directory
819 - enhanced mediathekview profile 854 - enhanced mediathekview profile
@@ -939,6 +974,10 @@ Topi Miettinen (https://github.com/topimiettinen)
939 - improve loading of seccomp filter and memory-deny-write-execute feature 974 - improve loading of seccomp filter and memory-deny-write-execute feature
940 - private-lib feature 975 - private-lib feature
941 - make --nodbus block also system D-Bus socket 976 - make --nodbus block also system D-Bus socket
977Ted Robertson (https://github.com/tredondo)
978 - webstorm profile fixes
979 - added bcompare profile
980 - various documentation fixes
942user1024 (user1024@tut.by) 981user1024 (user1024@tut.by)
943 - electron profile whitelisting 982 - electron profile whitelisting
944 - fixed Rocket.Chat profile 983 - fixed Rocket.Chat profile
@@ -1003,6 +1042,9 @@ Vladimir Schowalter (https://github.com/VladimirSchowalter20)
1003 - apparmor profile enhancements 1042 - apparmor profile enhancements
1004 - various KDE profile enhancements 1043 - various KDE profile enhancements
1005 read-only kde5 services directory 1044 read-only kde5 services directory
1045Vladislav Nepogodin (https://github.com/vnepogodin)
1046 - added Librewolf profiles
1047 - added Sway profile
1006xee5ch (https://github.com/xee5ch) 1048xee5ch (https://github.com/xee5ch)
1007 - skypeforlinux profile 1049 - skypeforlinux profile
1008Ypnose (https://github.com/Ypnose) 1050Ypnose (https://github.com/Ypnose)
diff --git a/README.md b/README.md
index c524a328d..c235759e9 100644
--- a/README.md
+++ b/README.md
@@ -126,18 +126,18 @@ $ cd firejail
126$ ./configure && make && sudo make install-strip 126$ ./configure && make && sudo make install-strip
127````` 127`````
128On Debian/Ubuntu you will need to install git and gcc compiler. AppArmor 128On Debian/Ubuntu you will need to install git and gcc compiler. AppArmor
129development libraries and pkg-config are required when using --apparmor 129development libraries and pkg-config are required when using `--apparmor`
130./configure option: 130./configure option:
131````` 131`````
132$ sudo apt-get install git build-essential libapparmor-dev pkg-config gawk 132$ sudo apt-get install git build-essential libapparmor-dev pkg-config gawk
133````` 133`````
134For --selinux option, add libselinux1-dev (libselinux-devel for Fedora). 134For `--selinux` option, add libselinux1-dev (libselinux-devel for Fedora).
135 135
136Detailed information on using firejail from git is available on the [wiki](https://github.com/netblue30/firejail/wiki/Using-firejail-from-git). 136Detailed information on using firejail from git is available on the [wiki](https://github.com/netblue30/firejail/wiki/Using-firejail-from-git).
137 137
138## Running the sandbox 138## Running the sandbox
139 139
140To start the sandbox, prefix your command with firejail: 140To start the sandbox, prefix your command with `firejail`:
141 141
142````` 142`````
143$ firejail firefox # starting Mozilla Firefox 143$ firejail firefox # starting Mozilla Firefox
@@ -145,7 +145,7 @@ $ firejail transmission-gtk # starting Transmission BitTorrent
145$ firejail vlc # starting VideoLAN Client 145$ firejail vlc # starting VideoLAN Client
146$ sudo firejail /etc/init.d/nginx start 146$ sudo firejail /etc/init.d/nginx start
147````` 147`````
148Run "firejail --list" in a terminal to list all active sandboxes. Example: 148Run `firejail --list` in a terminal to list all active sandboxes. Example:
149````` 149`````
150$ firejail --list 150$ firejail --list
1511617:netblue:/usr/bin/firejail /usr/bin/firefox-esr 1511617:netblue:/usr/bin/firejail /usr/bin/firefox-esr
@@ -188,9 +188,7 @@ Use this issue to request new profiles: [#1139](https://github.com/netblue30/fir
188You can also use this tool to get a list of syscalls needed by a program: [contrib/syscalls.sh](contrib/syscalls.sh). 188You can also use this tool to get a list of syscalls needed by a program: [contrib/syscalls.sh](contrib/syscalls.sh).
189 189
190We also keep a list of profile fixes for previous released versions in [etc-fixes](https://github.com/netblue30/firejail/tree/master/etc-fixes) directory. 190We also keep a list of profile fixes for previous released versions in [etc-fixes](https://github.com/netblue30/firejail/tree/master/etc-fixes) directory.
191`````
192 191
193`````
194## Latest released version: 0.9.64 192## Latest released version: 0.9.64
195 193
196## Current development version: 0.9.65 194## Current development version: 0.9.65
@@ -334,5 +332,6 @@ avidemux, calligragemini, vmware-player, vmware-workstation, gget, com.github.ph
334pcsxr, PPSSPPSDL, openmw, openmw-launcher, jami-gnome, PCSX2, bcompare, b2sum, cksum, md5sum, sha1sum, sha224sum, 332pcsxr, PPSSPPSDL, openmw, openmw-launcher, jami-gnome, PCSX2, bcompare, b2sum, cksum, md5sum, sha1sum, sha224sum,
335sha256sum, sha384sum, sha512sum, sum, librewold-nightly, Quodlibet, tmux, sway, alienarena, alienarena-wrapper, 333sha256sum, sha384sum, sha512sum, sum, librewold-nightly, Quodlibet, tmux, sway, alienarena, alienarena-wrapper,
336ballbuster, ballbuster-wrapper, colorful, colorful-wrapper, gl-117, gl-117-wrapper, glaxium, glaxium-wrapper, 334ballbuster, ballbuster-wrapper, colorful, colorful-wrapper, gl-117, gl-117-wrapper, glaxium, glaxium-wrapper,
337pinball, pinball-wrapper, etr-wrapper, neverball-wrapper, neverputt-wrapper, supertuxkart-wrapper, firedragon 335pinball, pinball-wrapper, etr-wrapper, neverball-wrapper, neverputt-wrapper, supertuxkart-wrapper, firedragon,
338neochat, node, nvm, cargo, LibreCAD, blobby, funnyboat 336neochat, node, nvm, cargo, LibreCAD, blobby, funnyboat, pipe-viewer, gtk-pipe-viewer, links2, xlinks2, googler, ddgr,
337tin
diff --git a/RELNOTES b/RELNOTES
index 74ef66fb9..c989b00ff 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,6 +1,7 @@
1firejail (0.9.65) baseline; urgency=low 1firejail (0.9.65) baseline; urgency=low
2 * deprecated --audit options, relpaced by jailtest 2 * deprecated --audit options, relpaced by jailcheck utility
3 * deprecated follow-symlink-as-user from firejail.config 3 * deprecated follow-symlink-as-user from firejail.config
4 * rename --noautopulse to keep-config-pulse
4 * filtering environment variables 5 * filtering environment variables
5 * zsh completion 6 * zsh completion
6 * command line: --mkdir, --mkfile 7 * command line: --mkdir, --mkfile
@@ -31,8 +32,9 @@ firejail (0.9.65) baseline; urgency=low
31 * colorful, colorful-wrapper, gl-117, gl-117-wrapper, glaxium, 32 * colorful, colorful-wrapper, gl-117, gl-117-wrapper, glaxium,
32 * glaxium-wrapper, pinball, pinball-wrapper, etr-wrapper, firedragon 33 * glaxium-wrapper, pinball, pinball-wrapper, etr-wrapper, firedragon
33 * neverball-wrapper, neverputt-wrapper, supertuxkart-wrapper, neochat, 34 * neverball-wrapper, neverputt-wrapper, supertuxkart-wrapper, neochat,
34 * cargo, LibreCAD, blobby, funnyboat 35 * cargo, LibreCAD, blobby, funnyboat, pipe-viewer, gtk-pipe-viewer
35 -- netblue30 <netblue30@yahoo.com> Tue, 9 Feb 2021 09:00:00 -0500 36 * links2, xlinks2, googler, ddgr, tin
37 -- netblue30 <netblue30@yahoo.com> Wed, 2 Jun 2021 09:00:00 -0500
36 38
37firejail (0.9.64.4) baseline; urgency=low 39firejail (0.9.64.4) baseline; urgency=low
38 * disabled overlayfs, pending multiple fixes (CVE-2021-26910) 40 * disabled overlayfs, pending multiple fixes (CVE-2021-26910)
diff --git a/configure b/configure
index b75848bea..9162b6c90 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
1#! /bin/sh 1#! /bin/sh
2# Guess values for system-dependent variables and create Makefiles. 2# Guess values for system-dependent variables and create Makefiles.
3# Generated by GNU Autoconf 2.69 for firejail 0.9.65. 3# Generated by GNU Autoconf 2.69 for firejail 0.9.66rc1.
4# 4#
5# Report bugs to <netblue30@protonmail.com>. 5# Report bugs to <netblue30@protonmail.com>.
6# 6#
@@ -580,8 +580,8 @@ MAKEFLAGS=
580# Identity of this package. 580# Identity of this package.
581PACKAGE_NAME='firejail' 581PACKAGE_NAME='firejail'
582PACKAGE_TARNAME='firejail' 582PACKAGE_TARNAME='firejail'
583PACKAGE_VERSION='0.9.65' 583PACKAGE_VERSION='0.9.66rc1'
584PACKAGE_STRING='firejail 0.9.65' 584PACKAGE_STRING='firejail 0.9.66rc1'
585PACKAGE_BUGREPORT='netblue30@protonmail.com' 585PACKAGE_BUGREPORT='netblue30@protonmail.com'
586PACKAGE_URL='https://firejail.wordpress.com' 586PACKAGE_URL='https://firejail.wordpress.com'
587 587
@@ -1299,7 +1299,7 @@ if test "$ac_init_help" = "long"; then
1299 # Omit some internal or obsolete options to make the list less imposing. 1299 # Omit some internal or obsolete options to make the list less imposing.
1300 # This message is too long to be a string in the A/UX 3.1 sh. 1300 # This message is too long to be a string in the A/UX 3.1 sh.
1301 cat <<_ACEOF 1301 cat <<_ACEOF
1302\`configure' configures firejail 0.9.65 to adapt to many kinds of systems. 1302\`configure' configures firejail 0.9.66rc1 to adapt to many kinds of systems.
1303 1303
1304Usage: $0 [OPTION]... [VAR=VALUE]... 1304Usage: $0 [OPTION]... [VAR=VALUE]...
1305 1305
@@ -1361,7 +1361,7 @@ fi
1361 1361
1362if test -n "$ac_init_help"; then 1362if test -n "$ac_init_help"; then
1363 case $ac_init_help in 1363 case $ac_init_help in
1364 short | recursive ) echo "Configuration of firejail 0.9.65:";; 1364 short | recursive ) echo "Configuration of firejail 0.9.66rc1:";;
1365 esac 1365 esac
1366 cat <<\_ACEOF 1366 cat <<\_ACEOF
1367 1367
@@ -1481,7 +1481,7 @@ fi
1481test -n "$ac_init_help" && exit $ac_status 1481test -n "$ac_init_help" && exit $ac_status
1482if $ac_init_version; then 1482if $ac_init_version; then
1483 cat <<\_ACEOF 1483 cat <<\_ACEOF
1484firejail configure 0.9.65 1484firejail configure 0.9.66rc1
1485generated by GNU Autoconf 2.69 1485generated by GNU Autoconf 2.69
1486 1486
1487Copyright (C) 2012 Free Software Foundation, Inc. 1487Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1783,7 +1783,7 @@ cat >config.log <<_ACEOF
1783This file contains any messages produced by compilers while 1783This file contains any messages produced by compilers while
1784running configure, to aid debugging if configure makes a mistake. 1784running configure, to aid debugging if configure makes a mistake.
1785 1785
1786It was created by firejail $as_me 0.9.65, which was 1786It was created by firejail $as_me 0.9.66rc1, which was
1787generated by GNU Autoconf 2.69. Invocation command line was 1787generated by GNU Autoconf 2.69. Invocation command line was
1788 1788
1789 $ $0 $@ 1789 $ $0 $@
@@ -4910,7 +4910,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
4910# report actual input values of CONFIG_FILES etc. instead of their 4910# report actual input values of CONFIG_FILES etc. instead of their
4911# values after options handling. 4911# values after options handling.
4912ac_log=" 4912ac_log="
4913This file was extended by firejail $as_me 0.9.65, which was 4913This file was extended by firejail $as_me 0.9.66rc1, which was
4914generated by GNU Autoconf 2.69. Invocation command line was 4914generated by GNU Autoconf 2.69. Invocation command line was
4915 4915
4916 CONFIG_FILES = $CONFIG_FILES 4916 CONFIG_FILES = $CONFIG_FILES
@@ -4964,7 +4964,7 @@ _ACEOF
4964cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 4964cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
4965ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" 4965ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
4966ac_cs_version="\\ 4966ac_cs_version="\\
4967firejail config.status 0.9.65 4967firejail config.status 0.9.66rc1
4968configured by $0, generated by GNU Autoconf 2.69, 4968configured by $0, generated by GNU Autoconf 2.69,
4969 with options \\"\$ac_cs_config\\" 4969 with options \\"\$ac_cs_config\\"
4970 4970
@@ -5560,47 +5560,49 @@ $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
5560fi 5560fi
5561 5561
5562 5562
5563echo 5563cat <<EOF
5564echo "Configuration options:" 5564
5565echo " prefix: $prefix" 5565Configuration options:
5566echo " sysconfdir: $sysconfdir" 5566 prefix: $prefix
5567echo " apparmor: $HAVE_APPARMOR" 5567 sysconfdir: $sysconfdir
5568echo " SELinux labeling support: $HAVE_SELINUX" 5568 apparmor: $HAVE_APPARMOR
5569echo " global config: $HAVE_GLOBALCFG" 5569 SELinux labeling support: $HAVE_SELINUX
5570echo " chroot: $HAVE_CHROOT" 5570 global config: $HAVE_GLOBALCFG
5571echo " network: $HAVE_NETWORK" 5571 chroot: $HAVE_CHROOT
5572echo " user namespace: $HAVE_USERNS" 5572 network: $HAVE_NETWORK
5573echo " X11 sandboxing support: $HAVE_X11" 5573 user namespace: $HAVE_USERNS
5574echo " whitelisting: $HAVE_WHITELIST" 5574 X11 sandboxing support: $HAVE_X11
5575echo " private home support: $HAVE_PRIVATE_HOME" 5575 whitelisting: $HAVE_WHITELIST
5576echo " file transfer support: $HAVE_FILE_TRANSFER" 5576 private home support: $HAVE_PRIVATE_HOME
5577echo " overlayfs support: $HAVE_OVERLAYFS" 5577 file transfer support: $HAVE_FILE_TRANSFER
5578echo " DBUS proxy support: $HAVE_DBUSPROXY" 5578 overlayfs support: $HAVE_OVERLAYFS
5579echo " allow tmpfs as regular user: $HAVE_USERTMPFS" 5579 DBUS proxy support: $HAVE_DBUSPROXY
5580echo " enable --ouput logging: $HAVE_OUTPUT" 5580 allow tmpfs as regular user: $HAVE_USERTMPFS
5581echo " Manpage support: $HAVE_MAN" 5581 enable --ouput logging: $HAVE_OUTPUT
5582echo " firetunnel support: $HAVE_FIRETUNNEL" 5582 Manpage support: $HAVE_MAN
5583echo " busybox workaround: $BUSYBOX_WORKAROUND" 5583 firetunnel support: $HAVE_FIRETUNNEL
5584echo " Spectre compiler patch: $HAVE_SPECTRE" 5584 busybox workaround: $BUSYBOX_WORKAROUND
5585echo " EXTRA_LDFLAGS: $EXTRA_LDFLAGS" 5585 Spectre compiler patch: $HAVE_SPECTRE
5586echo " EXTRA_CFLAGS: $EXTRA_CFLAGS" 5586 EXTRA_LDFLAGS: $EXTRA_LDFLAGS
5587echo " fatal warnings: $HAVE_FATAL_WARNINGS" 5587 EXTRA_CFLAGS: $EXTRA_CFLAGS
5588echo " Gcov instrumentation: $HAVE_GCOV" 5588 fatal warnings: $HAVE_FATAL_WARNINGS
5589echo " Install contrib scripts: $HAVE_CONTRIB_INSTALL" 5589 Gcov instrumentation: $HAVE_GCOV
5590echo " Install as a SUID executable: $HAVE_SUID" 5590 Install contrib scripts: $HAVE_CONTRIB_INSTALL
5591echo " LTS: $HAVE_LTS" 5591 Install as a SUID executable: $HAVE_SUID
5592echo " Always enforce filters: $HAVE_FORCE_NONEWPRIVS" 5592 LTS: $HAVE_LTS
5593echo 5593 Always enforce filters: $HAVE_FORCE_NONEWPRIVS
5594 5594
5595EOF
5595 5596
5596if test "$HAVE_LTS" = -DHAVE_LTS; then 5597if test "$HAVE_LTS" = -DHAVE_LTS; then
5597 echo 5598 cat <<\EOF
5598 echo 5599
5599 echo "*********************************************************"
5600 echo "* Warning: Long-term support (LTS) was enabled! *"
5601 echo "* Most compile-time options have bean rewritten! *"
5602 echo "*********************************************************"
5603 echo
5604 echo
5605fi
5606 5600
5601*********************************************************
5602* Warning: Long-term support (LTS) was enabled! *
5603* Most compile-time options have bean rewritten! *
5604*********************************************************
5605
5606
5607EOF
5608fi
diff --git a/configure.ac b/configure.ac
index 4af69766d..f37db5926 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,7 +12,7 @@
12# 12#
13 13
14AC_PREREQ([2.68]) 14AC_PREREQ([2.68])
15AC_INIT(firejail, 0.9.65, netblue30@protonmail.com, , https://firejail.wordpress.com) 15AC_INIT([firejail],[0.9.66rc1],[netblue30@protonmail.com],[],[https://firejail.wordpress.com])
16AC_CONFIG_SRCDIR([src/firejail/main.c]) 16AC_CONFIG_SRCDIR([src/firejail/main.c])
17 17
18AC_CONFIG_MACRO_DIR([m4]) 18AC_CONFIG_MACRO_DIR([m4])
@@ -304,53 +304,56 @@ if test "$prefix" = /usr; then
304fi 304fi
305 305
306AC_CONFIG_FILES([mkdeb.sh], [chmod +x mkdeb.sh]) 306AC_CONFIG_FILES([mkdeb.sh], [chmod +x mkdeb.sh])
307AC_OUTPUT(Makefile src/common.mk src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/fnetfilter/Makefile \ 307AC_CONFIG_FILES([Makefile src/common.mk src/lib/Makefile src/fcopy/Makefile src/fnet/Makefile src/firejail/Makefile src/fnetfilter/Makefile \
308src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/fbuilder/Makefile src/fsec-print/Makefile \ 308src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/fbuilder/Makefile src/fsec-print/Makefile \
309src/ftee/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile src/fsec-optimize/Makefile \ 309src/ftee/Makefile src/fseccomp/Makefile src/fldd/Makefile src/libpostexecseccomp/Makefile src/fsec-optimize/Makefile \
310src/profstats/Makefile src/man/Makefile src/zsh_completion/Makefile src/bash_completion/Makefile test/Makefile \ 310src/profstats/Makefile src/man/Makefile src/zsh_completion/Makefile src/bash_completion/Makefile test/Makefile \
311src/jailcheck/Makefile) 311src/jailcheck/Makefile])
312 312AC_OUTPUT
313echo 313
314echo "Configuration options:" 314cat <<EOF
315echo " prefix: $prefix" 315
316echo " sysconfdir: $sysconfdir" 316Configuration options:
317echo " apparmor: $HAVE_APPARMOR" 317 prefix: $prefix
318echo " SELinux labeling support: $HAVE_SELINUX" 318 sysconfdir: $sysconfdir
319echo " global config: $HAVE_GLOBALCFG" 319 apparmor: $HAVE_APPARMOR
320echo " chroot: $HAVE_CHROOT" 320 SELinux labeling support: $HAVE_SELINUX
321echo " network: $HAVE_NETWORK" 321 global config: $HAVE_GLOBALCFG
322echo " user namespace: $HAVE_USERNS" 322 chroot: $HAVE_CHROOT
323echo " X11 sandboxing support: $HAVE_X11" 323 network: $HAVE_NETWORK
324echo " whitelisting: $HAVE_WHITELIST" 324 user namespace: $HAVE_USERNS
325echo " private home support: $HAVE_PRIVATE_HOME" 325 X11 sandboxing support: $HAVE_X11
326echo " file transfer support: $HAVE_FILE_TRANSFER" 326 whitelisting: $HAVE_WHITELIST
327echo " overlayfs support: $HAVE_OVERLAYFS" 327 private home support: $HAVE_PRIVATE_HOME
328echo " DBUS proxy support: $HAVE_DBUSPROXY" 328 file transfer support: $HAVE_FILE_TRANSFER
329echo " allow tmpfs as regular user: $HAVE_USERTMPFS" 329 overlayfs support: $HAVE_OVERLAYFS
330echo " enable --ouput logging: $HAVE_OUTPUT" 330 DBUS proxy support: $HAVE_DBUSPROXY
331echo " Manpage support: $HAVE_MAN" 331 allow tmpfs as regular user: $HAVE_USERTMPFS
332echo " firetunnel support: $HAVE_FIRETUNNEL" 332 enable --ouput logging: $HAVE_OUTPUT
333echo " busybox workaround: $BUSYBOX_WORKAROUND" 333 Manpage support: $HAVE_MAN
334echo " Spectre compiler patch: $HAVE_SPECTRE" 334 firetunnel support: $HAVE_FIRETUNNEL
335echo " EXTRA_LDFLAGS: $EXTRA_LDFLAGS" 335 busybox workaround: $BUSYBOX_WORKAROUND
336echo " EXTRA_CFLAGS: $EXTRA_CFLAGS" 336 Spectre compiler patch: $HAVE_SPECTRE
337echo " fatal warnings: $HAVE_FATAL_WARNINGS" 337 EXTRA_LDFLAGS: $EXTRA_LDFLAGS
338echo " Gcov instrumentation: $HAVE_GCOV" 338 EXTRA_CFLAGS: $EXTRA_CFLAGS
339echo " Install contrib scripts: $HAVE_CONTRIB_INSTALL" 339 fatal warnings: $HAVE_FATAL_WARNINGS
340echo " Install as a SUID executable: $HAVE_SUID" 340 Gcov instrumentation: $HAVE_GCOV
341echo " LTS: $HAVE_LTS" 341 Install contrib scripts: $HAVE_CONTRIB_INSTALL
342echo " Always enforce filters: $HAVE_FORCE_NONEWPRIVS" 342 Install as a SUID executable: $HAVE_SUID
343echo 343 LTS: $HAVE_LTS
344 344 Always enforce filters: $HAVE_FORCE_NONEWPRIVS
345
346EOF
345 347
346if test "$HAVE_LTS" = -DHAVE_LTS; then 348if test "$HAVE_LTS" = -DHAVE_LTS; then
347 echo 349 cat <<\EOF
348 echo 350
349 echo "*********************************************************"
350 echo "* Warning: Long-term support (LTS) was enabled! *"
351 echo "* Most compile-time options have bean rewritten! *"
352 echo "*********************************************************"
353 echo
354 echo
355fi
356 351
352*********************************************************
353* Warning: Long-term support (LTS) was enabled! *
354* Most compile-time options have bean rewritten! *
355*********************************************************
356
357
358EOF
359fi
diff --git a/contrib/jail_prober.py b/contrib/jail_prober.py
index 9205d9b3e..f89f97ac4 100755
--- a/contrib/jail_prober.py
+++ b/contrib/jail_prober.py
@@ -70,6 +70,19 @@ def get_args(profile_path):
70 return profile 70 return profile
71 71
72 72
73def absolute_include(word):
74 home = os.environ['HOME']
75 path = home + '/.config/firejail/'
76
77 option, filename = word.split('=')
78 absolute_filename = path + filename
79
80 if not os.path.isfile(absolute_filename):
81 absolute_filename = '${CFG}/' + filename
82
83 return option + '=' + absolute_filename
84
85
73def arg_converter(arg_list, style): 86def arg_converter(arg_list, style):
74 """ 87 """
75 Convert between firejail command-line arguments (--example=something) and 88 Convert between firejail command-line arguments (--example=something) and
@@ -94,9 +107,12 @@ def arg_converter(arg_list, style):
94 if style == 'to_profile': 107 if style == 'to_profile':
95 new_args = [word[2:] for word in new_args] 108 new_args = [word[2:] for word in new_args]
96 109
97 # Remove invalid '--include' args if converting to command-line form
98 elif style == 'to_commandline': 110 elif style == 'to_commandline':
99 new_args = [word for word in new_args if 'include' not in word] 111 new_args = [
112 absolute_include(word) if word.startswith('--include')
113 else word
114 for word in new_args
115 ]
100 116
101 return new_args 117 return new_args
102 118
@@ -148,8 +164,12 @@ def run_firejail(program, all_args):
148 164
149 165
150def main(): 166def main():
151 profile_path = sys.argv[1] 167 try:
152 program = sys.argv[2] 168 profile_path = sys.argv[1]
169 program = sys.argv[2]
170 except IndexError:
171 print('USAGE: jail_prober.py <PROFILE-PATH> <PROGRAM>')
172 sys.exit()
153 # Quick error check and extract arguments 173 # Quick error check and extract arguments
154 check_params(profile_path) 174 check_params(profile_path)
155 profile = get_args(profile_path) 175 profile = get_args(profile_path)
diff --git a/contrib/vim/ftdetect/firejail.vim b/contrib/vim/ftdetect/firejail.vim
index a8ba5cd75..2edc741da 100644
--- a/contrib/vim/ftdetect/firejail.vim
+++ b/contrib/vim/ftdetect/firejail.vim
@@ -1,6 +1,6 @@
1autocmd BufNewFile,BufRead /etc/firejail/*.profile set filetype=firejail 1autocmd BufNewFile,BufRead /etc/firejail/*.profile setfiletype firejail
2autocmd BufNewFile,BufRead /etc/firejail/*.local set filetype=firejail 2autocmd BufNewFile,BufRead /etc/firejail/*.local setfiletype firejail
3autocmd BufNewFile,BufRead /etc/firejail/*.inc set filetype=firejail 3autocmd BufNewFile,BufRead /etc/firejail/*.inc setfiletype firejail
4autocmd BufNewFile,BufRead ~/.config/firejail/*.profile set filetype=firejail 4autocmd BufNewFile,BufRead ~/.config/firejail/*.profile setfiletype firejail
5autocmd BufNewFile,BufRead ~/.config/firejail/*.local set filetype=firejail 5autocmd BufNewFile,BufRead ~/.config/firejail/*.local setfiletype firejail
6autocmd BufNewFile,BufRead ~/.config/firejail/*.inc set filetype=firejail 6autocmd BufNewFile,BufRead ~/.config/firejail/*.inc setfiletype firejail
diff --git a/contrib/vim/syntax/firejail.vim b/contrib/vim/syntax/firejail.vim
index 8775ae71d..d07690ee2 100644
--- a/contrib/vim/syntax/firejail.vim
+++ b/contrib/vim/syntax/firejail.vim
@@ -20,19 +20,20 @@ syn match fjCapabilityList /,/ nextgroup=fjCapability contained
20syn keyword fjProtocol unix inet inet6 netlink packet nextgroup=fjProtocolList contained 20syn keyword fjProtocol unix inet inet6 netlink packet nextgroup=fjProtocolList contained
21syn match fjProtocolList /,/ nextgroup=fjProtocol contained 21syn match fjProtocolList /,/ nextgroup=fjProtocol contained
22 22
23" Syscalls grabbed from: src/include/syscall.h 23" Syscalls grabbed from: src/include/syscall*.h
24" Generate list with: rg -o '"([^"]+)' -r '$1' src/include/syscall.h | sort -u | tr $'\n' ' ' 24" Generate list with: sed -ne 's/{\s\+"\([^"]\+\)",.*},/\1/p' src/include/syscall*.h | sort -u | tr $'\n' ' '
25syn keyword fjSyscall _llseek _newselect _sysctl accept accept4 access acct add_key adjtimex afs_syscall alarm arch_prctl bdflush bind bpf break brk capget capset chdir chmod chown chown32 chroot clock_adjtime clock_getres clock_gettime clock_nanosleep clock_settime clone close connect copy_file_range creat create_module delete_module dup dup2 dup3 epoll_create epoll_create1 epoll_ctl epoll_ctl_old epoll_pwait epoll_wait epoll_wait_old eventfd eventfd2 execve execveat exit exit_group faccessat faccessat2 fadvise64 fadvise64_64 fallocate fanotify_init fanotify_mark fchdir fchmod fchmodat fchown fchown32 fchownat fcntl fcntl64 fdatasync fgetxattr finit_module flistxattr flock fork fremovexattr fsetxattr fstat fstat64 fstatat64 fstatfs fstatfs64 fsync ftime ftruncate ftruncate64 futex futimesat get_kernel_syms get_mempolicy get_robust_list get_thread_area getcpu getcwd getdents getdents64 getegid getegid32 geteuid geteuid32 getgid getgid32 getgroups getgroups32 getitimer getpeername getpgid getpgrp getpid getpmsg getppid getpriority getrandom getresgid getresgid32 getresuid getresuid32 getrlimit getrusage getsid getsockname getsockopt gettid gettimeofday getuid getuid32 getxattr gtty idle init_module inotify_add_watch inotify_init inotify_init1 inotify_rm_watch io_cancel io_destroy io_getevents io_setup io_submit ioctl ioperm iopl ioprio_get ioprio_set ipc kcmp kexec_file_load kexec_load keyctl kill lchown lchown32 lgetxattr link linkat listen listxattr llistxattr lock lookup_dcookie lremovexattr lseek lsetxattr lstat lstat64 madvise mbind membarrier memfd_create migrate_pages mincore mkdir mkdirat mknod mknodat mlock mlock2 mlockall mmap mmap2 modify_ldt mount move_pages mprotect mpx mq_getsetattr mq_notify mq_open mq_timedreceive mq_timedsend mq_unlink mremap msgctl msgget msgrcv msgsnd msync munlock munlockall munmap name_to_handle_at nanosleep newfstatat nfsservctl nice oldfstat oldlstat oldolduname oldstat olduname open open_by_handle_at openat pause perf_event_open personality pipe pipe2 pivot_root pkey_alloc pkey_free pkey_mprotect poll ppoll prctl pread64 preadv preadv2 prlimit64 process_vm_readv process_vm_writev prof profil pselect6 ptrace putpmsg pwrite64 pwritev pwritev2 query_module quotactl read readahead readdir readlink readlinkat readv reboot recvfrom recvmmsg recvmsg remap_file_pages removexattr rename renameat renameat2 request_key restart_syscall rmdir rt_sigaction rt_sigpending rt_sigprocmask rt_sigqueueinfo rt_sigreturn rt_sigsuspend rt_sigtimedwait rt_tgsigqueueinfo sched_get_priority_max sched_get_priority_min sched_getaffinity sched_getattr sched_getparam sched_getscheduler sched_rr_get_interval sched_setaffinity sched_setattr sched_setparam sched_setscheduler sched_yield seccomp security select semctl semget semop semtimedop sendfile sendfile64 sendmmsg sendmsg sendto set_mempolicy set_robust_list set_thread_area set_tid_address setdomainname setfsgid setfsgid32 setfsuid setfsuid32 setgid setgid32 setgroups setgroups32 sethostname setitimer setns setpgid setpriority setregid setregid32 setresgid setresgid32 setresuid setresuid32 setreuid setreuid32 setrlimit setsid setsockopt settimeofday setuid setuid32 setxattr sgetmask shmat shmctl shmdt shmget shutdown sigaction sigaltstack signal signalfd signalfd4 sigpending sigprocmask sigreturn sigsuspend socket socketcall socketpair splice ssetmask stat stat64 statfs statfs64 statx stime stty swapoff swapon symlink symlinkat sync sync_file_range syncfs sysfs sysinfo syslog tee tgkill time timer_create timer_delete timer_getoverrun timer_gettime timer_settime timerfd_create timerfd_gettime timerfd_settime times tkill truncate truncate64 tuxcall ugetrlimit ulimit umask umount umount2 uname unlink unlinkat unshare uselib userfaultfd ustat utime utimensat utimes vfork vhangup vm86 vm86old vmsplice vserver wait4 waitid waitpid write writev nextgroup=fjSyscallErrno contained 25syn keyword fjSyscall _llseek _newselect _sysctl accept accept4 access acct add_key adjtimex afs_syscall alarm arch_prctl arm_fadvise64_64 arm_sync_file_range bdflush bind bpf break brk capget capset chdir chmod chown chown32 chroot clock_adjtime clock_adjtime64 clock_getres clock_getres_time64 clock_gettime clock_gettime64 clock_nanosleep clock_nanosleep_time64 clock_settime clock_settime64 clone clone3 close connect copy_file_range creat create_module delete_module dup dup2 dup3 epoll_create epoll_create1 epoll_ctl epoll_ctl_old epoll_pwait epoll_wait epoll_wait_old eventfd eventfd2 execve execveat exit exit_group faccessat faccessat2 fadvise64 fadvise64_64 fallocate fanotify_init fanotify_mark fchdir fchmod fchmodat fchown fchown32 fchownat fcntl fcntl64 fdatasync fgetxattr finit_module flistxattr flock fork fremovexattr fsconfig fsetxattr fsmount fsopen fspick fstat fstat64 fstatat64 fstatfs fstatfs64 fsync ftime ftruncate ftruncate64 futex futex_time64 futimesat getcpu getcwd getdents getdents64 getegid getegid32 geteuid geteuid32 getgid getgid32 getgroups getgroups32 getitimer get_kernel_syms get_mempolicy getpeername getpgid getpgrp getpid getpmsg getppid getpriority getrandom getresgid getresgid32 getresuid getresuid32 getrlimit get_robust_list getrusage getsid getsockname getsockopt get_thread_area gettid gettimeofday getuid getuid32 getxattr gtty idle init_module inotify_add_watch inotify_init inotify_init1 inotify_rm_watch io_cancel ioctl io_destroy io_getevents ioperm io_pgetevents io_pgetevents_time64 iopl ioprio_get ioprio_set io_setup io_submit io_uring_enter io_uring_register io_uring_setup ipc kcmp kexec_file_load kexec_load keyctl kill lchown lchown32 lgetxattr link linkat listen listxattr llistxattr lock lookup_dcookie lremovexattr lseek lsetxattr lstat lstat64 madvise mbind membarrier memfd_create migrate_pages mincore mkdir mkdirat mknod mknodat mlock mlock2 mlockall mmap mmap2 modify_ldt mount move_mount move_pages mprotect mpx mq_getsetattr mq_notify mq_open mq_timedreceive mq_timedreceive_time64 mq_timedsend mq_timedsend_time64 mq_unlink mremap msgctl msgget msgrcv msgsnd msync munlock munlockall munmap name_to_handle_at nanosleep newfstatat nfsservctl nice oldfstat oldlstat oldolduname oldstat olduname open openat open_by_handle_at open_tree pause pciconfig_iobase pciconfig_read pciconfig_write perf_event_open personality pidfd_open pidfd_send_signal pipe pipe2 pivot_root pkey_alloc pkey_free pkey_mprotect poll ppoll ppoll_time64 prctl pread64 preadv preadv2 prlimit64 process_vm_readv process_vm_writev prof profil pselect6 pselect6_time64 ptrace putpmsg pwrite64 pwritev pwritev2 query_module quotactl read readahead readdir readlink readlinkat readv reboot recv recvfrom recvmmsg recvmmsg_time64 recvmsg remap_file_pages removexattr rename renameat renameat2 request_key restart_syscall rmdir rseq rt_sigaction rt_sigpending rt_sigprocmask rt_sigqueueinfo rt_sigreturn rt_sigsuspend rt_sigtimedwait rt_sigtimedwait_time64 rt_tgsigqueueinfo sched_getaffinity sched_getattr sched_getparam sched_get_priority_max sched_get_priority_min sched_getscheduler sched_rr_get_interval sched_rr_get_interval_time64 sched_setaffinity sched_setattr sched_setparam sched_setscheduler sched_yield seccomp security select semctl semget semop semtimedop semtimedop_time64 send sendfile sendfile64 sendmmsg sendmsg sendto setdomainname setfsgid setfsgid32 setfsuid setfsuid32 setgid setgid32 setgroups setgroups32 sethostname setitimer set_mempolicy setns setpgid setpriority setregid setregid32 setresgid setresgid32 setresuid setresuid32 setreuid setreuid32 setrlimit set_robust_list setsid setsockopt set_thread_area set_tid_address settimeofday setuid setuid32 setxattr sgetmask shmat shmctl shmdt shmget shutdown sigaction sigaltstack signal signalfd signalfd4 sigpending sigprocmask sigreturn sigsuspend socket socketcall socketpair splice ssetmask stat stat64 statfs statfs64 statx stime stty swapoff swapon symlink symlinkat sync sync_file_range sync_file_range2 syncfs syscall sysfs sysinfo syslog tee tgkill time timer_create timer_delete timerfd_create timerfd_gettime timerfd_gettime64 timerfd_settime timerfd_settime64 timer_getoverrun timer_gettime timer_gettime64 timer_settime timer_settime64 times tkill truncate truncate64 tuxcall ugetrlimit ulimit umask umount umount2 uname unlink unlinkat unshare uselib userfaultfd ustat utime utimensat utimensat_time64 utimes vfork vhangup vm86 vm86old vmsplice vserver wait4 waitid waitpid write writev nextgroup=fjSyscallErrno contained
26" Syscall groups grabbed from: src/fseccomp/syscall.c 26" Syscall groups grabbed from: src/fseccomp/syscall.c
27" Generate list with: rg -o '"@([^",]+)' -r '$1' src/fseccomp/syscall.c | sort -u | tr $'\n' '|' 27" Generate list with: rg -o '"@([^",]+)' -r '$1' src/lib/syscall.c | sort -u | tr $'\n' '|'
28syn match fjSyscall /\v\@(clock|cpu-emulation|debug|default|default-keep|default-nodebuggers|module|obsolete|privileged|raw-io|reboot|resources|swap)>/ nextgroup=fjSyscallErrno contained 28syn match fjSyscall /\v\@(aio|basic-io|chown|clock|cpu-emulation|debug|default|default-keep|default-nodebuggers|file-system|io-event|ipc|keyring|memlock|module|mount|network-io|obsolete|privileged|process|raw-io|reboot|resources|setuid|signal|swap|sync|system-service|timer)>/ nextgroup=fjSyscallErrno contained
29syn match fjSyscall /\$[0-9]\+/ nextgroup=fjSyscallErrno contained 29syn match fjSyscall /\$[0-9]\+/ nextgroup=fjSyscallErrno contained
30" Errnos grabbed from: src/fseccomp/errno.c 30" Errnos grabbed from: src/fseccomp/errno.c
31" Generate list with: rg -o '"(E[^"]+)' -r '$1' src/fseccomp/errno.c | sort -u | tr $'\n' '|' 31" Generate list with: rg -o '"(E[^"]+)' -r '$1' src/lib/errno.c | sort -u | tr $'\n' '|'
32syn match fjSyscallErrno /\v(:(E2BIG|EACCES|EADDRINUSE|EADDRNOTAVAIL|EADV|EAFNOSUPPORT|EAGAIN|EALREADY|EBADE|EBADF|EBADFD|EBADMSG|EBADR|EBADRQC|EBADSLT|EBFONT|EBUSY|ECANCELED|ECHILD|ECHRNG|ECOMM|ECONNABORTED|ECONNREFUSED|ECONNRESET|EDEADLK|EDEADLOCK|EDESTADDRREQ|EDOM|EDOTDOT|EDQUOT|EEXIST|EFAULT|EFBIG|EHOSTDOWN|EHOSTUNREACH|EHWPOISON|EIDRM|EILSEQ|EINPROGRESS|EINTR|EINVAL|EIO|EISCONN|EISDIR|EISNAM|EKEYEXPIRED|EKEYREJECTED|EKEYREVOKED|EL2HLT|EL2NSYNC|EL3HLT|EL3RST|ELIBACC|ELIBBAD|ELIBEXEC|ELIBMAX|ELIBSCN|ELNRNG|ELOOP|EMEDIUMTYPE|EMFILE|EMLINK|EMSGSIZE|EMULTIHOP|ENAMETOOLONG|ENAVAIL|ENETDOWN|ENETRESET|ENETUNREACH|ENFILE|ENOANO|ENOATTR|ENOBUFS|ENOCSI|ENODATA|ENODEV|ENOENT|ENOEXEC|ENOKEY|ENOLCK|ENOLINK|ENOMEDIUM|ENOMEM|ENOMSG|ENONET|ENOPKG|ENOPROTOOPT|ENOSPC|ENOSR|ENOSTR|ENOSYS|ENOTBLK|ENOTCONN|ENOTDIR|ENOTEMPTY|ENOTNAM|ENOTRECOVERABLE|ENOTSOCK|ENOTSUP|ENOTTY|ENOTUNIQ|ENXIO|EOPNOTSUPP|EOVERFLOW|EOWNERDEAD|EPERM|EPFNOSUPPORT|EPIPE|EPROTO|EPROTONOSUPPORT|EPROTOTYPE|ERANGE|EREMCHG|EREMOTE|EREMOTEIO|ERESTART|ERFKILL|EROFS|ESHUTDOWN|ESOCKTNOSUPPORT|ESPIPE|ESRCH|ESRMNT|ESTALE|ESTRPIPE|ETIME|ETIMEDOUT|ETOOMANYREFS|ETXTBSY|EUCLEAN|EUNATCH|EUSERS|EWOULDBLOCK|EXDEV|EXFULL)>)?/ nextgroup=fjSyscallList contained 32syn match fjSyscallErrno /\v(:(E2BIG|EACCES|EADDRINUSE|EADDRNOTAVAIL|EADV|EAFNOSUPPORT|EAGAIN|EALREADY|EBADE|EBADF|EBADFD|EBADMSG|EBADR|EBADRQC|EBADSLT|EBFONT|EBUSY|ECANCELED|ECHILD|ECHRNG|ECOMM|ECONNABORTED|ECONNREFUSED|ECONNRESET|EDEADLK|EDEADLOCK|EDESTADDRREQ|EDOM|EDOTDOT|EDQUOT|EEXIST|EFAULT|EFBIG|EHOSTDOWN|EHOSTUNREACH|EHWPOISON|EIDRM|EILSEQ|EINPROGRESS|EINTR|EINVAL|EIO|EISCONN|EISDIR|EISNAM|EKEYEXPIRED|EKEYREJECTED|EKEYREVOKED|EL2HLT|EL2NSYNC|EL3HLT|EL3RST|ELIBACC|ELIBBAD|ELIBEXEC|ELIBMAX|ELIBSCN|ELNRNG|ELOOP|EMEDIUMTYPE|EMFILE|EMLINK|EMSGSIZE|EMULTIHOP|ENAMETOOLONG|ENAVAIL|ENETDOWN|ENETRESET|ENETUNREACH|ENFILE|ENOANO|ENOATTR|ENOBUFS|ENOCSI|ENODATA|ENODEV|ENOENT|ENOEXEC|ENOKEY|ENOLCK|ENOLINK|ENOMEDIUM|ENOMEM|ENOMSG|ENONET|ENOPKG|ENOPROTOOPT|ENOSPC|ENOSR|ENOSTR|ENOSYS|ENOTBLK|ENOTCONN|ENOTDIR|ENOTEMPTY|ENOTNAM|ENOTRECOVERABLE|ENOTSOCK|ENOTSUP|ENOTTY|ENOTUNIQ|ENXIO|EOPNOTSUPP|EOVERFLOW|EOWNERDEAD|EPERM|EPFNOSUPPORT|EPIPE|EPROTO|EPROTONOSUPPORT|EPROTOTYPE|ERANGE|EREMCHG|EREMOTE|EREMOTEIO|ERESTART|ERFKILL|EROFS|ESHUTDOWN|ESOCKTNOSUPPORT|ESPIPE|ESRCH|ESRMNT|ESTALE|ESTRPIPE|ETIME|ETIMEDOUT|ETOOMANYREFS|ETXTBSY|EUCLEAN|EUNATCH|EUSERS|EWOULDBLOCK|EXDEV|EXFULL)>)?/ nextgroup=fjSyscallList contained
33syn match fjSyscallList /,/ nextgroup=fjSyscall contained 33syn match fjSyscallList /,/ nextgroup=fjSyscall contained
34 34
35syn keyword fjX11Sandbox none xephyr xorg xpra xvfb contained 35syn keyword fjX11Sandbox none xephyr xorg xpra xvfb contained
36syn keyword fjSeccompAction kill log ERRNO contained
36 37
37syn match fjEnvVar "[A-Za-z0-9_]\+=" contained 38syn match fjEnvVar "[A-Za-z0-9_]\+=" contained
38syn match fjRmenvVar "[A-Za-z0-9_]\+" contained 39syn match fjRmenvVar "[A-Za-z0-9_]\+" contained
@@ -40,6 +41,7 @@ syn match fjRmenvVar "[A-Za-z0-9_]\+" contained
40syn keyword fjAll all contained 41syn keyword fjAll all contained
41syn keyword fjNone none contained 42syn keyword fjNone none contained
42syn keyword fjLo lo contained 43syn keyword fjLo lo contained
44syn keyword fjFilter filter contained
43 45
44" Variable names grabbed from: src/firejail/macros.c 46" Variable names grabbed from: src/firejail/macros.c
45" Generate list with: rg -o '\$\{([^}]+)\}' -r '$1' src/firejail/macros.c | sort -u | tr $'\n' '|' 47" Generate list with: rg -o '\$\{([^}]+)\}' -r '$1' src/firejail/macros.c | sort -u | tr $'\n' '|'
@@ -47,27 +49,30 @@ syn match fjVar /\v\$\{(CFG|DESKTOP|DOCUMENTS|DOWNLOADS|HOME|MUSIC|PATH|PICTURES
47 49
48" Commands grabbed from: src/firejail/profile.c 50" Commands grabbed from: src/firejail/profile.c
49" Generate list with: { rg -o 'strn?cmp\(ptr, "([^"]+) "' -r '$1' src/firejail/profile.c; echo private-lib; } | grep -vEx '(include|ignore|caps\.drop|caps\.keep|protocol|seccomp|seccomp\.drop|seccomp\.keep|env|rmenv|net|ip)' | sort -u | tr $'\n' '|' # private-lib is special-cased in the code and doesn't match the regex; grep-ed patterns are handled later with 'syn match nextgroup=' directives (except for include which is special-cased as a fjCommandNoCond keyword) 51" Generate list with: { rg -o 'strn?cmp\(ptr, "([^"]+) "' -r '$1' src/firejail/profile.c; echo private-lib; } | grep -vEx '(include|ignore|caps\.drop|caps\.keep|protocol|seccomp|seccomp\.drop|seccomp\.keep|env|rmenv|net|ip)' | sort -u | tr $'\n' '|' # private-lib is special-cased in the code and doesn't match the regex; grep-ed patterns are handled later with 'syn match nextgroup=' directives (except for include which is special-cased as a fjCommandNoCond keyword)
50syn match fjCommand /\v(bind|blacklist|blacklist-nolog|cgroup|cpu|defaultgw|dns|hostname|hosts-file|ip6|iprange|join-or-start|mac|mkdir|mkfile|mtu|name|netfilter|netfilter6|netmask|nice|noblacklist|noexec|nowhitelist|overlay-named|private|private-bin|private-etc|private-home|private-lib|private-opt|private-srv|read-only|read-write|rlimit-as|rlimit-cpu|rlimit-fsize|rlimit-nofile|rlimit-nproc|rlimit-sigpending|timeout|tmpfs|veth-name|whitelist|xephyr-screen) / skipwhite contained 52syn match fjCommand /\v(bind|blacklist|blacklist-nolog|cgroup|cpu|defaultgw|dns|hostname|hosts-file|ip6|iprange|join-or-start|mac|mkdir|mkfile|mtu|name|netfilter|netfilter6|netmask|nice|noblacklist|noexec|nowhitelist|overlay-named|private|private-bin|private-cwd|private-etc|private-home|private-lib|private-opt|private-srv|read-only|read-write|rlimit-as|rlimit-cpu|rlimit-fsize|rlimit-nofile|rlimit-nproc|rlimit-sigpending|timeout|tmpfs|veth-name|whitelist|xephyr-screen) / skipwhite contained
51" Generate list with: rg -o 'strn?cmp\(ptr, "([^ "]*[^ ])"' -r '$1' src/firejail/profile.c | grep -vEx '(include|rlimit|quiet)' | sed -e 's/\./\\./' | sort -u | tr $'\n' '|' # include/rlimit are false positives, quiet is special-cased below 53" Generate list with: rg -o 'strn?cmp\(ptr, "([^ "]*[^ ])"' -r '$1' src/firejail/profile.c | grep -vEx '(include|rlimit|quiet)' | sed -e 's/\./\\./' | sort -u | tr $'\n' '|' # include/rlimit are false positives, quiet is special-cased below
52syn match fjCommand /\v(allusers|apparmor|caps|disable-mnt|ipc-namespace|keep-config-pulse|keep-dev-shm|keep-var-tmp|machine-id|memory-deny-write-execute|netfilter|no3d|noautopulse|nodbus|nodvd|nogroups|noinput|nonewprivs|noroot|nosound|notv|nou2f|novideo|overlay|overlay-tmpfs|private|private-cache|private-dev|private-lib|private-tmp|seccomp|seccomp\.block-secondary|tracelog|writable-etc|writable-run-user|writable-var|writable-var-log|x11)$/ contained 54syn match fjCommand /\v(allow-debuggers|allusers|apparmor|caps|disable-mnt|ipc-namespace|keep-config-pulse|keep-dev-shm|keep-var-tmp|machine-id|memory-deny-write-execute|netfilter|no3d|noautopulse|nodbus|nodvd|nogroups|noinput|nonewprivs|noroot|nosound|notv|nou2f|novideo|overlay|overlay-tmpfs|private|private-cache|private-cwd|private-dev|private-lib|private-tmp|seccomp|seccomp\.32|seccomp\.block-secondary|tracelog|writable-etc|writable-run-user|writable-var|writable-var-log|x11)$/ contained
53syn match fjCommand /ignore / nextgroup=fjCommand,fjCommandNoCond skipwhite contained 55syn match fjCommand /ignore / nextgroup=fjCommand,fjCommandNoCond skipwhite contained
54syn match fjCommand /caps\.drop / nextgroup=fjCapability,fjAll skipwhite contained 56syn match fjCommand /caps\.drop / nextgroup=fjCapability,fjAll skipwhite contained
55syn match fjCommand /caps\.keep / nextgroup=fjCapability skipwhite contained 57syn match fjCommand /caps\.keep / nextgroup=fjCapability skipwhite contained
56syn match fjCommand /protocol / nextgroup=fjProtocol skipwhite contained 58syn match fjCommand /protocol / nextgroup=fjProtocol skipwhite contained
57syn match fjCommand /\vseccomp(\.drop|\.keep)? / nextgroup=fjSyscall skipwhite contained 59syn match fjCommand /\vseccomp(\.32)?(\.drop|\.keep)? / nextgroup=fjSyscall skipwhite contained
58syn match fjCommand /x11 / nextgroup=fjX11Sandbox skipwhite contained 60syn match fjCommand /x11 / nextgroup=fjX11Sandbox skipwhite contained
59syn match fjCommand /env / nextgroup=fjEnvVar skipwhite contained 61syn match fjCommand /env / nextgroup=fjEnvVar skipwhite contained
60syn match fjCommand /rmenv / nextgroup=fjRmenvVar skipwhite contained 62syn match fjCommand /rmenv / nextgroup=fjRmenvVar skipwhite contained
61syn match fjCommand /shell / nextgroup=fjNone skipwhite contained 63syn match fjCommand /shell / nextgroup=fjNone skipwhite contained
62syn match fjCommand /net / nextgroup=fjNone,fjLo skipwhite contained 64syn match fjCommand /net / nextgroup=fjNone,fjLo skipwhite contained
63syn match fjCommand /ip / nextgroup=fjNone skipwhite contained 65syn match fjCommand /ip / nextgroup=fjNone skipwhite contained
66syn match fjCommand /seccomp-error-action / nextgroup=fjSeccompAction skipwhite contained
67syn match fjCommand /\vdbus-(user|system) / nextgroup=fjFilter,fjNone skipwhite contained
68syn match fjCommand /\vdbus-(user|system)\.(broadcast|call|own|see|talk) / skipwhite contained
64" Commands that can't be inside a ?CONDITIONAL: statement 69" Commands that can't be inside a ?CONDITIONAL: statement
65syn match fjCommandNoCond /include / skipwhite contained 70syn match fjCommandNoCond /include / skipwhite contained
66syn match fjCommandNoCond /quiet$/ contained 71syn match fjCommandNoCond /quiet$/ contained
67 72
68" Conditionals grabbed from: src/firejail/profile.c 73" Conditionals grabbed from: src/firejail/profile.c
69" Generate list with: awk -- 'BEGIN {process=0;} /^Cond conditionals\[\] = \{$/ {process=1;} /\t*\{"[^"]+".*/ { if (process) {print gensub(/^\t*\{"([^"]+)".*$/, "\\1", 1);} } /^\t\{ NULL, NULL \}$/ {process=0;}' src/firejail/profile.c | sort -u | tr $'\n' '|' 74" Generate list with: awk -- 'BEGIN {process=0;} /^Cond conditionals\[\] = \{$/ {process=1;} /\t*\{"[^"]+".*/ { if (process) {print gensub(/^\t*\{"([^"]+)".*$/, "\\1", 1);} } /^\t\{ NULL, NULL \}$/ {process=0;}' src/firejail/profile.c | sort -u | tr $'\n' '|'
70syn match fjConditional /\v\?(BROWSER_ALLOW_DRM|BROWSER_DISABLE_U2F|HAS_APPIMAGE|HAS_NODBUS) ?:/ nextgroup=fjCommand skipwhite contained 75syn match fjConditional /\v\?(BROWSER_ALLOW_DRM|BROWSER_DISABLE_U2F|HAS_APPIMAGE|HAS_NET|HAS_NODBUS|HAS_NOSOUND|HAS_X11) ?:/ nextgroup=fjCommand skipwhite contained
71 76
72" A line is either a command, a conditional or a comment 77" A line is either a command, a conditional or a comment
73syn match fjStatement /^/ nextgroup=fjCommand,fjCommandNoCond,fjConditional,fjComment 78syn match fjStatement /^/ nextgroup=fjCommand,fjCommandNoCond,fjConditional,fjComment
@@ -88,6 +93,8 @@ hi def link fjRmenvVar Type
88hi def link fjAll Type 93hi def link fjAll Type
89hi def link fjNone Type 94hi def link fjNone Type
90hi def link fjLo Type 95hi def link fjLo Type
96hi def link fjFilter Type
97hi def link fjSeccompAction Type
91 98
92 99
93let b:current_syntax = "firejail" 100let b:current_syntax = "firejail"
diff --git a/etc/firejail.config b/etc/firejail.config
index c671efef9..f5b3d5efa 100644
--- a/etc/firejail.config
+++ b/etc/firejail.config
@@ -35,11 +35,6 @@
35# cannot be overridden by --noblacklist or --ignore. 35# cannot be overridden by --noblacklist or --ignore.
36# disable-mnt no 36# disable-mnt no
37 37
38# Set the limit for file copy in several --private-* options. The size is set
39# in megabytes. By default we allow up to 500MB.
40# Note: the files are copied in RAM.
41# file-copy-limit 500
42
43# Enable or disable file transfer support, default enabled. 38# Enable or disable file transfer support, default enabled.
44# file-transfer yes 39# file-transfer yes
45 40
@@ -77,18 +72,35 @@
77# Enable or disable overlayfs features, default enabled. 72# Enable or disable overlayfs features, default enabled.
78# overlayfs yes 73# overlayfs yes
79 74
75# Set the limit for file copy in several --private-* options. The size is set
76# in megabytes. By default we allow up to 500MB.
77# Note: the files are copied in RAM.
78# file-copy-limit 500
79
80# Enable or disable private-bin feature, default enabled.
81# private-bin yes
82
80# Remove /usr/local directories from private-bin list, default disabled. 83# Remove /usr/local directories from private-bin list, default disabled.
81# private-bin-no-local no 84# private-bin-no-local no
82 85
83# Enable or disable private-cache feature, default enabled 86# Enable or disable private-cache feature, default enabled
84# private-cache yes 87# private-cache yes
85 88
89# Enable or disable private-etc feature, default enabled.
90# private-etc yes
91
86# Enable or disable private-home feature, default enabled 92# Enable or disable private-home feature, default enabled
87# private-home yes 93# private-home yes
88 94
89# Enable or disable private-lib feature, default enabled 95# Enable or disable private-lib feature, default enabled
90# private-lib yes 96# private-lib yes
91 97
98# Enable or disable private-opt feature, default enabled.
99# private-opt yes
100
101# Enable or disable private-srv feature, default enabled.
102# private-srv yes
103
92# Enable --quiet as default every time the sandbox is started. Default disabled. 104# Enable --quiet as default every time the sandbox is started. Default disabled.
93# quiet-by-default no 105# quiet-by-default no
94 106
diff --git a/etc/inc/disable-programs.inc b/etc/inc/disable-programs.inc
index 518587957..0e575e5eb 100644
--- a/etc/inc/disable-programs.inc
+++ b/etc/inc/disable-programs.inc
@@ -39,6 +39,8 @@ blacklist ${HOME}/.WebStorm*
39blacklist ${HOME}/.Wolfram Research 39blacklist ${HOME}/.Wolfram Research
40blacklist ${HOME}/.ZAP 40blacklist ${HOME}/.ZAP
41blacklist ${HOME}/.abook 41blacklist ${HOME}/.abook
42blacklist ${HOME}/.addressbook
43blacklist ${HOME}/.alpine-smime
42blacklist ${HOME}/.aMule 44blacklist ${HOME}/.aMule
43blacklist ${HOME}/.android 45blacklist ${HOME}/.android
44blacklist ${HOME}/.anydesk 46blacklist ${HOME}/.anydesk
@@ -589,6 +591,7 @@ blacklist ${HOME}/.kodi
589blacklist ${HOME}/.librewolf 591blacklist ${HOME}/.librewolf
590blacklist ${HOME}/.lincity-ng 592blacklist ${HOME}/.lincity-ng
591blacklist ${HOME}/.links 593blacklist ${HOME}/.links
594blacklist ${HOME}/.links2
592blacklist ${HOME}/.linphone-history.db 595blacklist ${HOME}/.linphone-history.db
593blacklist ${HOME}/.linphonerc 596blacklist ${HOME}/.linphonerc
594blacklist ${HOME}/.lmmsrc.xml 597blacklist ${HOME}/.lmmsrc.xml
@@ -809,6 +812,7 @@ blacklist ${HOME}/.netactview
809blacklist ${HOME}/.neverball 812blacklist ${HOME}/.neverball
810blacklist ${HOME}/.newsbeuter 813blacklist ${HOME}/.newsbeuter
811blacklist ${HOME}/.newsboat 814blacklist ${HOME}/.newsboat
815blacklist ${HOME}/.newsrc
812blacklist ${HOME}/.nicotine 816blacklist ${HOME}/.nicotine
813blacklist ${HOME}/.node-gyp 817blacklist ${HOME}/.node-gyp
814blacklist ${HOME}/.npm 818blacklist ${HOME}/.npm
@@ -829,6 +833,14 @@ blacklist ${HOME}/.paradoxinteractive
829blacklist ${HOME}/.parallelrealities/blobwars 833blacklist ${HOME}/.parallelrealities/blobwars
830blacklist ${HOME}/.pcsxr 834blacklist ${HOME}/.pcsxr
831blacklist ${HOME}/.penguin-command 835blacklist ${HOME}/.penguin-command
836blacklist ${HOME}/.pine-crash
837blacklist ${HOME}/.pine-debug1
838blacklist ${HOME}/.pine-debug2
839blacklist ${HOME}/.pine-debug3
840blacklist ${HOME}/.pine-debug4
841blacklist ${HOME}/.pine-interrupted-mail
842blacklist ${HOME}/.pinerc
843blacklist ${HOME}/.pinercex
832blacklist ${HOME}/.pingus 844blacklist ${HOME}/.pingus
833blacklist ${HOME}/.pioneer 845blacklist ${HOME}/.pioneer
834blacklist ${HOME}/.purple 846blacklist ${HOME}/.purple
@@ -866,6 +878,7 @@ blacklist ${HOME}/.teeworlds
866blacklist ${HOME}/.texlive20* 878blacklist ${HOME}/.texlive20*
867blacklist ${HOME}/.thunderbird 879blacklist ${HOME}/.thunderbird
868blacklist ${HOME}/.tilp 880blacklist ${HOME}/.tilp
881blacklist ${HOME}/.tin
869blacklist ${HOME}/.tooling 882blacklist ${HOME}/.tooling
870blacklist ${HOME}/.tor-browser* 883blacklist ${HOME}/.tor-browser*
871blacklist ${HOME}/.torcs 884blacklist ${HOME}/.torcs
diff --git a/etc/profile-a-l/0ad.profile b/etc/profile-a-l/0ad.profile
index 454a15ab2..4009853d3 100644
--- a/etc/profile-a-l/0ad.profile
+++ b/etc/profile-a-l/0ad.profile
@@ -10,6 +10,8 @@ noblacklist ${HOME}/.cache/0ad
10noblacklist ${HOME}/.config/0ad 10noblacklist ${HOME}/.config/0ad
11noblacklist ${HOME}/.local/share/0ad 11noblacklist ${HOME}/.local/share/0ad
12 12
13blacklist /usr/libexec
14
13include disable-common.inc 15include disable-common.inc
14include disable-devel.inc 16include disable-devel.inc
15include disable-exec.inc 17include disable-exec.inc
diff --git a/etc/profile-a-l/alpine.profile b/etc/profile-a-l/alpine.profile
new file mode 100644
index 000000000..0b5cf0df0
--- /dev/null
+++ b/etc/profile-a-l/alpine.profile
@@ -0,0 +1,104 @@
1# Firejail profile for alpine
2# Description: Text-based email and newsgroups reader
3# This file is overwritten after every install/update
4quiet
5# Persistent local customizations
6include alpine.local
7# Persistent global definitions
8include globals.local
9
10# Workaround for bug https://github.com/netblue30/firejail/issues/2747
11# firejail --private-bin=sh --include='${CFG}/allow-bin-sh.inc' --profile=alpine sh -c '(alpine)'
12
13noblacklist /var/mail
14noblacklist /var/spool/mail
15noblacklist ${DOCUMENTS}
16noblacklist ${HOME}/.addressbook
17noblacklist ${HOME}/.alpine-smime
18noblacklist ${HOME}/.mailcap
19noblacklist ${HOME}/.mh_profile
20noblacklist ${HOME}/.mime.types
21noblacklist ${HOME}/.newsrc
22noblacklist ${HOME}/.pine-crash
23noblacklist ${HOME}/.pine-debug1
24noblacklist ${HOME}/.pine-debug2
25noblacklist ${HOME}/.pine-debug3
26noblacklist ${HOME}/.pine-debug4
27noblacklist ${HOME}/.pine-interrupted-mail
28noblacklist ${HOME}/.pinerc
29noblacklist ${HOME}/.pinercex
30noblacklist ${HOME}/.signature
31noblacklist ${HOME}/mail
32
33blacklist /tmp/.X11-unix
34blacklist ${RUNUSER}/wayland-*
35
36include disable-common.inc
37include disable-devel.inc
38include disable-exec.inc
39include disable-interpreters.inc
40include disable-passwdmgr.inc
41include disable-programs.inc
42include disable-shell.inc
43include disable-xdg.inc
44
45#whitelist ${DOCUMENTS}
46#whitelist ${DOWNLOADS}
47#whitelist ${HOME}/.addressbook
48#whitelist ${HOME}/.alpine-smime
49#whitelist ${HOME}/.mailcap
50#whitelist ${HOME}/.mh_profile
51#whitelist ${HOME}/.mime.types
52#whitelist ${HOME}/.newsrc
53#whitelist ${HOME}/.pine-crash
54#whitelist ${HOME}/.pine-interrupted-mail
55#whitelist ${HOME}/.pinerc
56#whitelist ${HOME}/.pinercex
57#whitelist ${HOME}/.pine-debug1
58#whitelist ${HOME}/.pine-debug2
59#whitelist ${HOME}/.pine-debug3
60#whitelist ${HOME}/.pine-debug4
61#whitelist ${HOME}/.signature
62#whitelist ${HOME}/mail
63whitelist /var/mail
64whitelist /var/spool/mail
65#include whitelist-common.inc
66include whitelist-runuser-common.inc
67include whitelist-usr-share-common.inc
68include whitelist-var-common.inc
69
70apparmor
71caps.drop all
72ipc-namespace
73machine-id
74netfilter
75no3d
76nodvd
77nogroups
78noinput
79nonewprivs
80noroot
81nosound
82notv
83nou2f
84novideo
85protocol unix,inet,inet6
86seccomp
87seccomp.block-secondary
88shell none
89tracelog
90
91disable-mnt
92private-bin alpine
93private-cache
94private-dev
95private-etc alternatives,c-client.cf,ca-certificates,crypto-policies,host.conf,hostname,hosts,krb5.keytab,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,mailcap,mime.types,nsswitch.conf,passwd,pine.conf,pinerc.fixed,pki,protocols,resolv.conf,rpc,services,ssl,terminfo,xdg
96private-tmp
97writable-run-user
98writable-var
99
100dbus-user none
101dbus-system none
102
103memory-deny-write-execute
104read-only ${HOME}/.signature
diff --git a/etc/profile-a-l/alpinef.profile b/etc/profile-a-l/alpinef.profile
new file mode 100644
index 000000000..97b97fe5f
--- /dev/null
+++ b/etc/profile-a-l/alpinef.profile
@@ -0,0 +1,14 @@
1# Firejail profile for alpinef
2# Description: Text-based email and newsgroups reader using function keys
3# This file is overwritten after every install/update
4quiet
5# Persistent local customizations
6include alpinef.local
7# Persistent global definitions
8# added by included profile
9#include globals.local
10
11private-bin alpinef
12
13# Redirect
14include alpine.profile
diff --git a/etc/profile-a-l/apostrophe.profile b/etc/profile-a-l/apostrophe.profile
index 54abdb234..01566314f 100644
--- a/etc/profile-a-l/apostrophe.profile
+++ b/etc/profile-a-l/apostrophe.profile
@@ -31,6 +31,7 @@ include disable-programs.inc
31include disable-shell.inc 31include disable-shell.inc
32include disable-xdg.inc 32include disable-xdg.inc
33 33
34whitelist /usr/libexec/webkit2gtk-4.0
34whitelist /usr/share/apostrophe 35whitelist /usr/share/apostrophe
35whitelist /usr/share/texlive 36whitelist /usr/share/texlive
36whitelist /usr/share/texmf 37whitelist /usr/share/texmf
diff --git a/etc/profile-a-l/bijiben.profile b/etc/profile-a-l/bijiben.profile
index 721a6c082..854fe5cb9 100644
--- a/etc/profile-a-l/bijiben.profile
+++ b/etc/profile-a-l/bijiben.profile
@@ -20,6 +20,7 @@ include disable-xdg.inc
20mkdir ${HOME}/.local/share/bijiben 20mkdir ${HOME}/.local/share/bijiben
21whitelist ${HOME}/.local/share/bijiben 21whitelist ${HOME}/.local/share/bijiben
22whitelist ${HOME}/.cache/tracker 22whitelist ${HOME}/.cache/tracker
23whitelist /usr/libexec/webkit2gtk-4.0
23whitelist /usr/share/bijiben 24whitelist /usr/share/bijiben
24whitelist /usr/share/tracker 25whitelist /usr/share/tracker
25whitelist /usr/share/tracker3 26whitelist /usr/share/tracker3
diff --git a/etc/profile-a-l/celluloid.profile b/etc/profile-a-l/celluloid.profile
index f02161b9b..1c539cc93 100644
--- a/etc/profile-a-l/celluloid.profile
+++ b/etc/profile-a-l/celluloid.profile
@@ -17,6 +17,8 @@ include allow-lua.inc
17include allow-python2.inc 17include allow-python2.inc
18include allow-python3.inc 18include allow-python3.inc
19 19
20blacklist /usr/libexec
21
20include disable-common.inc 22include disable-common.inc
21include disable-devel.inc 23include disable-devel.inc
22include disable-exec.inc 24include disable-exec.inc
diff --git a/etc/profile-a-l/chromium-browser-privacy.profile b/etc/profile-a-l/chromium-browser-privacy.profile
index 0283a6934..8803a4d9d 100644
--- a/etc/profile-a-l/chromium-browser-privacy.profile
+++ b/etc/profile-a-l/chromium-browser-privacy.profile
@@ -6,6 +6,8 @@ include chromium-browser-privacy.local
6noblacklist ${HOME}/.cache/ungoogled-chromium 6noblacklist ${HOME}/.cache/ungoogled-chromium
7noblacklist ${HOME}/.config/ungoogled-chromium 7noblacklist ${HOME}/.config/ungoogled-chromium
8 8
9blacklist /usr/libexec
10
9mkdir ${HOME}/.cache/ungoogled-chromium 11mkdir ${HOME}/.cache/ungoogled-chromium
10mkdir ${HOME}/.config/ungoogled-chromium 12mkdir ${HOME}/.config/ungoogled-chromium
11whitelist ${HOME}/.cache/ungoogled-chromium 13whitelist ${HOME}/.cache/ungoogled-chromium
diff --git a/etc/profile-a-l/ddgr.profile b/etc/profile-a-l/ddgr.profile
new file mode 100644
index 000000000..b1d41ddf7
--- /dev/null
+++ b/etc/profile-a-l/ddgr.profile
@@ -0,0 +1,13 @@
1# Firejail profile for ddgr
2# Description: Search DuckDuckGo from your terminal
3# This file is overwritten after every install/update
4quiet
5# Persistent local customizations
6include ddgr.local
7# Persistent global definitions
8include globals.local
9
10private-bin ddgr
11
12# Redirect
13include googler-common.profile
diff --git a/etc/profile-a-l/elinks.profile b/etc/profile-a-l/elinks.profile
index 8120725d2..5a29eb24b 100644
--- a/etc/profile-a-l/elinks.profile
+++ b/etc/profile-a-l/elinks.profile
@@ -1,6 +1,7 @@
1# Firejail profile for elinks 1# Firejail profile for elinks
2# Description: Advanced text-mode WWW browser 2# Description: Advanced text-mode WWW browser
3# This file is overwritten after every install/update 3# This file is overwritten after every install/update
4quiet
4# Persistent local customizations 5# Persistent local customizations
5include elinks.local 6include elinks.local
6# Persistent global definitions 7# Persistent global definitions
@@ -8,37 +9,10 @@ include globals.local
8 9
9noblacklist ${HOME}/.elinks 10noblacklist ${HOME}/.elinks
10 11
11blacklist /tmp/.X11-unix 12mkdir ${HOME}/.elinks
12blacklist ${RUNUSER}/wayland-* 13whitelist ${HOME}/.elinks
13 14
14include disable-common.inc 15private-bin elinks
15include disable-devel.inc
16include disable-interpreters.inc
17include disable-passwdmgr.inc
18include disable-programs.inc
19include disable-xdg.inc
20 16
21include whitelist-runuser-common.inc 17# Redirect
22 18include links-common.profile
23caps.drop all
24netfilter
25no3d
26nodvd
27nogroups
28noinput
29nonewprivs
30noroot
31nosound
32notv
33nou2f
34novideo
35protocol unix,inet,inet6
36seccomp
37shell none
38tracelog
39
40# private-bin elinks
41private-cache
42private-dev
43# private-etc alternatives,ca-certificates,crypto-policies,pki,ssl
44private-tmp
diff --git a/etc/profile-a-l/eo-common.profile b/etc/profile-a-l/eo-common.profile
index 8e8047b00..fe7913e77 100644
--- a/etc/profile-a-l/eo-common.profile
+++ b/etc/profile-a-l/eo-common.profile
@@ -11,6 +11,8 @@ noblacklist ${HOME}/.local/share/Trash
11noblacklist ${HOME}/.Steam 11noblacklist ${HOME}/.Steam
12noblacklist ${HOME}/.steam 12noblacklist ${HOME}/.steam
13 13
14blacklist /usr/libexec
15
14include disable-common.inc 16include disable-common.inc
15include disable-devel.inc 17include disable-devel.inc
16include disable-exec.inc 18include disable-exec.inc
diff --git a/etc/profile-a-l/etr.profile b/etc/profile-a-l/etr.profile
index d44d419c1..fdff1e4b5 100644
--- a/etc/profile-a-l/etr.profile
+++ b/etc/profile-a-l/etr.profile
@@ -8,6 +8,8 @@ include globals.local
8 8
9noblacklist ${HOME}/.etr 9noblacklist ${HOME}/.etr
10 10
11blacklist /usr/libexec
12
11include disable-common.inc 13include disable-common.inc
12include disable-devel.inc 14include disable-devel.inc
13include disable-exec.inc 15include disable-exec.inc
diff --git a/etc/profile-a-l/evince.profile b/etc/profile-a-l/evince.profile
index adcb29063..a9e39b15c 100644
--- a/etc/profile-a-l/evince.profile
+++ b/etc/profile-a-l/evince.profile
@@ -13,6 +13,8 @@ include globals.local
13noblacklist ${HOME}/.config/evince 13noblacklist ${HOME}/.config/evince
14noblacklist ${DOCUMENTS} 14noblacklist ${DOCUMENTS}
15 15
16blacklist /usr/libexec
17
16include disable-common.inc 18include disable-common.inc
17include disable-devel.inc 19include disable-devel.inc
18include disable-exec.inc 20include disable-exec.inc
diff --git a/etc/profile-a-l/file-roller.profile b/etc/profile-a-l/file-roller.profile
index 0b8a8cd6c..4e651ed61 100644
--- a/etc/profile-a-l/file-roller.profile
+++ b/etc/profile-a-l/file-roller.profile
@@ -13,6 +13,7 @@ include disable-interpreters.inc
13include disable-passwdmgr.inc 13include disable-passwdmgr.inc
14include disable-programs.inc 14include disable-programs.inc
15 15
16whitelist /usr/libexec/file-roller
16whitelist /usr/share/file-roller 17whitelist /usr/share/file-roller
17include whitelist-runuser-common.inc 18include whitelist-runuser-common.inc
18include whitelist-usr-share-common.inc 19include whitelist-usr-share-common.inc
diff --git a/etc/profile-a-l/firefox.profile b/etc/profile-a-l/firefox.profile
index b22a78458..7874c882f 100644
--- a/etc/profile-a-l/firefox.profile
+++ b/etc/profile-a-l/firefox.profile
@@ -17,6 +17,8 @@ include globals.local
17noblacklist ${HOME}/.cache/mozilla 17noblacklist ${HOME}/.cache/mozilla
18noblacklist ${HOME}/.mozilla 18noblacklist ${HOME}/.mozilla
19 19
20blacklist /usr/libexec
21
20mkdir ${HOME}/.cache/mozilla/firefox 22mkdir ${HOME}/.cache/mozilla/firefox
21mkdir ${HOME}/.mozilla 23mkdir ${HOME}/.mozilla
22whitelist ${HOME}/.cache/mozilla/firefox 24whitelist ${HOME}/.cache/mozilla/firefox
diff --git a/etc/profile-a-l/frogatto.profile b/etc/profile-a-l/frogatto.profile
index fa56d2b2d..b4ad81046 100644
--- a/etc/profile-a-l/frogatto.profile
+++ b/etc/profile-a-l/frogatto.profile
@@ -18,6 +18,7 @@ include disable-xdg.inc
18 18
19mkdir ${HOME}/.frogatto 19mkdir ${HOME}/.frogatto
20whitelist ${HOME}/.frogatto 20whitelist ${HOME}/.frogatto
21whitelist /usr/libexec/frogatto
21whitelist /usr/share/frogatto 22whitelist /usr/share/frogatto
22include whitelist-common.inc 23include whitelist-common.inc
23include whitelist-runuser-common.inc 24include whitelist-runuser-common.inc
diff --git a/etc/profile-a-l/gapplication.profile b/etc/profile-a-l/gapplication.profile
index f2da60c87..3a8c055f2 100644
--- a/etc/profile-a-l/gapplication.profile
+++ b/etc/profile-a-l/gapplication.profile
@@ -7,6 +7,7 @@ include gapplication.local
7include globals.local 7include globals.local
8 8
9blacklist ${RUNUSER}/wayland-* 9blacklist ${RUNUSER}/wayland-*
10blacklist /usr/libexec
10 11
11include disable-common.inc 12include disable-common.inc
12include disable-devel.inc 13include disable-devel.inc
diff --git a/etc/profile-a-l/gfeeds.profile b/etc/profile-a-l/gfeeds.profile
index 7ec8ba810..f894a42ca 100644
--- a/etc/profile-a-l/gfeeds.profile
+++ b/etc/profile-a-l/gfeeds.profile
@@ -31,6 +31,7 @@ whitelist ${HOME}/.cache/gfeeds
31whitelist ${HOME}/.cache/org.gabmus.gfeeds 31whitelist ${HOME}/.cache/org.gabmus.gfeeds
32whitelist ${HOME}/.config/org.gabmus.gfeeds.json 32whitelist ${HOME}/.config/org.gabmus.gfeeds.json
33whitelist ${HOME}/.config/org.gabmus.gfeeds.saved_articles 33whitelist ${HOME}/.config/org.gabmus.gfeeds.saved_articles
34whitelist /usr/libexec/webkit2gtk-4.0
34whitelist /usr/share/gfeeds 35whitelist /usr/share/gfeeds
35include whitelist-common.inc 36include whitelist-common.inc
36include whitelist-runuser-common.inc 37include whitelist-runuser-common.inc
diff --git a/etc/profile-a-l/gnome-maps.profile b/etc/profile-a-l/gnome-maps.profile
index cf2ac2f75..23aab343f 100644
--- a/etc/profile-a-l/gnome-maps.profile
+++ b/etc/profile-a-l/gnome-maps.profile
@@ -18,6 +18,8 @@ noblacklist ${HOME}/.local/share/maps-places.json
18# Allow gjs (blacklisted by disable-interpreters.inc) 18# Allow gjs (blacklisted by disable-interpreters.inc)
19include allow-gjs.inc 19include allow-gjs.inc
20 20
21blacklist /usr/libexec
22
21include disable-common.inc 23include disable-common.inc
22include disable-devel.inc 24include disable-devel.inc
23include disable-exec.inc 25include disable-exec.inc
diff --git a/etc/profile-a-l/gnome-passwordsafe.profile b/etc/profile-a-l/gnome-passwordsafe.profile
index 763d67b92..fee5f88b9 100644
--- a/etc/profile-a-l/gnome-passwordsafe.profile
+++ b/etc/profile-a-l/gnome-passwordsafe.profile
@@ -13,6 +13,8 @@ noblacklist ${HOME}/*.kdbx
13# Allow python (blacklisted by disable-interpreters.inc) 13# Allow python (blacklisted by disable-interpreters.inc)
14include allow-python3.inc 14include allow-python3.inc
15 15
16blacklist /usr/libexec
17
16include disable-common.inc 18include disable-common.inc
17include disable-devel.inc 19include disable-devel.inc
18include disable-exec.inc 20include disable-exec.inc
diff --git a/etc/profile-a-l/googler-common.profile b/etc/profile-a-l/googler-common.profile
new file mode 100644
index 000000000..2d0bce52b
--- /dev/null
+++ b/etc/profile-a-l/googler-common.profile
@@ -0,0 +1,62 @@
1# Firejail profile for googler clones
2# Description: common profile for googler clones
3# This file is overwritten after every install/update
4# Persistent local customizations
5include googler-common.local
6# Persistent global definitions
7# added by caller profile
8#include globals.local
9
10blacklist /tmp/.X11-unix
11blacklist ${RUNUSER}
12
13noblacklist ${HOME}/.w3m
14
15# Allow /bin/sh (blacklisted by disable-shell.inc)
16include allow-bin-sh.inc
17# Allow python (blacklisted by disable-interpreters.inc)
18include allow-python3.inc
19
20include disable-common.inc
21include disable-devel.inc
22include disable-exec.inc
23include disable-interpreters.inc
24include disable-passwdmgr.inc
25include disable-programs.inc
26include disable-shell.inc
27include disable-xdg.inc
28
29whitelist ${HOME}/.w3m
30include whitelist-usr-share-common.inc
31include whitelist-var-common.inc
32
33apparmor
34caps.drop all
35ipc-namespace
36machine-id
37netfilter
38no3d
39nodvd
40nogroups
41noinput
42nonewprivs
43noroot
44nosound
45notv
46nou2f
47novideo
48protocol unix,inet,inet6
49seccomp
50seccomp.block-secondary
51shell none
52tracelog
53
54disable-mnt
55private-bin env,python3*,sh,w3m
56private-cache
57private-dev
58private-etc ca-certificates,crypto-policies,host.conf,hostname,hosts,nsswitch.conf,pki,protocols,resolv.conf,rpc,services,ssl
59private-tmp
60
61dbus-user none
62dbus-system none
diff --git a/etc/profile-a-l/googler.profile b/etc/profile-a-l/googler.profile
new file mode 100644
index 000000000..9d67006f6
--- /dev/null
+++ b/etc/profile-a-l/googler.profile
@@ -0,0 +1,13 @@
1# Firejail profile for googler
2# Description: Search Google from your terminal
3# This file is overwritten after every install/update
4quiet
5# Persistent local customizations
6include googler.local
7# Persistent global definitions
8include globals.local
9
10private-bin googler
11
12# Redirect
13include googler-common.profile
diff --git a/etc/profile-a-l/gunzip.profile b/etc/profile-a-l/gunzip.profile
index 6e97c6b78..584d88f85 100644
--- a/etc/profile-a-l/gunzip.profile
+++ b/etc/profile-a-l/gunzip.profile
@@ -7,5 +7,7 @@ include gunzip.local
7# added by included profile 7# added by included profile
8#include globals.local 8#include globals.local
9 9
10include allow-bin-sh.inc
11
10# Redirect 12# Redirect
11include gzip.profile 13include gzip.profile
diff --git a/etc/profile-a-l/hexchat.profile b/etc/profile-a-l/hexchat.profile
index f72af0b4a..b887de147 100644
--- a/etc/profile-a-l/hexchat.profile
+++ b/etc/profile-a-l/hexchat.profile
@@ -8,6 +8,9 @@ include globals.local
8 8
9noblacklist ${HOME}/.config/hexchat 9noblacklist ${HOME}/.config/hexchat
10 10
11# Allow /bin/sh (blacklisted by disable-shell.inc)
12include allow-bin-sh.inc
13
11# Allow perl (blacklisted by disable-interpreters.inc) 14# Allow perl (blacklisted by disable-interpreters.inc)
12include allow-perl.inc 15include allow-perl.inc
13 16
@@ -48,7 +51,7 @@ tracelog
48 51
49disable-mnt 52disable-mnt
50# debug note: private-bin requires perl, python, etc on some systems 53# debug note: private-bin requires perl, python, etc on some systems
51private-bin hexchat,python* 54private-bin hexchat,python*,sh
52private-dev 55private-dev
53#private-lib - python problems 56#private-lib - python problems
54private-tmp 57private-tmp
diff --git a/etc/profile-a-l/keepassxc.profile b/etc/profile-a-l/keepassxc.profile
index c352a5d89..f71dcf82b 100644
--- a/etc/profile-a-l/keepassxc.profile
+++ b/etc/profile-a-l/keepassxc.profile
@@ -22,6 +22,8 @@ noblacklist ${HOME}/.config/vivaldi
22noblacklist ${HOME}/.local/share/torbrowser 22noblacklist ${HOME}/.local/share/torbrowser
23noblacklist ${HOME}/.mozilla 23noblacklist ${HOME}/.mozilla
24 24
25blacklist /usr/libexec
26
25include disable-common.inc 27include disable-common.inc
26include disable-devel.inc 28include disable-devel.inc
27include disable-exec.inc 29include disable-exec.inc
diff --git a/etc/profile-a-l/kodi.profile b/etc/profile-a-l/kodi.profile
index b72632bf4..b7091f1fc 100644
--- a/etc/profile-a-l/kodi.profile
+++ b/etc/profile-a-l/kodi.profile
@@ -8,6 +8,10 @@ include globals.local
8 8
9# noexec ${HOME} breaks plugins 9# noexec ${HOME} breaks plugins
10ignore noexec ${HOME} 10ignore noexec ${HOME}
11# Add the following to your kodi.local if you use a CEC Adapter.
12#ignore nogroups
13#ignore noroot
14#ignore private-dev
11 15
12noblacklist ${HOME}/.kodi 16noblacklist ${HOME}/.kodi
13noblacklist ${MUSIC} 17noblacklist ${MUSIC}
diff --git a/etc/profile-a-l/libreoffice.profile b/etc/profile-a-l/libreoffice.profile
index e4440eac0..b1a24888c 100644
--- a/etc/profile-a-l/libreoffice.profile
+++ b/etc/profile-a-l/libreoffice.profile
@@ -14,6 +14,8 @@ noblacklist ${HOME}/.config/libreoffice
14# Allow java (blacklisted by disable-devel.inc) 14# Allow java (blacklisted by disable-devel.inc)
15include allow-java.inc 15include allow-java.inc
16 16
17blacklist /usr/libexec
18
17include disable-common.inc 19include disable-common.inc
18include disable-devel.inc 20include disable-devel.inc
19include disable-exec.inc 21include disable-exec.inc
diff --git a/etc/profile-a-l/links-common.profile b/etc/profile-a-l/links-common.profile
new file mode 100644
index 000000000..cd885b1d4
--- /dev/null
+++ b/etc/profile-a-l/links-common.profile
@@ -0,0 +1,63 @@
1# This file is overwritten during software install.
2# Persistent customizations should go in a .local file.
3include links-common.local
4
5# common profile for links browsers
6
7blacklist /tmp/.X11-unix
8blacklist ${RUNUSER}/wayland-*
9
10include disable-common.inc
11include disable-devel.inc
12include disable-exec.inc
13include disable-interpreters.inc
14include disable-passwdmgr.inc
15# Additional noblacklist files/directories (blacklisted in disable-programs.inc)
16# used as associated programs can be added in your links-common.local.
17include disable-programs.inc
18include disable-xdg.inc
19
20whitelist ${DOWNLOADS}
21include whitelist-runuser-common.inc
22include whitelist-usr-share-common.inc
23include whitelist-var-common.inc
24
25caps.drop all
26ipc-namespace
27# Add 'ignore machine-id' to your links-common.local if you want to restrict access to
28# the user-configured associated media player.
29machine-id
30netfilter
31# Add 'ignore no3d' to your links-common.local if you want to restrict access to
32# the user-configured associated media player.
33no3d
34nodvd
35nogroups
36noinput
37nonewprivs
38noroot
39# Add 'ignore nosound' to your links-common.local if you want to restrict access to
40# the user-configured associated media player.
41nosound
42notv
43nou2f
44novideo
45protocol unix,inet,inet6
46seccomp
47shell none
48tracelog
49
50disable-mnt
51# Add 'private-bin PROGRAM1,PROGRAM2' to your links-common.local if you want to use user-configured programs.
52private-bin sh
53private-cache
54private-dev
55private-etc alternatives,ca-certificates,crypto-policies,nsswitch.conf,pki,resolv.conf,ssl
56# Add the next line to your links-common.local to allow external media players.
57# private-etc alsa,asound.conf,machine-id,openal,pulse
58private-tmp
59
60dbus-user none
61dbus-system none
62
63memory-deny-write-execute
diff --git a/etc/profile-a-l/links.profile b/etc/profile-a-l/links.profile
index a1eeda14a..8ce39cc7f 100644
--- a/etc/profile-a-l/links.profile
+++ b/etc/profile-a-l/links.profile
@@ -9,58 +9,10 @@ include globals.local
9 9
10noblacklist ${HOME}/.links 10noblacklist ${HOME}/.links
11 11
12blacklist /tmp/.X11-unix
13blacklist ${RUNUSER}/wayland-*
14
15include disable-common.inc
16include disable-devel.inc
17include disable-exec.inc
18include disable-interpreters.inc
19include disable-passwdmgr.inc
20# Additional noblacklist files/directories (blacklisted in disable-programs.inc)
21# used as associated programs can be added in your links.local.
22include disable-programs.inc
23include disable-xdg.inc
24
25mkdir ${HOME}/.links 12mkdir ${HOME}/.links
26whitelist ${HOME}/.links 13whitelist ${HOME}/.links
27whitelist ${DOWNLOADS}
28include whitelist-runuser-common.inc
29include whitelist-var-common.inc
30
31caps.drop all
32ipc-namespace
33# Add 'ignore machine-id' to your links.local if you want to restrict access to
34# the user-configured associated media player.
35machine-id
36netfilter
37# Add 'ignore no3d' to your links.local if you want to restrict access to
38# the user-configured associated media player.
39no3d
40nodvd
41nogroups
42noinput
43nonewprivs
44noroot
45# Add 'ignore nosound' to your links.local if you want to restrict access to
46# the user-configured associated media player.
47nosound
48notv
49nou2f
50novideo
51protocol unix,inet,inet6
52seccomp
53shell none
54tracelog
55 14
56disable-mnt 15private-bin links
57# Add 'private-bin PROGRAM1,PROGRAM2' to your links.local if you want to use user-configured programs.
58private-bin links,sh
59private-cache
60private-dev
61private-etc alternatives,ca-certificates,crypto-policies,nsswitch.conf,pki,resolv.conf,ssl
62# Add the next line to your links.local to allow external media players.
63# private-etc alsa,asound.conf,machine-id,openal,pulse
64private-tmp
65 16
66memory-deny-write-execute 17# Redirect
18include links-common.profile
diff --git a/etc/profile-a-l/links2.profile b/etc/profile-a-l/links2.profile
new file mode 100644
index 000000000..5f91dfcd2
--- /dev/null
+++ b/etc/profile-a-l/links2.profile
@@ -0,0 +1,18 @@
1# Firejail profile for links2
2# Description: Text WWW browser with a graphic version
3# This file is overwritten after every install/update
4quiet
5# Persistent local customizations
6include links2.local
7# Persistent global definitions
8include globals.local
9
10noblacklist ${HOME}/.links2
11
12mkdir ${HOME}/.links2
13whitelist ${HOME}/.links2
14
15private-bin links2
16
17# Redirect
18include links-common.profile
diff --git a/etc/profile-m-z/marker.profile b/etc/profile-m-z/marker.profile
index 087c02964..bd56a8221 100644
--- a/etc/profile-m-z/marker.profile
+++ b/etc/profile-m-z/marker.profile
@@ -25,6 +25,7 @@ include disable-programs.inc
25include disable-shell.inc 25include disable-shell.inc
26include disable-xdg.inc 26include disable-xdg.inc
27 27
28whitelist /usr/libexec/webkit2gtk-4.0
28whitelist /usr/share/com.github.fabiocolacio.marker 29whitelist /usr/share/com.github.fabiocolacio.marker
29include whitelist-runuser-common.inc 30include whitelist-runuser-common.inc
30include whitelist-usr-share-common.inc 31include whitelist-usr-share-common.inc
diff --git a/etc/profile-m-z/mcomix.profile b/etc/profile-m-z/mcomix.profile
new file mode 100644
index 000000000..fcd1e24e5
--- /dev/null
+++ b/etc/profile-m-z/mcomix.profile
@@ -0,0 +1,74 @@
1# Firejail profile for mcomix
2# Description: A comic book and manga viewer in python
3# This file is overwritten after every install/update
4# Persistent local customizations
5include mcomix.local
6# Persistent global definitions
7include globals.local
8
9noblacklist ${HOME}/.config/mcomix
10noblacklist ${HOME}/.local/share/mcomix
11noblacklist ${DOCUMENTS}
12
13# Allow /bin/sh (blacklisted by disable-shell.inc)
14include allow-bin-sh.inc
15
16# Allow python (blacklisted by disable-interpreters.inc)
17# mcomix <= 1.2 uses python2
18include allow-python2.inc
19include allow-python3.inc
20
21include disable-common.inc
22include disable-devel.inc
23include disable-exec.inc
24include disable-interpreters.inc
25include disable-passwdmgr.inc
26include disable-programs.inc
27include disable-shell.inc
28include disable-write-mnt.inc
29include disable-xdg.inc
30
31mkdir ${HOME}/.config/mcomix
32mkdir ${HOME}/.local/share/mcomix
33whitelist /usr/share/mcomix
34include whitelist-usr-share-common.inc
35include whitelist-var-common.inc
36include whitelist-runuser-common.inc
37
38apparmor
39caps.drop all
40machine-id
41net none
42nodvd
43nogroups
44noinput
45nonewprivs
46noroot
47nosound
48notv
49nou2f
50novideo
51protocol unix
52seccomp
53seccomp.block-secondary
54shell none
55tracelog
56
57# mcomix <= 1.2 uses python2
58private-bin 7z,lha,mcomix,mutool,python*,rar,sh,unrar,unzip
59private-cache
60private-dev
61# mcomix <= 1.2 uses gtk-2.0
62private-etc alternatives,dconf,fonts,gconf,gtk-2.0,gtk-3.0,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,machine-id,mime.types,pango,passwd,X11,xdg
63private-tmp
64
65dbus-user none
66dbus-system none
67
68read-only ${HOME}
69read-write ${HOME}/.config/mcomix
70read-write ${HOME}/.local/share/mcomix
71#to allow ${HOME}/.local/share/recently-used.xbel
72read-write ${HOME}/.local/share
73# used by mcomix <= 1.2, tip, make a symbolic link to .cache/thumbnails
74read-write ${HOME}/.thumbnails
diff --git a/etc/profile-m-z/megaglest.profile b/etc/profile-m-z/megaglest.profile
index 972838729..f07b9166a 100644
--- a/etc/profile-m-z/megaglest.profile
+++ b/etc/profile-m-z/megaglest.profile
@@ -20,6 +20,7 @@ include disable-xdg.inc
20mkdir ${HOME}/.megaglest 20mkdir ${HOME}/.megaglest
21whitelist ${HOME}/.megaglest 21whitelist ${HOME}/.megaglest
22whitelist /usr/share/megaglest 22whitelist /usr/share/megaglest
23whitelist /usr/share/games/megaglest # Debian version
23include whitelist-common.inc 24include whitelist-common.inc
24include whitelist-runuser-common.inc 25include whitelist-runuser-common.inc
25include whitelist-usr-share-common.inc 26include whitelist-usr-share-common.inc
diff --git a/etc/profile-m-z/meld.profile b/etc/profile-m-z/meld.profile
index 1225cc107..2a8bb3acf 100644
--- a/etc/profile-m-z/meld.profile
+++ b/etc/profile-m-z/meld.profile
@@ -29,6 +29,8 @@ include allow-python3.inc
29# Allow ssh (blacklisted by disable-common.inc) 29# Allow ssh (blacklisted by disable-common.inc)
30include allow-ssh.inc 30include allow-ssh.inc
31 31
32blacklist /usr/libexec
33
32# Add the next line to your meld.local if you don't need to compare files in disable-common.inc. 34# Add the next line to your meld.local if you don't need to compare files in disable-common.inc.
33#include disable-common.inc 35#include disable-common.inc
34include disable-devel.inc 36include disable-devel.inc
diff --git a/etc/profile-m-z/minecraft-launcher.profile b/etc/profile-m-z/minecraft-launcher.profile
index 2536d0b38..1028e374a 100644
--- a/etc/profile-m-z/minecraft-launcher.profile
+++ b/etc/profile-m-z/minecraft-launcher.profile
@@ -31,7 +31,6 @@ include whitelist-runuser-common.inc
31include whitelist-usr-share-common.inc 31include whitelist-usr-share-common.inc
32include whitelist-var-common.inc 32include whitelist-var-common.inc
33 33
34apparmor
35caps.drop all 34caps.drop all
36netfilter 35netfilter
37nodvd 36nodvd
diff --git a/etc/profile-m-z/mpv.profile b/etc/profile-m-z/mpv.profile
index 310f36ea1..af5c214f7 100644
--- a/etc/profile-m-z/mpv.profile
+++ b/etc/profile-m-z/mpv.profile
@@ -35,6 +35,8 @@ include allow-lua.inc
35include allow-python2.inc 35include allow-python2.inc
36include allow-python3.inc 36include allow-python3.inc
37 37
38blacklist /usr/libexec
39
38include disable-common.inc 40include disable-common.inc
39include disable-devel.inc 41include disable-devel.inc
40include disable-exec.inc 42include disable-exec.inc
diff --git a/etc/profile-m-z/mrrescue.profile b/etc/profile-m-z/mrrescue.profile
index 035a7e625..e3ceb3bd4 100644
--- a/etc/profile-m-z/mrrescue.profile
+++ b/etc/profile-m-z/mrrescue.profile
@@ -14,6 +14,8 @@ include allow-bin-sh.inc
14# Allow lua (blacklisted by disable-interpreters.inc) 14# Allow lua (blacklisted by disable-interpreters.inc)
15include allow-lua.inc 15include allow-lua.inc
16 16
17blacklist /usr/libexec
18
17include disable-common.inc 19include disable-common.inc
18include disable-devel.inc 20include disable-devel.inc
19include disable-exec.inc 21include disable-exec.inc
diff --git a/etc/profile-m-z/pingus.profile b/etc/profile-m-z/pingus.profile
index 3889d87d2..f1fdfcbad 100644
--- a/etc/profile-m-z/pingus.profile
+++ b/etc/profile-m-z/pingus.profile
@@ -11,6 +11,8 @@ noblacklist ${HOME}/.pingus
11# Allow /bin/sh (blacklisted by disable-shell.inc) 11# Allow /bin/sh (blacklisted by disable-shell.inc)
12include allow-bin-sh.inc 12include allow-bin-sh.inc
13 13
14blacklist /usr/libexec
15
14include disable-common.inc 16include disable-common.inc
15include disable-devel.inc 17include disable-devel.inc
16include disable-exec.inc 18include disable-exec.inc
diff --git a/etc/profile-m-z/qcomicbook.profile b/etc/profile-m-z/qcomicbook.profile
new file mode 100644
index 000000000..0e52d7fc4
--- /dev/null
+++ b/etc/profile-m-z/qcomicbook.profile
@@ -0,0 +1,68 @@
1# Firejail profile for qcomicbook
2# Description: A comic book and manga viewer in QT
3# This file is overwritten after every install/update
4# Persistent local customizations
5include qcomicbook.local
6# Persistent global definitions
7include globals.local
8
9noblacklist ${HOME}/.cache/PawelStolowski
10noblacklist ${HOME}/.config/PawelStolowski
11noblacklist ${HOME}/.local/share/PawelStolowski
12noblacklist ${DOCUMENTS}
13
14# Allow /bin/sh (blacklisted by disable-shell.inc)
15include allow-bin-sh.inc
16
17include disable-common.inc
18include disable-devel.inc
19include disable-exec.inc
20include disable-interpreters.inc
21include disable-passwdmgr.inc
22include disable-programs.inc
23include disable-shell.inc
24include disable-write-mnt.inc
25include disable-xdg.inc
26
27mkdir ${HOME}/.cache/PawelStolowski
28mkdir ${HOME}/.config/PawelStolowski
29mkdir ${HOME}/.local/share/PawelStolowski
30whitelist /usr/share/qcomicbook
31include whitelist-runuser-common.inc
32include whitelist-usr-share-common.inc
33include whitelist-var-common.inc
34
35apparmor
36caps.drop all
37machine-id
38net none
39nodvd
40nogroups
41noinput
42nonewprivs
43noroot
44nosound
45notv
46nou2f
47novideo
48protocol unix
49seccomp
50seccomp.block-secondary
51shell none
52tracelog
53
54private-bin 7z,7zr,qcomicbook,rar,sh,tar,unace,unrar,unzip
55private-cache
56private-dev
57private-etc alternatives,fonts,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,localtime,machine-id,mime.types,pango,passwd,Trolltech.conf,X11,xdg
58private-tmp
59
60dbus-user none
61dbus-system none
62
63read-only ${HOME}
64read-write ${HOME}/.cache/PawelStolowski
65read-write ${HOME}/.config/PawelStolowski
66read-write ${HOME}/.local/share/PawelStolowski
67#to allow ${HOME}/.local/share/recently-used.xbel
68read-write ${HOME}/.local/share
diff --git a/etc/profile-m-z/rtin.profile b/etc/profile-m-z/rtin.profile
new file mode 100644
index 000000000..cd84ce05e
--- /dev/null
+++ b/etc/profile-m-z/rtin.profile
@@ -0,0 +1,8 @@
1# Firejail profile for rtin
2# Description: ncurses-based Usenet newsreader
3# symlink to tin, same as `tin -r`
4# This file is overwritten after every install/update
5# Persistent local customizations
6include rtin.local
7
8include tin.profile
diff --git a/etc/profile-m-z/scorched3d.profile b/etc/profile-m-z/scorched3d.profile
index aac3e721f..b1989e474 100644
--- a/etc/profile-m-z/scorched3d.profile
+++ b/etc/profile-m-z/scorched3d.profile
@@ -19,6 +19,7 @@ include disable-xdg.inc
19mkdir ${HOME}/.scorched3d 19mkdir ${HOME}/.scorched3d
20whitelist ${HOME}/.scorched3d 20whitelist ${HOME}/.scorched3d
21whitelist /usr/share/scorched3d 21whitelist /usr/share/scorched3d
22whitelist /usr/share/games/scorched3d
22include whitelist-common.inc 23include whitelist-common.inc
23include whitelist-runuser-common.inc 24include whitelist-runuser-common.inc
24include whitelist-usr-share-common.inc 25include whitelist-usr-share-common.inc
diff --git a/etc/profile-m-z/seahorse-adventures.profile b/etc/profile-m-z/seahorse-adventures.profile
index 131dcbb68..7799ab7ed 100644
--- a/etc/profile-m-z/seahorse-adventures.profile
+++ b/etc/profile-m-z/seahorse-adventures.profile
@@ -6,6 +6,9 @@ include seahorse-adventures.local
6# Persistent global definitions 6# Persistent global definitions
7include globals.local 7include globals.local
8 8
9# Allow /bin/sh (blacklisted by disable-shell.inc)
10include allow-bin-sh.inc
11
9# Allow python (blacklisted by disable-interpreters.inc) 12# Allow python (blacklisted by disable-interpreters.inc)
10include allow-python2.inc 13include allow-python2.inc
11include allow-python3.inc 14include allow-python3.inc
@@ -20,6 +23,7 @@ include disable-shell.inc
20include disable-xdg.inc 23include disable-xdg.inc
21 24
22whitelist /usr/share/seahorse-adventures 25whitelist /usr/share/seahorse-adventures
26whitelist /usr/share/games/seahorse-adventures
23include whitelist-common.inc 27include whitelist-common.inc
24include whitelist-usr-share-common.inc 28include whitelist-usr-share-common.inc
25include whitelist-var-common.inc 29include whitelist-var-common.inc
@@ -42,7 +46,7 @@ tracelog
42 46
43disable-mnt 47disable-mnt
44private 48private
45private-bin python*,seahorse-adventures 49private-bin bash,dash,python*,seahorse-adventures,sh
46private-cache 50private-cache
47private-dev 51private-dev
48private-etc machine-id 52private-etc machine-id
diff --git a/etc/profile-m-z/slack.profile b/etc/profile-m-z/slack.profile
index 9ad772cd5..51f6c8b00 100644
--- a/etc/profile-m-z/slack.profile
+++ b/etc/profile-m-z/slack.profile
@@ -18,12 +18,14 @@ ignore dbus-system none
18 18
19noblacklist ${HOME}/.config/Slack 19noblacklist ${HOME}/.config/Slack
20 20
21include allow-bin-sh.inc
22
21include disable-shell.inc 23include disable-shell.inc
22 24
23mkdir ${HOME}/.config/Slack 25mkdir ${HOME}/.config/Slack
24whitelist ${HOME}/.config/Slack 26whitelist ${HOME}/.config/Slack
25 27
26private-bin locale,slack 28private-bin electron,electron[0-9],electron[0-9][0-9],locale,sh,slack
27private-etc alternatives,asound.conf,ca-certificates,crypto-policies,debian_version,fedora-release,fonts,group,ld.so.cache,ld.so.conf,localtime,machine-id,os-release,passwd,pki,pulse,redhat-release,resolv.conf,ssl,system-release,system-release-cpe 29private-etc alternatives,asound.conf,ca-certificates,crypto-policies,debian_version,fedora-release,fonts,group,ld.so.cache,ld.so.conf,localtime,machine-id,os-release,passwd,pki,pulse,redhat-release,resolv.conf,ssl,system-release,system-release-cpe
28 30
29# Redirect 31# Redirect
diff --git a/etc/profile-m-z/supertux2.profile b/etc/profile-m-z/supertux2.profile
index dd456f085..cfd7a63ea 100644
--- a/etc/profile-m-z/supertux2.profile
+++ b/etc/profile-m-z/supertux2.profile
@@ -20,6 +20,7 @@ include disable-xdg.inc
20mkdir ${HOME}/.local/share/supertux2 20mkdir ${HOME}/.local/share/supertux2
21whitelist ${HOME}/.local/share/supertux2 21whitelist ${HOME}/.local/share/supertux2
22whitelist /usr/share/supertux2 22whitelist /usr/share/supertux2
23whitelist /usr/share/games/supertux2 # Debian version
23include whitelist-common.inc 24include whitelist-common.inc
24include whitelist-runuser-common.inc 25include whitelist-runuser-common.inc
25include whitelist-usr-share-common.inc 26include whitelist-usr-share-common.inc
diff --git a/etc/profile-m-z/supertuxkart.profile b/etc/profile-m-z/supertuxkart.profile
index 6a0ed46e0..4eb8f921c 100644
--- a/etc/profile-m-z/supertuxkart.profile
+++ b/etc/profile-m-z/supertuxkart.profile
@@ -10,6 +10,8 @@ noblacklist ${HOME}/.config/supertuxkart
10noblacklist ${HOME}/.cache/supertuxkart 10noblacklist ${HOME}/.cache/supertuxkart
11noblacklist ${HOME}/.local/share/supertuxkart 11noblacklist ${HOME}/.local/share/supertuxkart
12 12
13blacklist /usr/libexec
14
13include disable-common.inc 15include disable-common.inc
14include disable-devel.inc 16include disable-devel.inc
15include disable-exec.inc 17include disable-exec.inc
@@ -26,6 +28,7 @@ whitelist ${HOME}/.config/supertuxkart
26whitelist ${HOME}/.cache/supertuxkart 28whitelist ${HOME}/.cache/supertuxkart
27whitelist ${HOME}/.local/share/supertuxkart 29whitelist ${HOME}/.local/share/supertuxkart
28whitelist /usr/share/supertuxkart 30whitelist /usr/share/supertuxkart
31whitelist /usr/share/games/supertuxkart # Debian version
29include whitelist-common.inc 32include whitelist-common.inc
30include whitelist-runuser-common.inc 33include whitelist-runuser-common.inc
31include whitelist-usr-share-common.inc 34include whitelist-usr-share-common.inc
diff --git a/etc/profile-m-z/telegram-desktop.profile b/etc/profile-m-z/telegram-desktop.profile
index e0c5aee9e..7463b761f 100644
--- a/etc/profile-m-z/telegram-desktop.profile
+++ b/etc/profile-m-z/telegram-desktop.profile
@@ -2,7 +2,7 @@
2# Description: Official Telegram Desktop client 2# Description: Official Telegram Desktop client
3# This file is overwritten after every install/update 3# This file is overwritten after every install/update
4# Persistent local customizations 4# Persistent local customizations
5include tekegram-desktop.local 5include telegram-desktop.local
6# Persistent global definitions 6# Persistent global definitions
7# added by included profile 7# added by included profile
8#include globals.local 8#include globals.local
diff --git a/etc/profile-m-z/tin.profile b/etc/profile-m-z/tin.profile
new file mode 100644
index 000000000..e0ed3090a
--- /dev/null
+++ b/etc/profile-m-z/tin.profile
@@ -0,0 +1,69 @@
1# Firejail profile for tin
2# Description: ncurses-based Usenet newsreader
3# This file is overwritten after every install/update
4# Persistent local customizations
5include tin.local
6# Persistent global definitions
7include globals.local
8
9noblacklist ${HOME}/.newsrc
10noblacklist ${HOME}/.tin
11
12blacklist /tmp/.X11-unix
13blacklist ${RUNUSER}
14blacklist /usr/libexec
15
16include disable-common.inc
17include disable-devel.inc
18include disable-exec.inc
19include disable-interpreters.inc
20include disable-passwdmgr.inc
21include disable-programs.inc
22include disable-shell.inc
23include disable-xdg.inc
24
25mkdir ${HOME}/.tin
26mkfile ${HOME}/.newsrc
27# Note: files/directories directly in ${HOME} can't be whitelisted, as
28# tin saves .newsrc by renaming a temporary file, which is not possible for
29# bind-mounted files.
30#whitelist ${HOME}/.newsrc
31#whitelist ${HOME}/.tin
32#include whitelist-common.inc
33include whitelist-runuser-common.inc
34include whitelist-usr-share-common.inc
35include whitelist-var-common.inc
36
37apparmor
38caps.drop all
39ipc-namespace
40machine-id
41netfilter
42no3d
43nodvd
44nogroups
45noinput
46nonewprivs
47noroot
48nosound
49notv
50nou2f
51novideo
52protocol inet,inet6
53seccomp
54seccomp.block-secondary
55shell none
56tracelog
57
58disable-mnt
59private-bin rtin,tin
60private-cache
61private-dev
62private-etc passwd,resolv.conf,terminfo,tin
63private-lib terminfo
64private-tmp
65
66dbus-user none
67dbus-system none
68
69memory-deny-write-execute
diff --git a/etc/profile-m-z/tuxguitar.profile b/etc/profile-m-z/tuxguitar.profile
index d0bcbe79f..3cd496412 100644
--- a/etc/profile-m-z/tuxguitar.profile
+++ b/etc/profile-m-z/tuxguitar.profile
@@ -6,6 +6,9 @@ include tuxguitar.local
6# Persistent global definitions 6# Persistent global definitions
7include globals.local 7include globals.local
8 8
9# tuxguitar fails to launch
10ignore noexec ${HOME}
11
9noblacklist ${HOME}/.tuxguitar* 12noblacklist ${HOME}/.tuxguitar*
10noblacklist ${DOCUMENTS} 13noblacklist ${DOCUMENTS}
11noblacklist ${MUSIC} 14noblacklist ${MUSIC}
@@ -41,6 +44,3 @@ tracelog
41 44
42private-dev 45private-dev
43private-tmp 46private-tmp
44
45# noexec ${HOME} - tuxguitar may fail to launch
46noexec /tmp
diff --git a/etc/profile-m-z/w3m.profile b/etc/profile-m-z/w3m.profile
index 131213ed2..69b2c6c59 100644
--- a/etc/profile-m-z/w3m.profile
+++ b/etc/profile-m-z/w3m.profile
@@ -17,18 +17,32 @@ noblacklist ${HOME}/.w3m
17blacklist /tmp/.X11-unix 17blacklist /tmp/.X11-unix
18blacklist ${RUNUSER}/wayland-* 18blacklist ${RUNUSER}/wayland-*
19 19
20# Allow /bin/sh (blacklisted by disable-shell.inc)
21include allow-bin-sh.inc
22
23# Allow perl (blacklisted by disable-interpreters.inc)
20include allow-perl.inc 24include allow-perl.inc
21 25
22include disable-common.inc 26include disable-common.inc
23include disable-devel.inc 27include disable-devel.inc
28include disable-exec.inc
24include disable-interpreters.inc 29include disable-interpreters.inc
25include disable-passwdmgr.inc 30include disable-passwdmgr.inc
26include disable-programs.inc 31include disable-programs.inc
32include disable-shell.inc
27include disable-xdg.inc 33include disable-xdg.inc
28 34
35mkdir ${HOME}/.w3m
36whitelist /usr/share/w3m
37whitelist ${DOWNLOADS}
38whitelist ${HOME}/.w3m
29include whitelist-runuser-common.inc 39include whitelist-runuser-common.inc
40include whitelist-usr-share-common.inc
41include whitelist-var-common.inc
30 42
31caps.drop all 43caps.drop all
44ipc-namespace
45machine-id
32netfilter 46netfilter
33no3d 47no3d
34nodvd 48nodvd
@@ -45,8 +59,14 @@ seccomp
45shell none 59shell none
46tracelog 60tracelog
47 61
48# private-bin w3m 62disable-mnt
63private-bin perl,sh,w3m
49private-cache 64private-cache
50private-dev 65private-dev
51private-etc alternatives,ca-certificates,crypto-policies,pki,resolv.conf,ssl 66private-etc alternatives,ca-certificates,crypto-policies,mailcap,nsswitch.conf,pki,resolv.conf,ssl
52private-tmp 67private-tmp
68
69dbus-user none
70dbus-system none
71
72memory-deny-write-execute
diff --git a/etc/profile-m-z/weechat.profile b/etc/profile-m-z/weechat.profile
index 3a93d2ec7..76935212f 100644
--- a/etc/profile-m-z/weechat.profile
+++ b/etc/profile-m-z/weechat.profile
@@ -11,6 +11,7 @@ noblacklist ${HOME}/.weechat
11include disable-common.inc 11include disable-common.inc
12include disable-programs.inc 12include disable-programs.inc
13 13
14whitelist /usr/share/weechat
14include whitelist-usr-share-common.inc 15include whitelist-usr-share-common.inc
15include whitelist-var-common.inc 16include whitelist-var-common.inc
16 17
diff --git a/etc/profile-m-z/xlinks.profile b/etc/profile-m-z/xlinks.profile
index 7987af280..d5e25cfe7 100644
--- a/etc/profile-m-z/xlinks.profile
+++ b/etc/profile-m-z/xlinks.profile
@@ -8,7 +8,6 @@ include xlinks.local
8#include globals.local 8#include globals.local
9 9
10noblacklist /tmp/.X11-unix 10noblacklist /tmp/.X11-unix
11noblacklist ${HOME}/.links
12 11
13include whitelist-common.inc 12include whitelist-common.inc
14 13
diff --git a/etc/profile-m-z/xlinks2 b/etc/profile-m-z/xlinks2
new file mode 100644
index 000000000..1ae6a60ca
--- /dev/null
+++ b/etc/profile-m-z/xlinks2
@@ -0,0 +1,20 @@
1# Firejail profile for xlinks2
2# Description: Text WWW browser (X11)
3# This file is overwritten after every install/update
4# Persistent local customizations
5include xlinks2.local
6# Persistent global definitions
7# added by included profile
8#include globals.local
9
10noblacklist /tmp/.X11-unix
11
12include whitelist-common.inc
13
14# if you want to use user-configured programs add 'private-bin PROGRAM1,PROGRAM2'
15# to your xlinks.local or append 'PROGRAM1,PROGRAM2' to this private-bin line
16private-bin xlinks2
17private-etc fonts
18
19# Redirect
20include links2.profile
diff --git a/etc/profile-m-z/yelp.profile b/etc/profile-m-z/yelp.profile
index 93054bfed..dee154409 100644
--- a/etc/profile-m-z/yelp.profile
+++ b/etc/profile-m-z/yelp.profile
@@ -19,6 +19,7 @@ include disable-xdg.inc
19 19
20mkdir ${HOME}/.config/yelp 20mkdir ${HOME}/.config/yelp
21whitelist ${HOME}/.config/yelp 21whitelist ${HOME}/.config/yelp
22whitelist /usr/libexec/webkit2gtk-4.0
22whitelist /usr/share/doc 23whitelist /usr/share/doc
23whitelist /usr/share/groff 24whitelist /usr/share/groff
24whitelist /usr/share/help 25whitelist /usr/share/help
diff --git a/etc/profile-m-z/zathura.profile b/etc/profile-m-z/zathura.profile
index a39729685..d0e68c980 100644
--- a/etc/profile-m-z/zathura.profile
+++ b/etc/profile-m-z/zathura.profile
@@ -17,12 +17,14 @@ include disable-interpreters.inc
17include disable-passwdmgr.inc 17include disable-passwdmgr.inc
18include disable-programs.inc 18include disable-programs.inc
19include disable-shell.inc 19include disable-shell.inc
20include disable-write-mnt.inc
20include disable-xdg.inc 21include disable-xdg.inc
21 22
22mkdir ${HOME}/.config/zathura 23mkdir ${HOME}/.config/zathura
23mkdir ${HOME}/.local/share/zathura 24mkdir ${HOME}/.local/share/zathura
24whitelist /usr/share/doc 25whitelist /usr/share/doc
25whitelist /usr/share/zathura 26whitelist /usr/share/zathura
27include whitelist-runuser-common.inc
26include whitelist-usr-share-common.inc 28include whitelist-usr-share-common.inc
27include whitelist-var-common.inc 29include whitelist-var-common.inc
28 30
@@ -41,6 +43,7 @@ nou2f
41novideo 43novideo
42protocol unix 44protocol unix
43seccomp 45seccomp
46seccomp.block-secondary
44shell none 47shell none
45tracelog 48tracelog
46 49
diff --git a/etc/templates/profile.template b/etc/templates/profile.template
index fcc7fe949..18e4e8bce 100644
--- a/etc/templates/profile.template
+++ b/etc/templates/profile.template
@@ -59,14 +59,6 @@ include globals.local
59##ignore noexec ${HOME} 59##ignore noexec ${HOME}
60##ignore noexec /tmp 60##ignore noexec /tmp
61 61
62##blacklist PATH
63# Disable X11 (CLI only), see also 'x11 none' below
64#blacklist /tmp/.X11-unix
65# Disable Wayland
66#blacklist ${RUNUSER}/wayland-*
67# Disable RUNUSER (cli only; supersedes Disable Wayland)
68#blacklist ${RUNUSER}
69
70# It is common practice to add files/dirs containing program-specific configuration 62# It is common practice to add files/dirs containing program-specific configuration
71# (often ${HOME}/PROGRAMNAME or ${HOME}/.config/PROGRAMNAME) into disable-programs.inc 63# (often ${HOME}/PROGRAMNAME or ${HOME}/.config/PROGRAMNAME) into disable-programs.inc
72# (keep list sorted) and then disable blacklisting below. 64# (keep list sorted) and then disable blacklisting below.
@@ -109,6 +101,17 @@ include globals.local
109# Allow ssh (blacklisted by disable-common.inc) 101# Allow ssh (blacklisted by disable-common.inc)
110#include allow-ssh.inc 102#include allow-ssh.inc
111 103
104##blacklist PATH
105# Disable X11 (CLI only), see also 'x11 none' below
106#blacklist /tmp/.X11-unix
107# Disable Wayland
108#blacklist ${RUNUSER}/wayland-*
109# Disable RUNUSER (cli only; supersedes Disable Wayland)
110#blacklist ${RUNUSER}
111# Remove the next blacklist if you system has no /usr/libexec dir,
112# otherwise try to add it.
113#blacklist /usr/libexec
114
112# disable-*.inc includes 115# disable-*.inc includes
113# remove disable-write-mnt.inc if you set disable-mnt 116# remove disable-write-mnt.inc if you set disable-mnt
114#include disable-common.inc 117#include disable-common.inc
@@ -189,7 +192,7 @@ include globals.local
189# GUI: fonts,pango,X11 192# GUI: fonts,pango,X11
190# GTK: dconf,gconf,gtk-2.0,gtk-3.0 193# GTK: dconf,gconf,gtk-2.0,gtk-3.0
191# KDE: kde4rc,kde5rc 194# KDE: kde4rc,kde5rc
192# Networking: ca-certificates,crypto-policies,host.conf,hostname,hosts,nsswitch.conf,pki,protocols,resolv.conf,services,rpc,ssl 195# Networking: ca-certificates,crypto-policies,host.conf,hostname,hosts,nsswitch.conf,pki,protocols,resolv.conf,rpc,services,ssl
193# Extra: gai.conf,proxychains.conf 196# Extra: gai.conf,proxychains.conf
194# Qt: Trolltech.conf 197# Qt: Trolltech.conf
195##private-lib LIBS 198##private-lib LIBS
diff --git a/platform/rpm/firejail.spec b/platform/rpm/firejail.spec
index acdc8d561..86cd6006e 100644
--- a/platform/rpm/firejail.spec
+++ b/platform/rpm/firejail.spec
@@ -45,8 +45,8 @@ rm -rf %{buildroot}
45%{_mandir}/man1/__NAME__.1.gz 45%{_mandir}/man1/__NAME__.1.gz
46%{_mandir}/man1/firecfg.1.gz 46%{_mandir}/man1/firecfg.1.gz
47%{_mandir}/man1/firemon.1.gz 47%{_mandir}/man1/firemon.1.gz
48%{_mandir}/man1/jailcheck.1.gz
48%{_mandir}/man5/__NAME__-login.5.gz 49%{_mandir}/man5/__NAME__-login.5.gz
49%{_mandir}/man5/__NAME__-profile.5.gz 50%{_mandir}/man5/__NAME__-profile.5.gz
50%{_mandir}/man5/__NAME__-users.5.gz 51%{_mandir}/man5/__NAME__-users.5.gz
51%{_mandir}/man5/jailcheck.5.gz
52%config(noreplace) %{_sysconfdir}/__NAME__ 52%config(noreplace) %{_sysconfdir}/__NAME__
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
index 572e9f601..31810de9a 100644
--- a/src/fcopy/main.c
+++ b/src/fcopy/main.c
@@ -19,11 +19,15 @@
19 */ 19 */
20 20
21#include "../include/common.h" 21#include "../include/common.h"
22#include <fcntl.h>
23#include <ftw.h> 22#include <ftw.h>
24#include <errno.h> 23#include <errno.h>
25#include <pwd.h> 24#include <pwd.h>
26 25
26#include <fcntl.h>
27#ifndef O_PATH
28#define O_PATH 010000000
29#endif
30
27#if HAVE_SELINUX 31#if HAVE_SELINUX
28#include <sys/stat.h> 32#include <sys/stat.h>
29#include <sys/types.h> 33#include <sys/types.h>
@@ -55,7 +59,7 @@ static void selinux_relabel_path(const char *path, const char *inside_path) {
55 assert(path); 59 assert(path);
56 assert(inside_path); 60 assert(inside_path);
57#if HAVE_SELINUX 61#if HAVE_SELINUX
58 char procfs_path[64]; 62 char procfs_path[64];
59 char *fcon = NULL; 63 char *fcon = NULL;
60 int fd; 64 int fd;
61 struct stat st; 65 struct stat st;
@@ -69,20 +73,23 @@ static void selinux_relabel_path(const char *path, const char *inside_path) {
69 if (!label_hnd) 73 if (!label_hnd)
70 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0); 74 label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
71 75
76 if (!label_hnd)
77 errExit("selabel_open");
78
72 /* Open the file as O_PATH, to pin it while we determine and adjust the label */ 79 /* Open the file as O_PATH, to pin it while we determine and adjust the label */
73 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); 80 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
74 if (fd < 0) 81 if (fd < 0)
75 return; 82 return;
76 if (fstat(fd, &st) < 0) 83 if (fstat(fd, &st) < 0)
77 goto close; 84 goto close;
78 85
79 if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) == 0) { 86 if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) == 0) {
80 sprintf(procfs_path, "/proc/self/fd/%i", fd); 87 sprintf(procfs_path, "/proc/self/fd/%i", fd);
81 if (arg_debug) 88 if (arg_debug)
82 printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon); 89 printf("Relabeling %s as %s (%s)\n", path, inside_path, fcon);
83 90
84 setfilecon_raw(procfs_path, fcon); 91 setfilecon_raw(procfs_path, fcon);
85 } 92 }
86 freecon(fcon); 93 freecon(fcon);
87 close: 94 close:
88 close(fd); 95 close(fd);
@@ -340,7 +347,7 @@ static char *check(const char *src) {
340 347
341errexit: 348errexit:
342 free(rsrc); 349 free(rsrc);
343 fprintf(stderr, "Error fcopy: invalid file %s\n", src); 350 fprintf(stderr, "Error fcopy: invalid ownership for file %s\n", src);
344 exit(1); 351 exit(1);
345} 352}
346 353
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index f0e3a887f..e58fe39ec 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -38,6 +38,8 @@ abrowser
38akonadi_control 38akonadi_control
39akregator 39akregator
40alacarte 40alacarte
41alpine
42alpinef
41amarok 43amarok
42amule 44amule
43amuled 45amuled
@@ -167,6 +169,7 @@ cvlc
167cyberfox 169cyberfox
168darktable 170darktable
169dconf-editor 171dconf-editor
172ddgr
170ddgtk 173ddgtk
171deadbeef 174deadbeef
172deluge 175deluge
@@ -350,6 +353,7 @@ google-chrome-unstable
350google-earth 353google-earth
351google-earth-pro 354google-earth-pro
352google-play-music-desktop-player 355google-play-music-desktop-player
356googler
353gpa 357gpa
354gpicview 358gpicview
355gpredict 359gpredict
@@ -452,6 +456,7 @@ liferea
452lightsoff 456lightsoff
453lincity-ng 457lincity-ng
454links 458links
459links2
455linphone 460linphone
456lmms 461lmms
457lobase 462lobase
@@ -491,6 +496,7 @@ mathematica
491matrix-mirage 496matrix-mirage
492mattermost-desktop 497mattermost-desktop
493mcabber 498mcabber
499mcomix
494mediainfo 500mediainfo
495mediathekview 501mediathekview
496megaglest 502megaglest
@@ -651,6 +657,7 @@ pybitmessage
651# pycharm-professional 657# pycharm-professional
652# pzstd - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095) 658# pzstd - disable until we fix CLI archivers for makepkg on Arch (see discussion in #3095)
653qbittorrent 659qbittorrent
660qcomicbook
654qemu-launcher 661qemu-launcher
655qgis 662qgis
656qlipper 663qlipper
@@ -871,6 +878,7 @@ xfce4-notes
871xfce4-screenshooter 878xfce4-screenshooter
872xiphos 879xiphos
873xlinks 880xlinks
881xlinks2
874xmms 882xmms
875xmr-stak 883xmr-stak
876xonotic 884xonotic
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
index 6b9fed765..a96415985 100644
--- a/src/firejail/appimage.c
+++ b/src/firejail/appimage.c
@@ -28,8 +28,13 @@
28#include <linux/loop.h> 28#include <linux/loop.h>
29#include <errno.h> 29#include <errno.h>
30 30
31#ifdef HAVE_GCOV
32#include <gcov.h>
33#endif
34
31static char *devloop = NULL; // device file 35static char *devloop = NULL; // device file
32static long unsigned size = 0; // offset into appimage file 36static long unsigned size = 0; // offset into appimage file
37#define MAXBUF 4096
33 38
34#ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h 39#ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h
35static void err_loop(void) { 40static void err_loop(void) {
@@ -38,6 +43,36 @@ static void err_loop(void) {
38} 43}
39#endif 44#endif
40 45
46// return 1 if found
47int appimage_find_profile(const char *archive) {
48 assert(archive);
49 assert(strlen(archive));
50
51 // try to match the name of the archive with the list of programs in /usr/lib/firejail/firecfg.config
52 FILE *fp = fopen(LIBDIR "/firejail/firecfg.config", "r");
53 if (!fp) {
54 fprintf(stderr, "Error: cannot find %s, firejail is not correctly installed\n", LIBDIR "/firejail/firecfg.config");
55 exit(1);
56 }
57 char buf[MAXBUF];
58 while (fgets(buf, MAXBUF, fp)) {
59 if (*buf == '#')
60 continue;
61 char *ptr = strchr(buf, '\n');
62 if (ptr)
63 *ptr = '\0';
64 if (strcasestr(archive, buf)) {
65 fclose(fp);
66 return profile_find_firejail(buf, 1);
67 }
68 }
69
70 fclose(fp);
71 return 0;
72
73}
74
75
41void appimage_set(const char *appimage) { 76void appimage_set(const char *appimage) {
42 assert(appimage); 77 assert(appimage);
43 assert(devloop == NULL); // don't call this twice! 78 assert(devloop == NULL); // don't call this twice!
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c
index cb087d395..f3ab0a6d8 100644
--- a/src/firejail/checkcfg.c
+++ b/src/firejail/checkcfg.c
@@ -110,10 +110,14 @@ int checkcfg(int val) {
110 PARSE_YESNO(CFG_RESTRICTED_NETWORK, "restricted-network") 110 PARSE_YESNO(CFG_RESTRICTED_NETWORK, "restricted-network")
111 PARSE_YESNO(CFG_XEPHYR_WINDOW_TITLE, "xephyr-window-title") 111 PARSE_YESNO(CFG_XEPHYR_WINDOW_TITLE, "xephyr-window-title")
112 PARSE_YESNO(CFG_OVERLAYFS, "overlayfs") 112 PARSE_YESNO(CFG_OVERLAYFS, "overlayfs")
113 PARSE_YESNO(CFG_PRIVATE_HOME, "private-home") 113 PARSE_YESNO(CFG_PRIVATE_BIN, "private-bin")
114 PARSE_YESNO(CFG_PRIVATE_BIN_NO_LOCAL, "private-bin-no-local")
114 PARSE_YESNO(CFG_PRIVATE_CACHE, "private-cache") 115 PARSE_YESNO(CFG_PRIVATE_CACHE, "private-cache")
116 PARSE_YESNO(CFG_PRIVATE_ETC, "private-etc")
117 PARSE_YESNO(CFG_PRIVATE_HOME, "private-home")
115 PARSE_YESNO(CFG_PRIVATE_LIB, "private-lib") 118 PARSE_YESNO(CFG_PRIVATE_LIB, "private-lib")
116 PARSE_YESNO(CFG_PRIVATE_BIN_NO_LOCAL, "private-bin-no-local") 119 PARSE_YESNO(CFG_PRIVATE_OPT, "private-opt")
120 PARSE_YESNO(CFG_PRIVATE_SRV, "private-srv")
117 PARSE_YESNO(CFG_DISABLE_MNT, "disable-mnt") 121 PARSE_YESNO(CFG_DISABLE_MNT, "disable-mnt")
118 PARSE_YESNO(CFG_XPRA_ATTACH, "xpra-attach") 122 PARSE_YESNO(CFG_XPRA_ATTACH, "xpra-attach")
119 PARSE_YESNO(CFG_BROWSER_DISABLE_U2F, "browser-disable-u2f") 123 PARSE_YESNO(CFG_BROWSER_DISABLE_U2F, "browser-disable-u2f")
@@ -130,8 +134,7 @@ int checkcfg(int val) {
130 *end = '\0'; 134 *end = '\0';
131 135
132 // is the file present? 136 // is the file present?
133 struct stat s; 137 if (access(fname, F_OK) == -1) {
134 if (stat(fname, &s) == -1) {
135 fprintf(stderr, "Error: netfilter-default file %s not available\n", fname); 138 fprintf(stderr, "Error: netfilter-default file %s not available\n", fname);
136 exit(1); 139 exit(1);
137 } 140 }
@@ -294,7 +297,7 @@ errout:
294 297
295void print_compiletime_support(void) { 298void print_compiletime_support(void) {
296 printf("Compile time support:\n"); 299 printf("Compile time support:\n");
297 printf("\t- Always force nonewprivs support is %s\n", 300 printf("\t- always force nonewprivs support is %s\n",
298#ifdef HAVE_FORCE_NONEWPRIVS 301#ifdef HAVE_FORCE_NONEWPRIVS
299 "enabled" 302 "enabled"
300#else 303#else
diff --git a/src/firejail/chroot.c b/src/firejail/chroot.c
index 757ffb1f7..edc31cdea 100644
--- a/src/firejail/chroot.c
+++ b/src/firejail/chroot.c
@@ -29,6 +29,9 @@
29#define O_PATH 010000000 29#define O_PATH 010000000
30#endif 30#endif
31 31
32#ifdef HAVE_GCOV
33#include <gcov.h>
34#endif
32 35
33// exit if error 36// exit if error
34void fs_check_chroot_dir(void) { 37void fs_check_chroot_dir(void) {
@@ -163,12 +166,8 @@ void fs_chroot(const char *rootdir) {
163 int fd = openat(parentfd, "dev", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 166 int fd = openat(parentfd, "dev", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
164 if (fd == -1) 167 if (fd == -1)
165 errExit("open"); 168 errExit("open");
166 char *proc; 169 if (bind_mount_path_to_fd("/dev", fd))
167 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
168 errExit("asprintf");
169 if (mount("/dev", proc, NULL, MS_BIND|MS_REC, NULL) < 0)
170 errExit("mounting /dev"); 170 errExit("mounting /dev");
171 free(proc);
172 close(fd); 171 close(fd);
173 172
174#ifdef HAVE_X11 173#ifdef HAVE_X11
@@ -192,11 +191,8 @@ void fs_chroot(const char *rootdir) {
192 fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 191 fd = openat(parentfd, "tmp/.X11-unix", O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
193 if (fd == -1) 192 if (fd == -1)
194 errExit("open"); 193 errExit("open");
195 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 194 if (bind_mount_path_to_fd("/tmp/.X11-unix", fd))
196 errExit("asprintf");
197 if (mount("/tmp/.X11-unix", proc, NULL, MS_BIND|MS_REC, NULL) < 0)
198 errExit("mounting /tmp/.X11-unix"); 195 errExit("mounting /tmp/.X11-unix");
199 free(proc);
200 close(fd); 196 close(fd);
201 } 197 }
202#endif // HAVE_X11 198#endif // HAVE_X11
@@ -225,19 +221,11 @@ void fs_chroot(const char *rootdir) {
225 fprintf(stderr, "Error: cannot open %s\n", pulse); 221 fprintf(stderr, "Error: cannot open %s\n", pulse);
226 exit(1); 222 exit(1);
227 } 223 }
228 free(pulse); 224 if (bind_mount_by_fd(src, dst))
229 225 errExit("mounting pulseaudio");
230 char *proc_src, *proc_dst;
231 if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1)
232 errExit("asprintf");
233 if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1)
234 errExit("asprintf");
235 if (mount(proc_src, proc_dst, NULL, MS_BIND|MS_REC, NULL) < 0)
236 errExit("mount bind");
237 free(proc_src);
238 free(proc_dst);
239 close(src); 226 close(src);
240 close(dst); 227 close(dst);
228 free(pulse);
241 229
242 // update /etc/machine-id in chroot 230 // update /etc/machine-id in chroot
243 update_file(parentfd, "etc/machine-id"); 231 update_file(parentfd, "etc/machine-id");
@@ -256,11 +244,8 @@ void fs_chroot(const char *rootdir) {
256 fd = openat(parentfd, &RUN_FIREJAIL_LIB_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 244 fd = openat(parentfd, &RUN_FIREJAIL_LIB_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
257 if (fd == -1) 245 if (fd == -1)
258 errExit("open"); 246 errExit("open");
259 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 247 if (bind_mount_path_to_fd(RUN_FIREJAIL_LIB_DIR, fd))
260 errExit("asprintf");
261 if (mount(RUN_FIREJAIL_LIB_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0)
262 errExit("mount bind"); 248 errExit("mount bind");
263 free(proc);
264 close(fd); 249 close(fd);
265 250
266 // create /run/firejail/mnt directory in chroot 251 // create /run/firejail/mnt directory in chroot
@@ -271,11 +256,8 @@ void fs_chroot(const char *rootdir) {
271 fd = openat(parentfd, &RUN_MNT_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 256 fd = openat(parentfd, &RUN_MNT_DIR[1], O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
272 if (fd == -1) 257 if (fd == -1)
273 errExit("open"); 258 errExit("open");
274 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 259 if (bind_mount_path_to_fd(RUN_MNT_DIR, fd))
275 errExit("asprintf");
276 if (mount(RUN_MNT_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0)
277 errExit("mount bind"); 260 errExit("mount bind");
278 free(proc);
279 close(fd); 261 close(fd);
280 262
281 // update chroot resolv.conf 263 // update chroot resolv.conf
@@ -289,11 +271,8 @@ void fs_chroot(const char *rootdir) {
289 if (mkdir(oroot, 0755) == -1) 271 if (mkdir(oroot, 0755) == -1)
290 errExit("mkdir"); 272 errExit("mkdir");
291 // mount the chroot dir on top of /run/firejail/mnt/oroot in order to reuse the apparmor rules for overlay 273 // mount the chroot dir on top of /run/firejail/mnt/oroot in order to reuse the apparmor rules for overlay
292 if (asprintf(&proc, "/proc/self/fd/%d", parentfd) == -1) 274 if (bind_mount_fd_to_path(parentfd, oroot))
293 errExit("asprintf");
294 if (mount(proc, oroot, NULL, MS_BIND|MS_REC, NULL) < 0)
295 errExit("mounting rootdir oroot"); 275 errExit("mounting rootdir oroot");
296 free(proc);
297 close(parentfd); 276 close(parentfd);
298 // chroot into the new directory 277 // chroot into the new directory
299 if (arg_debug) 278 if (arg_debug)
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c
index f902c4e1c..2fa68a55d 100644
--- a/src/firejail/cmdline.c
+++ b/src/firejail/cmdline.c
@@ -26,7 +26,7 @@
26#include <assert.h> 26#include <assert.h>
27#include <errno.h> 27#include <errno.h>
28 28
29static int cmdline_length(int argc, char **argv, int index) { 29static int cmdline_length(int argc, char **argv, int index, bool want_extra_quotes) {
30 assert(index != -1); 30 assert(index != -1);
31 31
32 unsigned i,j; 32 unsigned i,j;
@@ -46,10 +46,11 @@ static int cmdline_length(int argc, char **argv, int index) {
46 len += 3; 46 len += 3;
47 in_quotes = false; 47 in_quotes = false;
48 } else { 48 } else {
49 if (!in_quotes) 49 if (!in_quotes && want_extra_quotes)
50 len++; 50 len++;
51 len++; 51 len++;
52 in_quotes = true; 52 if (want_extra_quotes)
53 in_quotes = true;
53 } 54 }
54 } 55 }
55 if (in_quotes) { 56 if (in_quotes) {
@@ -64,7 +65,7 @@ static int cmdline_length(int argc, char **argv, int index) {
64 return len; 65 return len;
65} 66}
66 67
67static void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) { 68static void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index, bool want_extra_quotes) {
68 assert(index != -1); 69 assert(index != -1);
69 70
70 unsigned i,j; 71 unsigned i,j;
@@ -103,14 +104,15 @@ static void quote_cmdline(char *command_line, char *window_title, int len, int a
103 // anything other 104 // anything other
104 else 105 else
105 { 106 {
106 if (!in_quotes) { 107 if (!in_quotes && want_extra_quotes) {
107 // open quotes 108 // open quotes
108 ptr1[0] = '\''; 109 ptr1[0] = '\'';
109 ptr1++; 110 ptr1++;
110 } 111 }
111 ptr1[0] = argv[i + index][j]; 112 ptr1[0] = argv[i + index][j];
112 ptr1++; 113 ptr1++;
113 in_quotes = true; 114 if (want_extra_quotes)
115 in_quotes = true;
114 } 116 }
115 } 117 }
116 // close quotes 118 // close quotes
@@ -134,12 +136,12 @@ static void quote_cmdline(char *command_line, char *window_title, int len, int a
134 assert((unsigned) len == strlen(command_line)); 136 assert((unsigned) len == strlen(command_line));
135} 137}
136 138
137void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { 139void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes) {
138 // index == -1 could happen if we have --shell=none and no program was specified 140 // index == -1 could happen if we have --shell=none and no program was specified
139 // the program should exit with an error before entering this function 141 // the program should exit with an error before entering this function
140 assert(index != -1); 142 assert(index != -1);
141 143
142 int len = cmdline_length(argc, argv, index); 144 int len = cmdline_length(argc, argv, index, want_extra_quotes);
143 if (len > ARG_MAX) { 145 if (len > ARG_MAX) {
144 errno = E2BIG; 146 errno = E2BIG;
145 errExit("cmdline_length"); 147 errExit("cmdline_length");
@@ -152,7 +154,7 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar
152 if (!*window_title) 154 if (!*window_title)
153 errExit("malloc"); 155 errExit("malloc");
154 156
155 quote_cmdline(*command_line, *window_title, len, argc, argv, index); 157 quote_cmdline(*command_line, *window_title, len, argc, argv, index, want_extra_quotes);
156 158
157 if (arg_debug) 159 if (arg_debug)
158 printf("Building quoted command line: %s\n", *command_line); 160 printf("Building quoted command line: %s\n", *command_line);
@@ -161,17 +163,17 @@ void build_cmdline(char **command_line, char **window_title, int argc, char **ar
161 assert(*window_title); 163 assert(*window_title);
162} 164}
163 165
164void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { 166void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes) {
165 // index == -1 could happen if we have --shell=none and no program was specified 167 // index == -1 could happen if we have --shell=none and no program was specified
166 // the program should exit with an error before entering this function 168 // the program should exit with an error before entering this function
167 assert(index != -1); 169 assert(index != -1);
168 170
169 char *apprun_path = RUN_FIREJAIL_APPIMAGE_DIR "/AppRun"; 171 char *apprun_path = RUN_FIREJAIL_APPIMAGE_DIR "/AppRun";
170 172
171 int len1 = cmdline_length(argc, argv, index); // length of argv w/o changes 173 int len1 = cmdline_length(argc, argv, index, want_extra_quotes); // length of argv w/o changes
172 int len2 = cmdline_length(1, &argv[index], 0); // apptest.AppImage 174 int len2 = cmdline_length(1, &argv[index], 0, want_extra_quotes); // apptest.AppImage
173 int len3 = cmdline_length(1, &apprun_path, 0); // /run/firejail/appimage/AppRun 175 int len3 = cmdline_length(1, &apprun_path, 0, want_extra_quotes); // /run/firejail/appimage/AppRun
174 int len4 = (len1 - len2 + len3) + 1; // apptest.AppImage is replaced by /path/to/AppRun 176 int len4 = (len1 - len2 + len3) + 1; // apptest.AppImage is replaced by /path/to/AppRun
175 177
176 if (len4 > ARG_MAX) { 178 if (len4 > ARG_MAX) {
177 errno = E2BIG; 179 errno = E2BIG;
@@ -187,7 +189,7 @@ void build_appimage_cmdline(char **command_line, char **window_title, int argc,
187 errExit("malloc"); 189 errExit("malloc");
188 190
189 // run default quote_cmdline 191 // run default quote_cmdline
190 quote_cmdline(command_line_tmp, *window_title, len1, argc, argv, index); 192 quote_cmdline(command_line_tmp, *window_title, len1, argc, argv, index, want_extra_quotes);
191 193
192 assert(command_line_tmp); 194 assert(command_line_tmp);
193 assert(*window_title); 195 assert(*window_title);
diff --git a/src/firejail/dbus.c b/src/firejail/dbus.c
index b8aa2c974..9a4cb2e6b 100644
--- a/src/firejail/dbus.c
+++ b/src/firejail/dbus.c
@@ -258,12 +258,8 @@ static char *find_user_socket_by_format(char *format) {
258 if (asprintf(&dbus_user_socket, format, (int) getuid()) == -1) 258 if (asprintf(&dbus_user_socket, format, (int) getuid()) == -1)
259 errExit("asprintf"); 259 errExit("asprintf");
260 struct stat s; 260 struct stat s;
261 if (stat(dbus_user_socket, &s) == -1) { 261 if (lstat(dbus_user_socket, &s) == -1)
262 if (errno == ENOENT) 262 goto fail;
263 goto fail;
264 return NULL;
265 errExit("stat");
266 }
267 if (!S_ISSOCK(s.st_mode)) 263 if (!S_ISSOCK(s.st_mode))
268 goto fail; 264 goto fail;
269 return dbus_user_socket; 265 return dbus_user_socket;
@@ -426,12 +422,8 @@ static void socket_overlay(char *socket_path, char *proxy_path) {
426 errno = ENOTSOCK; 422 errno = ENOTSOCK;
427 errExit("mounting DBus proxy socket"); 423 errExit("mounting DBus proxy socket");
428 } 424 }
429 char *proxy_fd_path; 425 if (bind_mount_fd_to_path(fd, socket_path))
430 if (asprintf(&proxy_fd_path, "/proc/self/fd/%d", fd) == -1)
431 errExit("asprintf");
432 if (mount(proxy_path, socket_path, NULL, MS_BIND | MS_REC, NULL) == -1)
433 errExit("mount bind"); 426 errExit("mount bind");
434 free(proxy_fd_path);
435 close(fd); 427 close(fd);
436} 428}
437 429
@@ -478,7 +470,7 @@ void dbus_apply_policy(void) {
478 create_empty_dir_as_root(RUN_DBUS_DIR, 0755); 470 create_empty_dir_as_root(RUN_DBUS_DIR, 0755);
479 471
480 if (arg_dbus_user != DBUS_POLICY_ALLOW) { 472 if (arg_dbus_user != DBUS_POLICY_ALLOW) {
481 create_empty_file_as_root(RUN_DBUS_USER_SOCKET, 0700); 473 create_empty_file_as_root(RUN_DBUS_USER_SOCKET, 0600);
482 474
483 if (arg_dbus_user == DBUS_POLICY_FILTER) { 475 if (arg_dbus_user == DBUS_POLICY_FILTER) {
484 assert(dbus_user_proxy_socket != NULL); 476 assert(dbus_user_proxy_socket != NULL);
@@ -517,7 +509,7 @@ void dbus_apply_policy(void) {
517 } 509 }
518 510
519 if (arg_dbus_system != DBUS_POLICY_ALLOW) { 511 if (arg_dbus_system != DBUS_POLICY_ALLOW) {
520 create_empty_file_as_root(RUN_DBUS_SYSTEM_SOCKET, 0700); 512 create_empty_file_as_root(RUN_DBUS_SYSTEM_SOCKET, 0600);
521 513
522 if (arg_dbus_system == DBUS_POLICY_FILTER) { 514 if (arg_dbus_system == DBUS_POLICY_FILTER) {
523 assert(dbus_system_proxy_socket != NULL); 515 assert(dbus_system_proxy_socket != NULL);
diff --git a/src/firejail/dhcp.c b/src/firejail/dhcp.c
index 5bcdcad37..ec482e2ea 100644
--- a/src/firejail/dhcp.c
+++ b/src/firejail/dhcp.c
@@ -153,19 +153,13 @@ void dhcp_start(void) {
153 if (!any_dhcp()) 153 if (!any_dhcp())
154 return; 154 return;
155 155
156 char *dhclient_path = RUN_MNT_DIR "/dhclient";; 156 char *dhclient_path = RUN_MNT_DIR "/dhclient";
157 struct stat s; 157 struct stat s;
158 if (stat(dhclient_path, &s) == -1) { 158 if (stat(dhclient_path, &s) == -1) {
159 dhclient_path = "/usr/sbin/dhclient"; 159 fprintf(stderr, "Error: %s was not found.\n", dhclient_path);
160 if (stat(dhclient_path, &s) == -1) { 160 exit(1);
161 fprintf(stderr, "Error: dhclient was not found.\n");
162 exit(1);
163 }
164 } 161 }
165 162
166 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 4, PATH_FCOPY, "--follow-link", dhclient_path, RUN_MNT_DIR);
167 dhclient_path = RUN_MNT_DIR "/dhclient";
168
169 EUID_ROOT(); 163 EUID_ROOT();
170 if (mkdir(RUN_DHCLIENT_DIR, 0700)) 164 if (mkdir(RUN_DHCLIENT_DIR, 0700))
171 errExit("mkdir"); 165 errExit("mkdir");
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 756a5d095..c84965074 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -5,7 +5,7 @@
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify 6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or 8 * the Free Software Foundation; eithe r version 2 of the License, or
9 * (at your option) any later version. 9 * (at your option) any later version.
10 * 10 *
11 * This program is distributed in the hope that it will be useful, 11 * This program is distributed in the hope that it will be useful,
@@ -45,6 +45,15 @@
45 assert(s.st_gid == gid);\ 45 assert(s.st_gid == gid);\
46 assert((s.st_mode & 07777) == (mode));\ 46 assert((s.st_mode & 07777) == (mode));\
47 } while (0) 47 } while (0)
48#define ASSERT_PERMS_AS_USER(file, uid, gid, mode) \
49 do { \
50 assert(file);\
51 struct stat s;\
52 if (stat_as_user(file, &s) == -1) errExit("stat");\
53 assert(s.st_uid == uid);\
54 assert(s.st_gid == gid);\
55 assert((s.st_mode & 07777) == (mode));\
56 } while (0)
48#define ASSERT_PERMS_FD(fd, uid, gid, mode) \ 57#define ASSERT_PERMS_FD(fd, uid, gid, mode) \
49 do { \ 58 do { \
50 struct stat s;\ 59 struct stat s;\
@@ -504,6 +513,9 @@ void copy_file_from_user_to_root(const char *srcname, const char *destname, uid_
504void touch_file_as_user(const char *fname, mode_t mode); 513void touch_file_as_user(const char *fname, mode_t mode);
505int is_dir(const char *fname); 514int is_dir(const char *fname);
506int is_link(const char *fname); 515int is_link(const char *fname);
516char *realpath_as_user(const char *fname);
517int stat_as_user(const char *fname, struct stat *s);
518int lstat_as_user(const char *fname, struct stat *s);
507void trim_trailing_slash_or_dot(char *path); 519void trim_trailing_slash_or_dot(char *path);
508char *line_remove_spaces(const char *buf); 520char *line_remove_spaces(const char *buf);
509char *split_comma(char *str); 521char *split_comma(char *str);
@@ -527,11 +539,15 @@ unsigned extract_timeout(const char *str);
527void disable_file_or_dir(const char *fname); 539void disable_file_or_dir(const char *fname);
528void disable_file_path(const char *path, const char *file); 540void disable_file_path(const char *path, const char *file);
529int safer_openat(int dirfd, const char *path, int flags); 541int safer_openat(int dirfd, const char *path, int flags);
542int remount_by_fd(int dst, unsigned long mountflags);
543int bind_mount_by_fd(int src, int dst);
544int bind_mount_path_to_fd(const char *srcname, int dst);
545int bind_mount_fd_to_path(int src, const char *destname);
530int has_handler(pid_t pid, int signal); 546int has_handler(pid_t pid, int signal);
531void enter_network_namespace(pid_t pid); 547void enter_network_namespace(pid_t pid);
532int read_pid(const char *name, pid_t *pid); 548int read_pid(const char *name, pid_t *pid);
533pid_t require_pid(const char *name); 549pid_t require_pid(const char *name);
534void check_homedir(void); 550void check_homedir(const char *dir);
535 551
536// Get info regarding the last kernel mount operation from /proc/self/mountinfo 552// Get info regarding the last kernel mount operation from /proc/self/mountinfo
537// The return value points to a static area, and will be overwritten by subsequent calls. 553// The return value points to a static area, and will be overwritten by subsequent calls.
@@ -763,8 +779,14 @@ enum {
763 CFG_WHITELIST, 779 CFG_WHITELIST,
764 CFG_XEPHYR_WINDOW_TITLE, 780 CFG_XEPHYR_WINDOW_TITLE,
765 CFG_OVERLAYFS, 781 CFG_OVERLAYFS,
766 CFG_PRIVATE_HOME, 782 CFG_PRIVATE_BIN,
767 CFG_PRIVATE_BIN_NO_LOCAL, 783 CFG_PRIVATE_BIN_NO_LOCAL,
784 CFG_PRIVATE_CACHE,
785 CFG_PRIVATE_ETC,
786 CFG_PRIVATE_HOME,
787 CFG_PRIVATE_LIB,
788 CFG_PRIVATE_OPT,
789 CFG_PRIVATE_SRV,
768 CFG_FIREJAIL_PROMPT, 790 CFG_FIREJAIL_PROMPT,
769 CFG_DISABLE_MNT, 791 CFG_DISABLE_MNT,
770 CFG_JOIN, 792 CFG_JOIN,
@@ -772,10 +794,8 @@ enum {
772 CFG_XPRA_ATTACH, 794 CFG_XPRA_ATTACH,
773 CFG_BROWSER_DISABLE_U2F, 795 CFG_BROWSER_DISABLE_U2F,
774 CFG_BROWSER_ALLOW_DRM, 796 CFG_BROWSER_ALLOW_DRM,
775 CFG_PRIVATE_LIB,
776 CFG_APPARMOR, 797 CFG_APPARMOR,
777 CFG_DBUS, 798 CFG_DBUS,
778 CFG_PRIVATE_CACHE,
779 CFG_CGROUP, 799 CFG_CGROUP,
780 CFG_NAME_CHANGE, 800 CFG_NAME_CHANGE,
781 CFG_SECCOMP_ERROR_ACTION, 801 CFG_SECCOMP_ERROR_ACTION,
@@ -796,6 +816,7 @@ int checkcfg(int val);
796void print_compiletime_support(void); 816void print_compiletime_support(void);
797 817
798// appimage.c 818// appimage.c
819int appimage_find_profile(const char *archive);
799void appimage_set(const char *appimage_path); 820void appimage_set(const char *appimage_path);
800void appimage_mount(void); 821void appimage_mount(void);
801void appimage_clear(void); 822void appimage_clear(void);
@@ -804,8 +825,8 @@ void appimage_clear(void);
804long unsigned int appimage2_size(int fd); 825long unsigned int appimage2_size(int fd);
805 826
806// cmdline.c 827// cmdline.c
807void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); 828void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes);
808void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); 829void build_appimage_cmdline(char **command_line, char **window_title, int argc, char **argv, int index, bool want_extra_quotes);
809 830
810// sbox.c 831// sbox.c
811// programs 832// programs
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 09de11de9..4ae7dbfa4 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -33,6 +33,10 @@
33#define O_PATH 010000000 33#define O_PATH 010000000
34#endif 34#endif
35 35
36#ifdef HAVE_GCOV
37#include <gcov.h>
38#endif
39
36#define MAX_BUF 4096 40#define MAX_BUF 4096
37#define EMPTY_STRING ("") 41#define EMPTY_STRING ("")
38// check noblacklist statements not matched by a proper blacklist in disable-*.inc files 42// check noblacklist statements not matched by a proper blacklist in disable-*.inc files
@@ -54,16 +58,10 @@ static char *opstr[] = {
54 [MOUNT_RDWR_NOCHECK] = "read-write", 58 [MOUNT_RDWR_NOCHECK] = "read-write",
55}; 59};
56 60
57typedef enum {
58 UNSUCCESSFUL,
59 SUCCESSFUL
60} LAST_DISABLE_OPERATION;
61LAST_DISABLE_OPERATION last_disable = UNSUCCESSFUL;
62
63static void disable_file(OPERATION op, const char *filename) { 61static void disable_file(OPERATION op, const char *filename) {
64 assert(filename); 62 assert(filename);
65 assert(op <OPERATION_MAX); 63 assert(op <OPERATION_MAX);
66 last_disable = UNSUCCESSFUL; 64 EUID_ASSERT();
67 65
68 // Resolve all symlinks 66 // Resolve all symlinks
69 char* fname = realpath(filename, NULL); 67 char* fname = realpath(filename, NULL);
@@ -71,20 +69,24 @@ static void disable_file(OPERATION op, const char *filename) {
71 return; 69 return;
72 } 70 }
73 if (fname == NULL && errno == EACCES) { 71 if (fname == NULL && errno == EACCES) {
74 if (arg_debug)
75 printf("Debug: no access to file %s, forcing mount\n", filename);
76 // realpath and stat functions will fail on FUSE filesystems 72 // realpath and stat functions will fail on FUSE filesystems
77 // they don't seem to like a uid of 0 73 // they don't seem to like a uid of 0
78 // force mounting 74 // force mounting
79 int rv = mount(RUN_RO_DIR, filename, "none", MS_BIND, "mode=400,gid=0"); 75 int fd = open(filename, O_PATH|O_CLOEXEC);
80 if (rv == 0) 76 if (fd < 0) {
81 last_disable = SUCCESSFUL; 77 if (arg_debug)
82 else { 78 printf("Warning (blacklisting): cannot open %s: %s\n", filename, strerror(errno));
83 rv = mount(RUN_RO_FILE, filename, "none", MS_BIND, "mode=400,gid=0"); 79 return;
84 if (rv == 0)
85 last_disable = SUCCESSFUL;
86 } 80 }
87 if (last_disable == SUCCESSFUL) { 81
82 EUID_ROOT();
83 int err = bind_mount_path_to_fd(RUN_RO_DIR, fd);
84 if (err != 0)
85 err = bind_mount_path_to_fd(RUN_RO_FILE, fd);
86 EUID_USER();
87 close(fd);
88
89 if (err == 0) {
88 if (arg_debug) 90 if (arg_debug)
89 printf("Disable %s\n", filename); 91 printf("Disable %s\n", filename);
90 if (op == BLACKLIST_FILE) 92 if (op == BLACKLIST_FILE)
@@ -92,21 +94,18 @@ static void disable_file(OPERATION op, const char *filename) {
92 else 94 else
93 fs_logger2("blacklist-nolog", filename); 95 fs_logger2("blacklist-nolog", filename);
94 } 96 }
95 else { 97 else if (arg_debug)
96 if (arg_debug) 98 printf("Warning (blacklisting): cannot mount on %s\n", filename);
97 printf("Warning (blacklisting): %s is an invalid file, skipping...\n", filename);
98 }
99 99
100 return; 100 return;
101 } 101 }
102 102
103 // if the file is not present, do nothing 103 // if the file is not present, do nothing
104 assert(fname);
104 struct stat s; 105 struct stat s;
105 if (fname == NULL) 106 if (stat(fname, &s) < 0) {
106 return;
107 if (stat(fname, &s) == -1) {
108 if (arg_debug) 107 if (arg_debug)
109 fwarning("%s does not exist, skipping...\n", fname); 108 printf("Warning (blacklisting): cannot access %s: %s\n", fname, strerror(errno));
110 free(fname); 109 free(fname);
111 return; 110 return;
112 } 111 }
@@ -115,8 +114,10 @@ static void disable_file(OPERATION op, const char *filename) {
115 // we migth have a file found in ${PATH} pointing to /usr/bin/firejail 114 // we migth have a file found in ${PATH} pointing to /usr/bin/firejail
116 // blacklisting it here will end up breaking situations like user clicks on a link in Thunderbird 115 // blacklisting it here will end up breaking situations like user clicks on a link in Thunderbird
117 // and expects Firefox to open in the same sandbox 116 // and expects Firefox to open in the same sandbox
118 if (strcmp(BINDIR "/firejail", fname) == 0) 117 if (strcmp(BINDIR "/firejail", fname) == 0) {
118 free(fname);
119 return; 119 return;
120 }
120 121
121 // modify the file 122 // modify the file
122 if (op == BLACKLIST_FILE || op == BLACKLIST_NOLOG) { 123 if (op == BLACKLIST_FILE || op == BLACKLIST_NOLOG) {
@@ -141,15 +142,25 @@ static void disable_file(OPERATION op, const char *filename) {
141 printf(" - no logging\n"); 142 printf(" - no logging\n");
142 } 143 }
143 144
145 int fd = open(fname, O_PATH|O_CLOEXEC);
146 if (fd < 0) {
147 if (arg_debug)
148 printf("Warning (blacklisting): cannot open %s: %s\n", fname, strerror(errno));
149 free(fname);
150 return;
151 }
152 EUID_ROOT();
144 if (S_ISDIR(s.st_mode)) { 153 if (S_ISDIR(s.st_mode)) {
145 if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) 154 if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0)
146 errExit("disable file"); 155 errExit("disable file");
147 } 156 }
148 else { 157 else {
149 if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) 158 if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0)
150 errExit("disable file"); 159 errExit("disable file");
151 } 160 }
152 last_disable = SUCCESSFUL; 161 EUID_USER();
162 close(fd);
163
153 if (op == BLACKLIST_FILE) 164 if (op == BLACKLIST_FILE)
154 fs_logger2("blacklist", fname); 165 fs_logger2("blacklist", fname);
155 else 166 else
@@ -158,23 +169,30 @@ static void disable_file(OPERATION op, const char *filename) {
158 } 169 }
159 else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) { 170 else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) {
160 fs_remount_rec(fname, op); 171 fs_remount_rec(fname, op);
161 // todo: last_disable = SUCCESSFUL;
162 } 172 }
163 else if (op == MOUNT_TMPFS) { 173 else if (op == MOUNT_TMPFS) {
164 if (S_ISDIR(s.st_mode)) { 174 if (!S_ISDIR(s.st_mode)) {
165 if (getuid()) { 175 fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname);
166 if (strncmp(cfg.homedir, fname, strlen(cfg.homedir)) != 0 || 176 free(fname);
167 fname[strlen(cfg.homedir)] != '/') { 177 return;
168 fprintf(stderr, "Error: tmpfs outside $HOME is only available for root\n"); 178 }
169 exit(1); 179
170 } 180 uid_t uid = getuid();
181 if (uid != 0) {
182 // only user owned directories in user home
183 if (s.st_uid != uid ||
184 strncmp(cfg.homedir, fname, strlen(cfg.homedir)) != 0 ||
185 fname[strlen(cfg.homedir)] != '/') {
186 fwarning("you are not allowed to mount a tmpfs on %s\n", fname);
187 free(fname);
188 return;
171 } 189 }
172 fs_tmpfs(fname, getuid());
173 selinux_relabel_path(fname, fname);
174 last_disable = SUCCESSFUL;
175 } 190 }
176 else 191
177 fwarning("%s is not a directory; cannot mount a tmpfs on top of it.\n", fname); 192 fs_tmpfs(fname, uid);
193 EUID_USER(); // fs_tmpfs returns with EUID 0
194
195 selinux_relabel_path(fname, fname);
178 } 196 }
179 else 197 else
180 assert(0); 198 assert(0);
@@ -191,6 +209,7 @@ static int *nbcheck = NULL;
191// Treat pattern as a shell glob pattern and blacklist matching files 209// Treat pattern as a shell glob pattern and blacklist matching files
192static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len) { 210static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len) {
193 assert(pattern); 211 assert(pattern);
212 EUID_ASSERT();
194 213
195#ifdef TEST_NO_BLACKLIST_MATCHING 214#ifdef TEST_NO_BLACKLIST_MATCHING
196 if (nbcheck_start == 0) { 215 if (nbcheck_start == 0) {
@@ -264,6 +283,7 @@ void fs_blacklist(void) {
264 if (noblacklist == NULL) 283 if (noblacklist == NULL)
265 errExit("failed allocating memory for noblacklist entries"); 284 errExit("failed allocating memory for noblacklist entries");
266 285
286 EUID_USER();
267 while (entry) { 287 while (entry) {
268 OPERATION op = OPERATION_MAX; 288 OPERATION op = OPERATION_MAX;
269 char *ptr; 289 char *ptr;
@@ -294,11 +314,13 @@ void fs_blacklist(void) {
294 if (arg_debug) 314 if (arg_debug)
295 printf("Mount-bind %s on top of %s\n", dname1, dname2); 315 printf("Mount-bind %s on top of %s\n", dname1, dname2);
296 // preserve dname2 mode and ownership 316 // preserve dname2 mode and ownership
317 // EUID_ROOT(); - option not accessible to non-root users
297 if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0) 318 if (mount(dname1, dname2, NULL, MS_BIND|MS_REC, NULL) < 0)
298 errExit("mount bind"); 319 errExit("mount bind");
299 /* coverity[toctou] */ 320 /* coverity[toctou] */
300 if (set_perms(dname2, s.st_uid, s.st_gid,s.st_mode)) 321 if (set_perms(dname2, s.st_uid, s.st_gid,s.st_mode))
301 errExit("set_perms"); 322 errExit("set_perms");
323 // EUID_USER();
302 324
303 entry = entry->next; 325 entry = entry->next;
304 continue; 326 continue;
@@ -376,16 +398,12 @@ void fs_blacklist(void) {
376 op = MOUNT_TMPFS; 398 op = MOUNT_TMPFS;
377 } 399 }
378 else if (strncmp(entry->data, "mkdir ", 6) == 0) { 400 else if (strncmp(entry->data, "mkdir ", 6) == 0) {
379 EUID_USER();
380 fs_mkdir(entry->data + 6); 401 fs_mkdir(entry->data + 6);
381 EUID_ROOT();
382 entry = entry->next; 402 entry = entry->next;
383 continue; 403 continue;
384 } 404 }
385 else if (strncmp(entry->data, "mkfile ", 7) == 0) { 405 else if (strncmp(entry->data, "mkfile ", 7) == 0) {
386 EUID_USER();
387 fs_mkfile(entry->data + 7); 406 fs_mkfile(entry->data + 7);
388 EUID_ROOT();
389 entry = entry->next; 407 entry = entry->next;
390 continue; 408 continue;
391 } 409 }
@@ -441,6 +459,8 @@ void fs_blacklist(void) {
441 for (i = 0; i < noblacklist_c; i++) 459 for (i = 0; i < noblacklist_c; i++)
442 free(noblacklist[i]); 460 free(noblacklist[i]);
443 free(noblacklist); 461 free(noblacklist);
462
463 EUID_ROOT();
444} 464}
445 465
446//*********************************************** 466//***********************************************
@@ -449,6 +469,7 @@ void fs_blacklist(void) {
449 469
450// mount a writable tmpfs on directory; requires a resolved path 470// mount a writable tmpfs on directory; requires a resolved path
451void fs_tmpfs(const char *dir, unsigned check_owner) { 471void fs_tmpfs(const char *dir, unsigned check_owner) {
472 EUID_USER();
452 assert(dir); 473 assert(dir);
453 if (arg_debug) 474 if (arg_debug)
454 printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no"); 475 printf("Mounting tmpfs on %s, check owner: %s\n", dir, (check_owner)? "yes": "no");
@@ -473,6 +494,7 @@ void fs_tmpfs(const char *dir, unsigned check_owner) {
473 errExit("fstatvfs"); 494 errExit("fstatvfs");
474 unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND); 495 unsigned long flags = buf.f_flag & ~(MS_RDONLY|MS_BIND);
475 // mount via the symbolic link in /proc/self/fd 496 // mount via the symbolic link in /proc/self/fd
497 EUID_ROOT();
476 char *proc; 498 char *proc;
477 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 499 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
478 errExit("asprintf"); 500 errExit("asprintf");
@@ -490,38 +512,42 @@ void fs_tmpfs(const char *dir, unsigned check_owner) {
490 512
491// remount path, preserving other mount flags; requires a resolved path 513// remount path, preserving other mount flags; requires a resolved path
492static void fs_remount_simple(const char *path, OPERATION op) { 514static void fs_remount_simple(const char *path, OPERATION op) {
515 EUID_ASSERT();
493 assert(path); 516 assert(path);
494 517
495 // open path without following symbolic links 518 // open path without following symbolic links
496 int fd1 = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); 519 int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
497 if (fd1 == -1) 520 if (fd < 0)
498 goto out; 521 goto out;
499 struct stat s1; 522
500 if (fstat(fd1, &s1) == -1) { 523 struct stat s;
524 if (fstat(fd, &s) < 0) {
501 // fstat can fail with EACCES if path is a FUSE mount, 525 // fstat can fail with EACCES if path is a FUSE mount,
502 // mounted without 'allow_root' or 'allow_other' 526 // mounted without 'allow_root' or 'allow_other'
503 if (errno != EACCES) 527 if (errno != EACCES)
504 errExit("fstat"); 528 errExit("fstat");
505 close(fd1); 529 close(fd);
506 goto out; 530 goto out;
507 } 531 }
508 // get mount flags 532 // get mount flags
509 struct statvfs buf; 533 struct statvfs buf;
510 if (fstatvfs(fd1, &buf) == -1) 534 if (fstatvfs(fd, &buf) < 0) {
511 errExit("fstatvfs"); 535 close(fd);
536 goto out;
537 }
512 unsigned long flags = buf.f_flag; 538 unsigned long flags = buf.f_flag;
513 539
514 // read-write option 540 // read-write option
515 if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) { 541 if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) {
516 // nothing to do if there is no read-only flag 542 // nothing to do if there is no read-only flag
517 if ((flags & MS_RDONLY) == 0) { 543 if ((flags & MS_RDONLY) == 0) {
518 close(fd1); 544 close(fd);
519 return; 545 return;
520 } 546 }
521 // allow only user owned directories, except the user is root 547 // allow only user owned directories, except the user is root
522 if (op != MOUNT_RDWR_NOCHECK && getuid() != 0 && s1.st_uid != getuid()) { 548 if (op != MOUNT_RDWR_NOCHECK && getuid() != 0 && s.st_uid != getuid()) {
523 fwarning("you are not allowed to change %s to read-write\n", path); 549 fwarning("you are not allowed to change %s to read-write\n", path);
524 close(fd1); 550 close(fd);
525 return; 551 return;
526 } 552 }
527 flags &= ~MS_RDONLY; 553 flags &= ~MS_RDONLY;
@@ -530,7 +556,7 @@ static void fs_remount_simple(const char *path, OPERATION op) {
530 else if (op == MOUNT_NOEXEC) { 556 else if (op == MOUNT_NOEXEC) {
531 // nothing to do if path is mounted noexec already 557 // nothing to do if path is mounted noexec already
532 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) { 558 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) {
533 close(fd1); 559 close(fd);
534 return; 560 return;
535 } 561 }
536 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID; 562 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID;
@@ -539,7 +565,7 @@ static void fs_remount_simple(const char *path, OPERATION op) {
539 else if (op == MOUNT_READONLY) { 565 else if (op == MOUNT_READONLY) {
540 // nothing to do if path is mounted read-only already 566 // nothing to do if path is mounted read-only already
541 if ((flags & MS_RDONLY) == MS_RDONLY) { 567 if ((flags & MS_RDONLY) == MS_RDONLY) {
542 close(fd1); 568 close(fd);
543 return; 569 return;
544 } 570 }
545 flags |= MS_RDONLY; 571 flags |= MS_RDONLY;
@@ -549,29 +575,37 @@ static void fs_remount_simple(const char *path, OPERATION op) {
549 575
550 if (arg_debug) 576 if (arg_debug)
551 printf("Mounting %s %s\n", opstr[op], path); 577 printf("Mounting %s %s\n", opstr[op], path);
578
579 // make path a mount point:
552 // mount --bind path path 580 // mount --bind path path
553 char *proc; 581 EUID_ROOT();
554 if (asprintf(&proc, "/proc/self/fd/%d", fd1) == -1) 582 int err = bind_mount_by_fd(fd, fd);
555 errExit("asprintf"); 583 EUID_USER();
556 if (mount(proc, proc, NULL, MS_BIND|MS_REC, NULL) < 0) 584 if (err) {
557 errExit("mount"); 585 close(fd);
558 free(proc); 586 goto out;
587 }
559 588
560 // mount --bind -o remount,ro path 589 // remount the mount point
561 // need to open path again without following symbolic links 590 // need to open path again
562 int fd2 = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); 591 int fd2 = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
563 if (fd2 == -1) 592 close(fd); // earliest timepoint to close fd
564 errExit("open"); 593 if (fd2 < 0)
594 goto out;
595
596 // device and inode number should be the same
565 struct stat s2; 597 struct stat s2;
566 if (fstat(fd2, &s2) == -1) 598 if (fstat(fd2, &s2) < 0)
567 errExit("fstat"); 599 errExit("fstat");
568 // device and inode number should be the same 600 if (s.st_dev != s2.st_dev || s.st_ino != s2.st_ino)
569 if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
570 errLogExit("invalid %s mount", opstr[op]); 601 errLogExit("invalid %s mount", opstr[op]);
571 if (asprintf(&proc, "/proc/self/fd/%d", fd2) == -1) 602
572 errExit("asprintf"); 603 EUID_ROOT();
573 if (mount(NULL, proc, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0) 604 err = remount_by_fd(fd2, flags);
574 errExit("mount"); 605 EUID_USER();
606 close(fd2);
607 if (err)
608 goto out;
575 609
576 // run a sanity check on /proc/self/mountinfo and confirm that target of the last 610 // run a sanity check on /proc/self/mountinfo and confirm that target of the last
577 // mount operation was path; if there are other mount points contained inside path, 611 // mount operation was path; if there are other mount points contained inside path,
@@ -582,10 +616,8 @@ static void fs_remount_simple(const char *path, OPERATION op) {
582 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) 616 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/'))
583 && strcmp(path, "/") != 0) // support read-only=/ 617 && strcmp(path, "/") != 0) // support read-only=/
584 errLogExit("invalid %s mount", opstr[op]); 618 errLogExit("invalid %s mount", opstr[op]);
619
585 fs_logger2(opstr[op], path); 620 fs_logger2(opstr[op], path);
586 free(proc);
587 close(fd1);
588 close(fd2);
589 return; 621 return;
590 622
591out: 623out:
@@ -594,7 +626,9 @@ out:
594 626
595// remount recursively; requires a resolved path 627// remount recursively; requires a resolved path
596static void fs_remount_rec(const char *dir, OPERATION op) { 628static void fs_remount_rec(const char *dir, OPERATION op) {
629 EUID_ASSERT();
597 assert(dir); 630 assert(dir);
631
598 struct stat s; 632 struct stat s;
599 if (stat(dir, &s) != 0) 633 if (stat(dir, &s) != 0)
600 return; 634 return;
@@ -632,6 +666,14 @@ static void fs_remount_rec(const char *dir, OPERATION op) {
632// resolve a path and remount it 666// resolve a path and remount it
633void fs_remount(const char *path, OPERATION op, int rec) { 667void fs_remount(const char *path, OPERATION op, int rec) {
634 assert(path); 668 assert(path);
669
670 int called_as_root = 0;
671 if (geteuid() == 0)
672 called_as_root = 1;
673
674 if (called_as_root)
675 EUID_USER();
676
635 char *rpath = realpath(path, NULL); 677 char *rpath = realpath(path, NULL);
636 if (rpath) { 678 if (rpath) {
637 if (rec) 679 if (rec)
@@ -640,10 +682,14 @@ void fs_remount(const char *path, OPERATION op, int rec) {
640 fs_remount_simple(rpath, op); 682 fs_remount_simple(rpath, op);
641 free(rpath); 683 free(rpath);
642 } 684 }
685
686 if (called_as_root)
687 EUID_ROOT();
643} 688}
644 689
645// Disable /mnt, /media, /run/mount and /run/media access 690// Disable /mnt, /media, /run/mount and /run/media access
646void fs_mnt(const int enforce) { 691void fs_mnt(const int enforce) {
692 EUID_USER();
647 if (enforce) { 693 if (enforce) {
648 // disable-mnt set in firejail.config 694 // disable-mnt set in firejail.config
649 // overriding with noblacklist is not possible in this case 695 // overriding with noblacklist is not possible in this case
@@ -653,13 +699,12 @@ void fs_mnt(const int enforce) {
653 disable_file(BLACKLIST_FILE, "/run/media"); 699 disable_file(BLACKLIST_FILE, "/run/media");
654 } 700 }
655 else { 701 else {
656 EUID_USER();
657 profile_add("blacklist /mnt"); 702 profile_add("blacklist /mnt");
658 profile_add("blacklist /media"); 703 profile_add("blacklist /media");
659 profile_add("blacklist /run/mount"); 704 profile_add("blacklist /run/mount");
660 profile_add("blacklist /run/media"); 705 profile_add("blacklist /run/media");
661 EUID_ROOT();
662 } 706 }
707 EUID_ROOT();
663} 708}
664 709
665 710
@@ -674,7 +719,6 @@ void fs_proc_sys_dev_boot(void) {
674 errExit("mounting /proc/sys"); 719 errExit("mounting /proc/sys");
675 fs_logger("read-only /proc/sys"); 720 fs_logger("read-only /proc/sys");
676 721
677
678 /* Mount a version of /sys that describes the network namespace */ 722 /* Mount a version of /sys that describes the network namespace */
679 if (arg_debug) 723 if (arg_debug)
680 printf("Remounting /sys directory\n"); 724 printf("Remounting /sys directory\n");
@@ -689,13 +733,13 @@ void fs_proc_sys_dev_boot(void) {
689 else 733 else
690 fs_logger("remount /sys"); 734 fs_logger("remount /sys");
691 735
736 EUID_USER();
737
692 disable_file(BLACKLIST_FILE, "/sys/firmware"); 738 disable_file(BLACKLIST_FILE, "/sys/firmware");
693 disable_file(BLACKLIST_FILE, "/sys/hypervisor"); 739 disable_file(BLACKLIST_FILE, "/sys/hypervisor");
694 { // allow user access to some directories in /sys/ by specifying 'noblacklist' option 740 { // allow user access to some directories in /sys/ by specifying 'noblacklist' option
695 EUID_USER();
696 profile_add("blacklist /sys/fs"); 741 profile_add("blacklist /sys/fs");
697 profile_add("blacklist /sys/module"); 742 profile_add("blacklist /sys/module");
698 EUID_ROOT();
699 } 743 }
700 disable_file(BLACKLIST_FILE, "/sys/power"); 744 disable_file(BLACKLIST_FILE, "/sys/power");
701 disable_file(BLACKLIST_FILE, "/sys/kernel/debug"); 745 disable_file(BLACKLIST_FILE, "/sys/kernel/debug");
@@ -739,12 +783,8 @@ void fs_proc_sys_dev_boot(void) {
739 // disable /dev/port 783 // disable /dev/port
740 disable_file(BLACKLIST_FILE, "/dev/port"); 784 disable_file(BLACKLIST_FILE, "/dev/port");
741 785
742
743
744 // disable various ipc sockets in /run/user 786 // disable various ipc sockets in /run/user
745 if (!arg_writable_run_user) { 787 if (!arg_writable_run_user) {
746 struct stat s;
747
748 char *fname; 788 char *fname;
749 if (asprintf(&fname, "/run/user/%d", getuid()) == -1) 789 if (asprintf(&fname, "/run/user/%d", getuid()) == -1)
750 errExit("asprintf"); 790 errExit("asprintf");
@@ -755,8 +795,7 @@ void fs_proc_sys_dev_boot(void) {
755 errExit("asprintf"); 795 errExit("asprintf");
756 if (create_empty_dir_as_user(fnamegpg, 0700)) 796 if (create_empty_dir_as_user(fnamegpg, 0700))
757 fs_logger2("create", fnamegpg); 797 fs_logger2("create", fnamegpg);
758 if (stat(fnamegpg, &s) == 0) 798 disable_file(BLACKLIST_FILE, fnamegpg);
759 disable_file(BLACKLIST_FILE, fnamegpg);
760 free(fnamegpg); 799 free(fnamegpg);
761 800
762 // disable /run/user/{uid}/systemd 801 // disable /run/user/{uid}/systemd
@@ -765,8 +804,7 @@ void fs_proc_sys_dev_boot(void) {
765 errExit("asprintf"); 804 errExit("asprintf");
766 if (create_empty_dir_as_user(fnamesysd, 0755)) 805 if (create_empty_dir_as_user(fnamesysd, 0755))
767 fs_logger2("create", fnamesysd); 806 fs_logger2("create", fnamesysd);
768 if (stat(fnamesysd, &s) == 0) 807 disable_file(BLACKLIST_FILE, fnamesysd);
769 disable_file(BLACKLIST_FILE, fnamesysd);
770 free(fnamesysd); 808 free(fnamesysd);
771 } 809 }
772 free(fname); 810 free(fname);
@@ -777,35 +815,30 @@ void fs_proc_sys_dev_boot(void) {
777 disable_file(BLACKLIST_FILE, "/dev/kmsg"); 815 disable_file(BLACKLIST_FILE, "/dev/kmsg");
778 disable_file(BLACKLIST_FILE, "/proc/kmsg"); 816 disable_file(BLACKLIST_FILE, "/proc/kmsg");
779 } 817 }
818
819 EUID_ROOT();
780} 820}
781 821
782// disable firejail configuration in ~/.config/firejail 822// disable firejail configuration in ~/.config/firejail
783void disable_config(void) { 823void disable_config(void) {
784 struct stat s; 824 EUID_USER();
785
786 char *fname; 825 char *fname;
787 if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1) 826 if (asprintf(&fname, "%s/.config/firejail", cfg.homedir) == -1)
788 errExit("asprintf"); 827 errExit("asprintf");
789 if (stat(fname, &s) == 0) 828 disable_file(BLACKLIST_FILE, fname);
790 disable_file(BLACKLIST_FILE, fname);
791 free(fname); 829 free(fname);
792 830
793 // disable run time information 831 // disable run time information
794 if (stat(RUN_FIREJAIL_NETWORK_DIR, &s) == 0) 832 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NETWORK_DIR);
795 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NETWORK_DIR); 833 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_BANDWIDTH_DIR);
796 if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s) == 0) 834 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NAME_DIR);
797 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_BANDWIDTH_DIR); 835 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR);
798 if (stat(RUN_FIREJAIL_NAME_DIR, &s) == 0) 836 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR);
799 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_NAME_DIR); 837 EUID_ROOT();
800 if (stat(RUN_FIREJAIL_PROFILE_DIR, &s) == 0)
801 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_PROFILE_DIR);
802 if (stat(RUN_FIREJAIL_X11_DIR, &s) == 0)
803 disable_file(BLACKLIST_FILE, RUN_FIREJAIL_X11_DIR);
804} 838}
805 839
806 840
807// build a basic read-only filesystem 841// build a basic read-only filesystem
808// top level directories could be links, run no after-mount checks
809void fs_basic_fs(void) { 842void fs_basic_fs(void) {
810 uid_t uid = getuid(); 843 uid_t uid = getuid();
811 844
@@ -815,6 +848,7 @@ void fs_basic_fs(void) {
815 if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) 848 if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
816 errExit("mounting /proc"); 849 errExit("mounting /proc");
817 850
851 EUID_USER();
818 if (arg_debug) 852 if (arg_debug)
819 printf("Basic read-only filesystem:\n"); 853 printf("Basic read-only filesystem:\n");
820 if (!arg_writable_etc) { 854 if (!arg_writable_etc) {
@@ -834,6 +868,7 @@ void fs_basic_fs(void) {
834 fs_remount("/lib64", MOUNT_READONLY, 1); 868 fs_remount("/lib64", MOUNT_READONLY, 1);
835 fs_remount("/lib32", MOUNT_READONLY, 1); 869 fs_remount("/lib32", MOUNT_READONLY, 1);
836 fs_remount("/libx32", MOUNT_READONLY, 1); 870 fs_remount("/libx32", MOUNT_READONLY, 1);
871 EUID_ROOT();
837 872
838 // update /var directory in order to support multiple sandboxes running on the same root directory 873 // update /var directory in order to support multiple sandboxes running on the same root directory
839 fs_var_lock(); 874 fs_var_lock();
@@ -862,6 +897,7 @@ void fs_basic_fs(void) {
862#ifdef HAVE_OVERLAYFS 897#ifdef HAVE_OVERLAYFS
863char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { 898char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) {
864 assert(subdirname); 899 assert(subdirname);
900 EUID_ASSERT();
865 struct stat s; 901 struct stat s;
866 char *dirname; 902 char *dirname;
867 903
@@ -1221,6 +1257,7 @@ void fs_overlayfs(void) {
1221 1257
1222// this function is called from sandbox.c before blacklist/whitelist functions 1258// this function is called from sandbox.c before blacklist/whitelist functions
1223void fs_private_tmp(void) { 1259void fs_private_tmp(void) {
1260 EUID_ASSERT();
1224 if (arg_debug) 1261 if (arg_debug)
1225 printf("Generate private-tmp whitelist commands\n"); 1262 printf("Generate private-tmp whitelist commands\n");
1226 1263
@@ -1241,8 +1278,8 @@ void fs_private_tmp(void) {
1241 1278
1242 // whitelist x11 directory 1279 // whitelist x11 directory
1243 profile_add("whitelist /tmp/.X11-unix"); 1280 profile_add("whitelist /tmp/.X11-unix");
1244 // read-only x11 directory 1281 // read-only x11 directory
1245 profile_add("read-only /tmp/.X11-unix"); 1282 profile_add("read-only /tmp/.X11-unix");
1246 1283
1247 // whitelist any pulse* file in /tmp directory 1284 // whitelist any pulse* file in /tmp directory
1248 // some distros use PulseAudio sockets under /tmp instead of the socket in /urn/user 1285 // some distros use PulseAudio sockets under /tmp instead of the socket in /urn/user
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index 8c2870a4d..8cc3ecc62 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -187,8 +187,10 @@ static void mount_dev_shm(void) {
187static void process_dev_shm(void) { 187static void process_dev_shm(void) {
188 // Jack audio keeps an Unix socket under (/dev/shm/jack_default_1000_0 or /dev/shm/jack/...) 188 // Jack audio keeps an Unix socket under (/dev/shm/jack_default_1000_0 or /dev/shm/jack/...)
189 // looking for jack socket 189 // looking for jack socket
190 EUID_USER();
190 glob_t globbuf; 191 glob_t globbuf;
191 int globerr = glob(RUN_DEV_DIR "/shm/jack*", GLOB_NOSORT, NULL, &globbuf); 192 int globerr = glob(RUN_DEV_DIR "/shm/jack*", GLOB_NOSORT, NULL, &globbuf);
193 EUID_ROOT();
192 if (globerr && !arg_keep_dev_shm) { 194 if (globerr && !arg_keep_dev_shm) {
193 empty_dev_shm(); 195 empty_dev_shm();
194 return; 196 return;
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 4bcefa443..eab952eb8 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -42,15 +42,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
42 // copy skel files 42 // copy skel files
43 if (asprintf(&fname, "%s/.zshrc", homedir) == -1) 43 if (asprintf(&fname, "%s/.zshrc", homedir) == -1)
44 errExit("asprintf"); 44 errExit("asprintf");
45 struct stat s;
46 // don't copy it if we already have the file 45 // don't copy it if we already have the file
47 if (stat(fname, &s) == 0) 46 if (access(fname, F_OK) == 0)
48 return; 47 return;
49 if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat 48 if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat
50 fprintf(stderr, "Error: invalid %s file\n", fname); 49 fprintf(stderr, "Error: invalid %s file\n", fname);
51 exit(1); 50 exit(1);
52 } 51 }
53 if (stat("/etc/skel/.zshrc", &s) == 0) { 52 if (access("/etc/skel/.zshrc", R_OK) == 0) {
54 copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user 53 copy_file_as_user("/etc/skel/.zshrc", fname, u, g, 0644); // regular user
55 fs_logger("clone /etc/skel/.zshrc"); 54 fs_logger("clone /etc/skel/.zshrc");
56 fs_logger2("clone", fname); 55 fs_logger2("clone", fname);
@@ -67,16 +66,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
67 // copy skel files 66 // copy skel files
68 if (asprintf(&fname, "%s/.cshrc", homedir) == -1) 67 if (asprintf(&fname, "%s/.cshrc", homedir) == -1)
69 errExit("asprintf"); 68 errExit("asprintf");
70 struct stat s;
71
72 // don't copy it if we already have the file 69 // don't copy it if we already have the file
73 if (stat(fname, &s) == 0) 70 if (access(fname, F_OK) == 0)
74 return; 71 return;
75 if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat 72 if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat
76 fprintf(stderr, "Error: invalid %s file\n", fname); 73 fprintf(stderr, "Error: invalid %s file\n", fname);
77 exit(1); 74 exit(1);
78 } 75 }
79 if (stat("/etc/skel/.cshrc", &s) == 0) { 76 if (access("/etc/skel/.cshrc", R_OK) == 0) {
80 copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user 77 copy_file_as_user("/etc/skel/.cshrc", fname, u, g, 0644); // regular user
81 fs_logger("clone /etc/skel/.cshrc"); 78 fs_logger("clone /etc/skel/.cshrc");
82 fs_logger2("clone", fname); 79 fs_logger2("clone", fname);
@@ -93,15 +90,14 @@ static void skel(const char *homedir, uid_t u, gid_t g) {
93 // copy skel files 90 // copy skel files
94 if (asprintf(&fname, "%s/.bashrc", homedir) == -1) 91 if (asprintf(&fname, "%s/.bashrc", homedir) == -1)
95 errExit("asprintf"); 92 errExit("asprintf");
96 struct stat s;
97 // don't copy it if we already have the file 93 // don't copy it if we already have the file
98 if (stat(fname, &s) == 0) 94 if (access(fname, F_OK) == 0)
99 return; 95 return;
100 if (is_link(fname)) { // stat on dangling symlinks fails, try again using lstat 96 if (is_link(fname)) { // access(3) on dangling symlinks fails, try again using lstat
101 fprintf(stderr, "Error: invalid %s file\n", fname); 97 fprintf(stderr, "Error: invalid %s file\n", fname);
102 exit(1); 98 exit(1);
103 } 99 }
104 if (stat("/etc/skel/.bashrc", &s) == 0) { 100 if (access("/etc/skel/.bashrc", R_OK) == 0) {
105 copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user 101 copy_file_as_user("/etc/skel/.bashrc", fname, u, g, 0644); // regular user
106 fs_logger("clone /etc/skel/.bashrc"); 102 fs_logger("clone /etc/skel/.bashrc");
107 fs_logger2("clone", fname); 103 fs_logger2("clone", fname);
@@ -122,8 +118,8 @@ static int store_xauthority(void) {
122 errExit("asprintf"); 118 errExit("asprintf");
123 119
124 struct stat s; 120 struct stat s;
125 if (stat(src, &s) == 0) { 121 if (lstat_as_user(src, &s) == 0) {
126 if (is_link(src)) { 122 if (S_ISLNK(s.st_mode)) {
127 fwarning("invalid .Xauthority file\n"); 123 fwarning("invalid .Xauthority file\n");
128 free(src); 124 free(src);
129 return 0; 125 return 0;
@@ -161,11 +157,11 @@ static int store_asoundrc(void) {
161 errExit("asprintf"); 157 errExit("asprintf");
162 158
163 struct stat s; 159 struct stat s;
164 if (stat(src, &s) == 0) { 160 if (lstat_as_user(src, &s) == 0) {
165 if (is_link(src)) { 161 if (S_ISLNK(s.st_mode)) {
166 // make sure the real path of the file is inside the home directory 162 // make sure the real path of the file is inside the home directory
167 /* coverity[toctou] */ 163 /* coverity[toctou] */
168 char* rp = realpath(src, NULL); 164 char *rp = realpath_as_user(src);
169 if (!rp) { 165 if (!rp) {
170 fprintf(stderr, "Error: Cannot access %s\n", src); 166 fprintf(stderr, "Error: Cannot access %s\n", src);
171 exit(1); 167 exit(1);
@@ -234,6 +230,7 @@ static void copy_asoundrc(void) {
234 } 230 }
235 231
236 copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user 232 copy_file_as_user(src, dest, getuid(), getgid(), S_IRUSR | S_IWUSR); // regular user
233 selinux_relabel_path(dest, src);
237 fs_logger2("clone", dest); 234 fs_logger2("clone", dest);
238 free(dest); 235 free(dest);
239 236
@@ -262,6 +259,7 @@ void fs_private_homedir(void) {
262 if (arg_debug) 259 if (arg_debug)
263 printf("Mount-bind %s on top of %s\n", private_homedir, homedir); 260 printf("Mount-bind %s on top of %s\n", private_homedir, homedir);
264 // get file descriptors for homedir and private_homedir, fails if there is any symlink 261 // get file descriptors for homedir and private_homedir, fails if there is any symlink
262 EUID_USER();
265 int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 263 int src = safer_openat(-1, private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
266 if (src == -1) 264 if (src == -1)
267 errExit("opening private directory"); 265 errExit("opening private directory");
@@ -286,17 +284,10 @@ void fs_private_homedir(void) {
286 exit(1); 284 exit(1);
287 } 285 }
288 // mount via the links in /proc/self/fd 286 // mount via the links in /proc/self/fd
289 char *proc_src, *proc_dst; 287 EUID_ROOT();
290 if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) 288 if (bind_mount_by_fd(src, dst))
291 errExit("asprintf");
292 if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1)
293 errExit("asprintf");
294 if (mount(proc_src, proc_dst, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0)
295 errExit("mount bind"); 289 errExit("mount bind");
296 free(proc_src); 290
297 free(proc_dst);
298 close(src);
299 close(dst);
300 // check /proc/self/mountinfo to confirm the mount is ok 291 // check /proc/self/mountinfo to confirm the mount is ok
301 MountData *mptr = get_last_mount(); 292 MountData *mptr = get_last_mount();
302 size_t len = strlen(homedir); 293 size_t len = strlen(homedir);
@@ -304,6 +295,8 @@ void fs_private_homedir(void) {
304 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/')) 295 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/'))
305 errLogExit("invalid private mount"); 296 errLogExit("invalid private mount");
306 297
298 close(src);
299 close(dst);
307 fs_logger3("mount-bind", private_homedir, homedir); 300 fs_logger3("mount-bind", private_homedir, homedir);
308 fs_logger2("whitelist", homedir); 301 fs_logger2("whitelist", homedir);
309// preserve mode and ownership 302// preserve mode and ownership
@@ -438,6 +431,7 @@ void fs_check_private_cwd(const char *dir) {
438// --private-home 431// --private-home
439//*********************************************************************************** 432//***********************************************************************************
440static char *check_dir_or_file(const char *name) { 433static char *check_dir_or_file(const char *name) {
434 EUID_ASSERT();
441 assert(name); 435 assert(name);
442 436
443 // basic checks 437 // basic checks
@@ -498,6 +492,7 @@ errexit:
498} 492}
499 493
500static void duplicate(char *name) { 494static void duplicate(char *name) {
495 EUID_ASSERT();
501 char *fname = check_dir_or_file(name); 496 char *fname = check_dir_or_file(name);
502 497
503 if (arg_debug) 498 if (arg_debug)
@@ -553,10 +548,10 @@ void fs_private_home_list(void) {
553 selinux_relabel_path(RUN_HOME_DIR, homedir); 548 selinux_relabel_path(RUN_HOME_DIR, homedir);
554 fs_logger_print(); // save the current log 549 fs_logger_print(); // save the current log
555 550
551 // copy the list of files in the new home directory
552 EUID_USER();
556 if (arg_debug) 553 if (arg_debug)
557 printf("Copying files in the new home:\n"); 554 printf("Copying files in the new home:\n");
558
559 // copy the list of files in the new home directory
560 char *dlist = strdup(cfg.home_private_keep); 555 char *dlist = strdup(cfg.home_private_keep);
561 if (!dlist) 556 if (!dlist)
562 errExit("strdup"); 557 errExit("strdup");
@@ -589,13 +584,11 @@ void fs_private_home_list(void) {
589 exit(1); 584 exit(1);
590 } 585 }
591 // mount using the file descriptor 586 // mount using the file descriptor
592 char *proc; 587 EUID_ROOT();
593 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 588 if (bind_mount_path_to_fd(RUN_HOME_DIR, fd))
594 errExit("asprintf");
595 if (mount(RUN_HOME_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0)
596 errExit("mount bind"); 589 errExit("mount bind");
597 free(proc);
598 close(fd); 590 close(fd);
591
599 // check /proc/self/mountinfo to confirm the mount is ok 592 // check /proc/self/mountinfo to confirm the mount is ok
600 MountData *mptr = get_last_mount(); 593 MountData *mptr = get_last_mount();
601 if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) 594 if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
diff --git a/src/firejail/fs_lib.c b/src/firejail/fs_lib.c
index 5df356d04..9d7a17cf3 100644
--- a/src/firejail/fs_lib.c
+++ b/src/firejail/fs_lib.c
@@ -178,8 +178,7 @@ void fslib_mount(const char *full_path) {
178 178
179 if (*full_path == '\0' || 179 if (*full_path == '\0' ||
180 !valid_full_path(full_path) || 180 !valid_full_path(full_path) ||
181 access(full_path, F_OK) != 0 || 181 stat_as_user(full_path, &s) != 0 ||
182 stat(full_path, &s) != 0 ||
183 s.st_uid != 0) 182 s.st_uid != 0)
184 return; 183 return;
185 184
@@ -203,7 +202,7 @@ void fslib_mount_libs(const char *full_path, unsigned user) {
203 } 202 }
204 203
205 if (arg_debug || arg_debug_private_lib) 204 if (arg_debug || arg_debug_private_lib)
206 printf(" fslib_mount_libs %s (parse as %s)\n", full_path, user ? "user" : "root"); 205 printf(" fslib_mount_libs %s\n", full_path);
207 // create an empty RUN_LIB_FILE and allow the user to write to it 206 // create an empty RUN_LIB_FILE and allow the user to write to it
208 unlink(RUN_LIB_FILE); // in case is there 207 unlink(RUN_LIB_FILE); // in case is there
209 create_empty_file_as_root(RUN_LIB_FILE, 0644); 208 create_empty_file_as_root(RUN_LIB_FILE, 0644);
@@ -212,7 +211,7 @@ void fslib_mount_libs(const char *full_path, unsigned user) {
212 211
213 // run fldd to extract the list of files 212 // run fldd to extract the list of files
214 if (arg_debug || arg_debug_private_lib) 213 if (arg_debug || arg_debug_private_lib)
215 printf(" running fldd %s\n", full_path); 214 printf(" running fldd %s as %s\n", full_path, user ? "user" : "root");
216 unsigned mask; 215 unsigned mask;
217 if (user) 216 if (user)
218 mask = SBOX_USER; 217 mask = SBOX_USER;
@@ -246,7 +245,7 @@ static void load_library(const char *fname) {
246 245
247 // existing file owned by root 246 // existing file owned by root
248 struct stat s; 247 struct stat s;
249 if (!access(fname, F_OK) && stat(fname, &s) == 0 && s.st_uid == 0) { 248 if (stat_as_user(fname, &s) == 0 && s.st_uid == 0) {
250 // load directories, regular 64 bit libraries, and 64 bit executables 249 // load directories, regular 64 bit libraries, and 64 bit executables
251 if (S_ISDIR(s.st_mode)) 250 if (S_ISDIR(s.st_mode))
252 fslib_mount(fname); 251 fslib_mount(fname);
@@ -286,19 +285,21 @@ static void install_list_entry(const char *lib) {
286#define DO_GLOBBING 285#define DO_GLOBBING
287#ifdef DO_GLOBBING 286#ifdef DO_GLOBBING
288 // globbing 287 // globbing
288 EUID_USER();
289 glob_t globbuf; 289 glob_t globbuf;
290 int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf); 290 int globerr = glob(fname, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf);
291 if (globerr) { 291 if (globerr) {
292 fprintf(stderr, "Error: failed to glob private-lib pattern %s\n", fname); 292 fprintf(stderr, "Error: failed to glob private-lib pattern %s\n", fname);
293 exit(1); 293 exit(1);
294 } 294 }
295 EUID_ROOT();
295 size_t j; 296 size_t j;
296 for (j = 0; j < globbuf.gl_pathc; j++) { 297 for (j = 0; j < globbuf.gl_pathc; j++) {
297 assert(globbuf.gl_pathv[j]); 298 assert(globbuf.gl_pathv[j]);
298//printf("glob %s\n", globbuf.gl_pathv[j]); 299//printf("glob %s\n", globbuf.gl_pathv[j]);
299 // GLOB_NOCHECK - no pattern matched returns the original pattern; try to load it anyway 300 // GLOB_NOCHECK - no pattern matched returns the original pattern; try to load it anyway
300 301
301 // foobar/* includes foobar/. and foobar/.. 302 // foobar/* expands to foobar/. and foobar/..
302 const char *base = gnu_basename(globbuf.gl_pathv[j]); 303 const char *base = gnu_basename(globbuf.gl_pathv[j]);
303 if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0) 304 if (strcmp(base, ".") == 0 || strcmp(base, "..") == 0)
304 continue; 305 continue;
diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c
index 8cfeea582..bbc2aa938 100644
--- a/src/firejail/fs_mkdir.c
+++ b/src/firejail/fs_mkdir.c
@@ -25,6 +25,9 @@
25#include <sys/wait.h> 25#include <sys/wait.h>
26#include <string.h> 26#include <string.h>
27 27
28#ifdef HAVE_GCOV
29#include <gcov.h>
30#endif
28 31
29static void check(const char *fname) { 32static void check(const char *fname) {
30 // manufacture /run/user directory 33 // manufacture /run/user directory
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c
index 1fc38361e..475a391ec 100644
--- a/src/firejail/fs_trace.c
+++ b/src/firejail/fs_trace.c
@@ -71,12 +71,8 @@ void fs_tracefile(void) {
71 // mount using the symbolic link in /proc/self/fd 71 // mount using the symbolic link in /proc/self/fd
72 if (arg_debug) 72 if (arg_debug)
73 printf("Bind mount %s to %s\n", arg_tracefile, RUN_TRACE_FILE); 73 printf("Bind mount %s to %s\n", arg_tracefile, RUN_TRACE_FILE);
74 char *proc; 74 if (bind_mount_fd_to_path(fd, RUN_TRACE_FILE))
75 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
76 errExit("asprintf");
77 if (mount(proc, RUN_TRACE_FILE, NULL, MS_BIND|MS_REC, NULL) < 0)
78 errExit("mount bind " RUN_TRACE_FILE); 75 errExit("mount bind " RUN_TRACE_FILE);
79 free(proc);
80 close(fd); 76 close(fd);
81 // now that RUN_TRACE_FILE is user-writable, mount it noexec 77 // now that RUN_TRACE_FILE is user-writable, mount it noexec
82 fs_remount(RUN_TRACE_FILE, MOUNT_NOEXEC, 0); 78 fs_remount(RUN_TRACE_FILE, MOUNT_NOEXEC, 0);
diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c
index bae3d6df0..20e262d80 100644
--- a/src/firejail/fs_var.c
+++ b/src/firejail/fs_var.c
@@ -323,4 +323,8 @@ void fs_var_utmp(void) {
323 if (mount(RUN_UTMP_FILE, UTMP_FILE, NULL, MS_BIND|MS_NOSUID|MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) 323 if (mount(RUN_UTMP_FILE, UTMP_FILE, NULL, MS_BIND|MS_NOSUID|MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0)
324 errExit("mount bind utmp"); 324 errExit("mount bind utmp");
325 fs_logger2("create", UTMP_FILE); 325 fs_logger2("create", UTMP_FILE);
326
327 // blacklist RUN_UTMP_FILE
328 if (mount(RUN_RO_FILE, RUN_UTMP_FILE, NULL, MS_BIND, "mode=400,gid=0") < 0)
329 errExit("mount bind");
326} 330}
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index 77bb5e5bb..370035a4d 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -195,15 +195,7 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) {
195 195
196 if (arg_debug || arg_debug_whitelists) 196 if (arg_debug || arg_debug_whitelists)
197 printf("Whitelisting %s\n", path); 197 printf("Whitelisting %s\n", path);
198 198 if (bind_mount_by_fd(fd, fd3))
199 // in order to make this mount resilient against symlink attacks, use
200 // magic links in /proc/self/fd instead of mounting the paths directly
201 char *proc_src, *proc_dst;
202 if (asprintf(&proc_src, "/proc/self/fd/%d", fd) == -1)
203 errExit("asprintf");
204 if (asprintf(&proc_dst, "/proc/self/fd/%d", fd3) == -1)
205 errExit("asprintf");
206 if (mount(proc_src, proc_dst, NULL, MS_BIND | MS_REC, NULL) < 0)
207 errExit("mount bind"); 199 errExit("mount bind");
208 // check the last mount operation 200 // check the last mount operation
209 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found 201 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found
@@ -221,8 +213,6 @@ static void whitelist_file(int dirfd, const char *relpath, const char *path) {
221 // - there should be more than one '/' char in dest string 213 // - there should be more than one '/' char in dest string
222 if (mptr->dir == strrchr(mptr->dir, '/')) 214 if (mptr->dir == strrchr(mptr->dir, '/'))
223 errLogExit("invalid whitelist mount"); 215 errLogExit("invalid whitelist mount");
224 free(proc_src);
225 free(proc_dst);
226 close(fd); 216 close(fd);
227 close(fd3); 217 close(fd3);
228 fs_logger2("whitelist", path); 218 fs_logger2("whitelist", path);
@@ -267,6 +257,7 @@ static void whitelist_symlink(const char *link, const char *target) {
267} 257}
268 258
269static void globbing(const char *pattern) { 259static void globbing(const char *pattern) {
260 EUID_ASSERT();
270 assert(pattern); 261 assert(pattern);
271 262
272 // globbing 263 // globbing
@@ -304,7 +295,6 @@ static void globbing(const char *pattern) {
304} 295}
305 296
306// mount tmpfs on all top level directories 297// mount tmpfs on all top level directories
307// home directories *inside* /run/user/$UID are not fully supported
308static void tmpfs_topdirs(const TopDir *topdirs) { 298static void tmpfs_topdirs(const TopDir *topdirs) {
309 int tmpfs_home = 0; 299 int tmpfs_home = 0;
310 int tmpfs_runuser = 0; 300 int tmpfs_runuser = 0;
@@ -335,18 +325,15 @@ static void tmpfs_topdirs(const TopDir *topdirs) {
335 325
336 // mount tmpfs 326 // mount tmpfs
337 fs_tmpfs(topdirs[i].path, 0); 327 fs_tmpfs(topdirs[i].path, 0);
328 selinux_relabel_path(topdirs[i].path, topdirs[i].path);
338 329
339 // init tmpfs 330 // init tmpfs
340 if (strcmp(topdirs[i].path, "/run") == 0) { 331 if (strcmp(topdirs[i].path, "/run") == 0) {
341 // restore /run/firejail directory 332 // restore /run/firejail directory
342 if (mkdir(RUN_FIREJAIL_DIR, 0755) == -1) 333 if (mkdir(RUN_FIREJAIL_DIR, 0755) == -1)
343 errExit("mkdir"); 334 errExit("mkdir");
344 char *proc; 335 if (bind_mount_fd_to_path(fd, RUN_FIREJAIL_DIR))
345 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
346 errExit("asprintf");
347 if (mount(proc, RUN_FIREJAIL_DIR, NULL, MS_BIND | MS_REC, NULL) < 0)
348 errExit("mount bind"); 336 errExit("mount bind");
349 free(proc);
350 close(fd); 337 close(fd);
351 fs_logger2("whitelist", RUN_FIREJAIL_DIR); 338 fs_logger2("whitelist", RUN_FIREJAIL_DIR);
352 339
@@ -384,8 +371,6 @@ static void tmpfs_topdirs(const TopDir *topdirs) {
384 const char *rel = cfg.homedir + topdir_len + 1; 371 const char *rel = cfg.homedir + topdir_len + 1;
385 whitelist_file(topdirs[i].fd, rel, cfg.homedir); 372 whitelist_file(topdirs[i].fd, rel, cfg.homedir);
386 } 373 }
387
388 selinux_relabel_path(topdirs[i].path, topdirs[i].path);
389 } 374 }
390 375
391 // user home directory 376 // user home directory
@@ -423,6 +408,13 @@ static TopDir *add_topdir(const char *dir, TopDir *topdirs, const char *path) {
423 strcmp(dir, "/sys") == 0) 408 strcmp(dir, "/sys") == 0)
424 whitelist_error(path); 409 whitelist_error(path);
425 410
411 // whitelisting home directory is disabled if --private option is present
412 if (arg_private && strcmp(dir, cfg.homedir) == 0) {
413 if (arg_debug || arg_debug_whitelists)
414 printf("Debug %d: skip %s - a private home dir is configured!\n", __LINE__, path);
415 return NULL;
416 }
417
426 // do nothing if directory doesn't exist 418 // do nothing if directory doesn't exist
427 struct stat s; 419 struct stat s;
428 if (lstat(dir, &s) != 0) { 420 if (lstat(dir, &s) != 0) {
@@ -460,9 +452,9 @@ static TopDir *add_topdir(const char *dir, TopDir *topdirs, const char *path) {
460 errExit("strdup"); 452 errExit("strdup");
461 453
462 // open the directory, don't follow symbolic links 454 // open the directory, don't follow symbolic links
463 rv->fd = safer_openat(-1, rv->path, O_PATH|O_NOFOLLOW|O_DIRECTORY|O_CLOEXEC); 455 rv->fd = safer_openat(-1, dir, O_PATH|O_NOFOLLOW|O_DIRECTORY|O_CLOEXEC);
464 if (rv->fd == -1) { 456 if (rv->fd == -1) {
465 fprintf(stderr, "Error: cannot open %s\n", rv->path); 457 fprintf(stderr, "Error: cannot open %s\n", dir);
466 exit(1); 458 exit(1);
467 } 459 }
468 460
@@ -743,10 +735,11 @@ void fs_whitelist(void) {
743 } 735 }
744 736
745 // create the link if any 737 // create the link if any
746 if (link) 738 if (link) {
747 whitelist_symlink(link, file); 739 whitelist_symlink(link, file);
740 free(link);
741 }
748 742
749 free(link);
750 free(file); 743 free(file);
751 free(entry->wparam); 744 free(entry->wparam);
752 entry->wparam = NULL; 745 entry->wparam = NULL;
diff --git a/src/firejail/join.c b/src/firejail/join.c
index bab4b830f..394bbb528 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -147,7 +147,7 @@ static void extract_command(int argc, char **argv, int index) {
147 } 147 }
148 148
149 // build command 149 // build command
150 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, index); 150 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, index, true);
151} 151}
152 152
153static void extract_nogroups(pid_t pid) { 153static void extract_nogroups(pid_t pid) {
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index 796c42290..6ee557648 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -31,6 +31,10 @@
31//#include <stdio.h> 31//#include <stdio.h>
32//#include <stdlib.h> 32//#include <stdlib.h>
33 33
34#ifdef HAVE_GCOV
35#include <gcov.h>
36#endif
37
34// uid/gid cache 38// uid/gid cache
35static uid_t c_uid = 0; 39static uid_t c_uid = 0;
36static char *c_uid_name = NULL; 40static char *c_uid_name = NULL;
diff --git a/src/firejail/macros.c b/src/firejail/macros.c
index bcac1feb4..cd29d8f85 100644
--- a/src/firejail/macros.c
+++ b/src/firejail/macros.c
@@ -149,6 +149,7 @@ static char *resolve_xdg(const char *var) {
149 149
150// returns mallocated memory 150// returns mallocated memory
151static char *resolve_hardcoded(char *entries[]) { 151static char *resolve_hardcoded(char *entries[]) {
152 EUID_ASSERT();
152 char *fname; 153 char *fname;
153 struct stat s; 154 struct stat s;
154 155
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 4afd1d6b6..b376095f1 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -44,6 +44,10 @@
44#define O_PATH 010000000 44#define O_PATH 010000000
45#endif 45#endif
46 46
47#ifdef HAVE_GCOV
48#include <gcov.h>
49#endif
50
47#ifdef __ia64__ 51#ifdef __ia64__
48/* clone(2) has a different interface on ia64, as it needs to know 52/* clone(2) has a different interface on ia64, as it needs to know
49 the size of the stack */ 53 the size of the stack */
@@ -259,8 +263,8 @@ static void init_cfg(int argc, char **argv) {
259 fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); 263 fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username);
260 exit(1); 264 exit(1);
261 } 265 }
266 check_homedir(pw->pw_dir);
262 cfg.homedir = clean_pathname(pw->pw_dir); 267 cfg.homedir = clean_pathname(pw->pw_dir);
263 check_homedir();
264 268
265 // initialize random number generator 269 // initialize random number generator
266 sandbox_pid = getpid(); 270 sandbox_pid = getpid();
@@ -862,12 +866,11 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
862char *guess_shell(void) { 866char *guess_shell(void) {
863 const char *shell; 867 const char *shell;
864 char *retval; 868 char *retval;
865 struct stat s;
866 869
867 shell = env_get("SHELL"); 870 shell = env_get("SHELL");
868 if (shell) { 871 if (shell) {
869 invalid_filename(shell, 0); // no globbing 872 invalid_filename(shell, 0); // no globbing
870 if (!is_dir(shell) && strstr(shell, "..") == NULL && stat(shell, &s) == 0 && access(shell, X_OK) == 0 && 873 if (access(shell, X_OK) == 0 && !is_dir(shell) && strstr(shell, "..") == NULL &&
871 strcmp(shell, PATH_FIREJAIL) != 0) 874 strcmp(shell, PATH_FIREJAIL) != 0)
872 goto found; 875 goto found;
873 } 876 }
@@ -878,12 +881,15 @@ char *guess_shell(void) {
878 int i = 0; 881 int i = 0;
879 while (shells[i] != NULL) { 882 while (shells[i] != NULL) {
880 // access call checks as real UID/GID, not as effective UID/GID 883 // access call checks as real UID/GID, not as effective UID/GID
881 if (stat(shells[i], &s) == 0 && access(shells[i], X_OK) == 0) { 884 if (access(shells[i], X_OK) == 0) {
882 shell = shells[i]; 885 shell = shells[i];
883 break; 886 goto found;
884 } 887 }
885 i++; 888 i++;
886 } 889 }
890
891 return NULL;
892
887 found: 893 found:
888 retval = strdup(shell); 894 retval = strdup(shell);
889 if (!retval) 895 if (!retval)
@@ -1256,8 +1262,10 @@ int main(int argc, char **argv, char **envp) {
1256 for (i = 1; i < argc; i++) { 1262 for (i = 1; i < argc; i++) {
1257 run_cmd_and_exit(i, argc, argv); // will exit if the command is recognized 1263 run_cmd_and_exit(i, argc, argv); // will exit if the command is recognized
1258 1264
1259 if (strcmp(argv[i], "--debug") == 0 && !arg_quiet) 1265 if (strcmp(argv[i], "--debug") == 0) {
1260 arg_debug = 1; 1266 arg_debug = 1;
1267 arg_quiet = 0;
1268 }
1261 else if (strcmp(argv[i], "--debug-blacklists") == 0) 1269 else if (strcmp(argv[i], "--debug-blacklists") == 0)
1262 arg_debug_blacklists = 1; 1270 arg_debug_blacklists = 1;
1263 else if (strcmp(argv[i], "--debug-whitelists") == 0) 1271 else if (strcmp(argv[i], "--debug-whitelists") == 0)
@@ -1265,8 +1273,8 @@ int main(int argc, char **argv, char **envp) {
1265 else if (strcmp(argv[i], "--debug-private-lib") == 0) 1273 else if (strcmp(argv[i], "--debug-private-lib") == 0)
1266 arg_debug_private_lib = 1; 1274 arg_debug_private_lib = 1;
1267 else if (strcmp(argv[i], "--quiet") == 0) { 1275 else if (strcmp(argv[i], "--quiet") == 0) {
1268 arg_quiet = 1; 1276 if (!arg_debug)
1269 arg_debug = 0; 1277 arg_quiet = 1;
1270 } 1278 }
1271 else if (strcmp(argv[i], "--allow-debuggers") == 0) { 1279 else if (strcmp(argv[i], "--allow-debuggers") == 0) {
1272 // already handled 1280 // already handled
@@ -1910,8 +1918,6 @@ int main(int argc, char **argv, char **envp) {
1910 } 1918 }
1911 else if (strcmp(argv[i], "--private") == 0) { 1919 else if (strcmp(argv[i], "--private") == 0) {
1912 arg_private = 1; 1920 arg_private = 1;
1913 // disable whitelisting in home directory
1914 profile_add("whitelist ~/*");
1915 } 1921 }
1916 else if (strncmp(argv[i], "--private=", 10) == 0) { 1922 else if (strncmp(argv[i], "--private=", 10) == 0) {
1917 if (cfg.home_private_keep) { 1923 if (cfg.home_private_keep) {
@@ -1933,8 +1939,6 @@ int main(int argc, char **argv, char **envp) {
1933 cfg.home_private = NULL; 1939 cfg.home_private = NULL;
1934 } 1940 }
1935 arg_private = 1; 1941 arg_private = 1;
1936 // disable whitelisting in home directory
1937 profile_add("whitelist ~/*");
1938 } 1942 }
1939#ifdef HAVE_PRIVATE_HOME 1943#ifdef HAVE_PRIVATE_HOME
1940 else if (strncmp(argv[i], "--private-home=", 15) == 0) { 1944 else if (strncmp(argv[i], "--private-home=", 15) == 0) {
@@ -1967,61 +1971,77 @@ int main(int argc, char **argv, char **envp) {
1967 arg_keep_dev_shm = 1; 1971 arg_keep_dev_shm = 1;
1968 } 1972 }
1969 else if (strncmp(argv[i], "--private-etc=", 14) == 0) { 1973 else if (strncmp(argv[i], "--private-etc=", 14) == 0) {
1970 if (arg_writable_etc) { 1974 if (checkcfg(CFG_PRIVATE_ETC)) {
1971 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); 1975 if (arg_writable_etc) {
1972 exit(1); 1976 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n");
1973 } 1977 exit(1);
1978 }
1974 1979
1975 // extract private etc list 1980 // extract private etc list
1976 if (*(argv[i] + 14) == '\0') { 1981 if (*(argv[i] + 14) == '\0') {
1977 fprintf(stderr, "Error: invalid private-etc option\n"); 1982 fprintf(stderr, "Error: invalid private-etc option\n");
1978 exit(1); 1983 exit(1);
1984 }
1985 if (cfg.etc_private_keep) {
1986 if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, argv[i] + 14) < 0 )
1987 errExit("asprintf");
1988 } else
1989 cfg.etc_private_keep = argv[i] + 14;
1990 arg_private_etc = 1;
1979 } 1991 }
1980 if (cfg.etc_private_keep) { 1992 else
1981 if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, argv[i] + 14) < 0 ) 1993 exit_err_feature("private-etc");
1982 errExit("asprintf");
1983 } else
1984 cfg.etc_private_keep = argv[i] + 14;
1985 arg_private_etc = 1;
1986 } 1994 }
1987 else if (strncmp(argv[i], "--private-opt=", 14) == 0) { 1995 else if (strncmp(argv[i], "--private-opt=", 14) == 0) {
1988 // extract private opt list 1996 if (checkcfg(CFG_PRIVATE_OPT)) {
1989 if (*(argv[i] + 14) == '\0') { 1997 // extract private opt list
1990 fprintf(stderr, "Error: invalid private-opt option\n"); 1998 if (*(argv[i] + 14) == '\0') {
1991 exit(1); 1999 fprintf(stderr, "Error: invalid private-opt option\n");
2000 exit(1);
2001 }
2002 if (cfg.opt_private_keep) {
2003 if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, argv[i] + 14) < 0 )
2004 errExit("asprintf");
2005 } else
2006 cfg.opt_private_keep = argv[i] + 14;
2007 arg_private_opt = 1;
1992 } 2008 }
1993 if (cfg.opt_private_keep) { 2009 else
1994 if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, argv[i] + 14) < 0 ) 2010 exit_err_feature("private-opt");
1995 errExit("asprintf");
1996 } else
1997 cfg.opt_private_keep = argv[i] + 14;
1998 arg_private_opt = 1;
1999 } 2011 }
2000 else if (strncmp(argv[i], "--private-srv=", 14) == 0) { 2012 else if (strncmp(argv[i], "--private-srv=", 14) == 0) {
2001 // extract private srv list 2013 if (checkcfg(CFG_PRIVATE_SRV)) {
2002 if (*(argv[i] + 14) == '\0') { 2014 // extract private srv list
2003 fprintf(stderr, "Error: invalid private-srv option\n"); 2015 if (*(argv[i] + 14) == '\0') {
2004 exit(1); 2016 fprintf(stderr, "Error: invalid private-srv option\n");
2017 exit(1);
2018 }
2019 if (cfg.srv_private_keep) {
2020 if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, argv[i] + 14) < 0 )
2021 errExit("asprintf");
2022 } else
2023 cfg.srv_private_keep = argv[i] + 14;
2024 arg_private_srv = 1;
2005 } 2025 }
2006 if (cfg.srv_private_keep) { 2026 else
2007 if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, argv[i] + 14) < 0 ) 2027 exit_err_feature("private-srv");
2008 errExit("asprintf");
2009 } else
2010 cfg.srv_private_keep = argv[i] + 14;
2011 arg_private_srv = 1;
2012 } 2028 }
2013 else if (strncmp(argv[i], "--private-bin=", 14) == 0) { 2029 else if (strncmp(argv[i], "--private-bin=", 14) == 0) {
2014 // extract private bin list 2030 if (checkcfg(CFG_PRIVATE_BIN)) {
2015 if (*(argv[i] + 14) == '\0') { 2031 // extract private bin list
2016 fprintf(stderr, "Error: invalid private-bin option\n"); 2032 if (*(argv[i] + 14) == '\0') {
2017 exit(1); 2033 fprintf(stderr, "Error: invalid private-bin option\n");
2034 exit(1);
2035 }
2036 if (cfg.bin_private_keep) {
2037 if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, argv[i] + 14) < 0 )
2038 errExit("asprintf");
2039 } else
2040 cfg.bin_private_keep = argv[i] + 14;
2041 arg_private_bin = 1;
2018 } 2042 }
2019 if (cfg.bin_private_keep) { 2043 else
2020 if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, argv[i] + 14) < 0 ) 2044 exit_err_feature("private-bin");
2021 errExit("asprintf");
2022 } else
2023 cfg.bin_private_keep = argv[i] + 14;
2024 arg_private_bin = 1;
2025 } 2045 }
2026 else if (strncmp(argv[i], "--private-lib", 13) == 0) { 2046 else if (strncmp(argv[i], "--private-lib", 13) == 0) {
2027 if (checkcfg(CFG_PRIVATE_LIB)) { 2047 if (checkcfg(CFG_PRIVATE_LIB)) {
@@ -2809,6 +2829,11 @@ int main(int argc, char **argv, char **envp) {
2809 // build the sandbox command 2829 // build the sandbox command
2810 if (prog_index == -1 && cfg.shell) { 2830 if (prog_index == -1 && cfg.shell) {
2811 assert(cfg.command_line == NULL); // runs cfg.shell 2831 assert(cfg.command_line == NULL); // runs cfg.shell
2832 if (arg_appimage) {
2833 fprintf(stderr, "Error: no appimage archive specified\n");
2834 exit(1);
2835 }
2836
2812 cfg.window_title = cfg.shell; 2837 cfg.window_title = cfg.shell;
2813 cfg.command_name = cfg.shell; 2838 cfg.command_name = cfg.shell;
2814 } 2839 }
@@ -2816,10 +2841,11 @@ int main(int argc, char **argv, char **envp) {
2816 if (arg_debug) 2841 if (arg_debug)
2817 printf("Configuring appimage environment\n"); 2842 printf("Configuring appimage environment\n");
2818 appimage_set(cfg.command_name); 2843 appimage_set(cfg.command_name);
2819 build_appimage_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); 2844 build_appimage_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index, true);
2820 } 2845 }
2821 else { 2846 else {
2822 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); 2847 // Only add extra quotes if we were not launched by sshd.
2848 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index, !parent_sshd);
2823 } 2849 }
2824/* else { 2850/* else {
2825 fprintf(stderr, "Error: command must be specified when --shell=none used.\n"); 2851 fprintf(stderr, "Error: command must be specified when --shell=none used.\n");
@@ -2833,7 +2859,13 @@ int main(int argc, char **argv, char **envp) {
2833 2859
2834 // load the profile 2860 // load the profile
2835 if (!arg_noprofile && !custom_profile) { 2861 if (!arg_noprofile && !custom_profile) {
2836 custom_profile = profile_find_firejail(cfg.command_name, 1); 2862 if (arg_appimage) {
2863 custom_profile = appimage_find_profile(cfg.command_name);
2864 // disable shell=* for appimages
2865 arg_shell_none = 0;
2866 }
2867 else
2868 custom_profile = profile_find_firejail(cfg.command_name, 1);
2837 } 2869 }
2838 2870
2839 // use default.profile as the default 2871 // use default.profile as the default
@@ -2847,7 +2879,7 @@ int main(int argc, char **argv, char **envp) {
2847 custom_profile = profile_find_firejail(profile_name, 1); 2879 custom_profile = profile_find_firejail(profile_name, 1);
2848 2880
2849 if (!custom_profile) { 2881 if (!custom_profile) {
2850 fprintf(stderr, "Error: no default.profile installed\n"); 2882 fprintf(stderr, "Error: no %s installed\n", profile_name);
2851 exit(1); 2883 exit(1);
2852 } 2884 }
2853 2885
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c
index a700729d3..64a94bd84 100644
--- a/src/firejail/mountinfo.c
+++ b/src/firejail/mountinfo.c
@@ -22,7 +22,7 @@
22 22
23#include <fcntl.h> 23#include <fcntl.h>
24#ifndef O_PATH 24#ifndef O_PATH
25# define O_PATH 010000000 25#define O_PATH 010000000
26#endif 26#endif
27 27
28#define MAX_BUF 4096 28#define MAX_BUF 4096
@@ -153,6 +153,7 @@ MountData *get_last_mount(void) {
153 153
154// Extract the mount id from /proc/self/fdinfo and return it. 154// Extract the mount id from /proc/self/fdinfo and return it.
155int get_mount_id(const char *path) { 155int get_mount_id(const char *path) {
156 EUID_ASSERT();
156 assert(path); 157 assert(path);
157 158
158 int fd = open(path, O_PATH|O_CLOEXEC); 159 int fd = open(path, O_PATH|O_CLOEXEC);
@@ -162,7 +163,9 @@ int get_mount_id(const char *path) {
162 char *fdinfo; 163 char *fdinfo;
163 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1) 164 if (asprintf(&fdinfo, "/proc/self/fdinfo/%d", fd) == -1)
164 errExit("asprintf"); 165 errExit("asprintf");
166 EUID_ROOT();
165 FILE *fp = fopen(fdinfo, "re"); 167 FILE *fp = fopen(fdinfo, "re");
168 EUID_USER();
166 free(fdinfo); 169 free(fdinfo);
167 if (!fp) 170 if (!fp)
168 goto errexit; 171 goto errexit;
diff --git a/src/firejail/no_sandbox.c b/src/firejail/no_sandbox.c
index 0e153c47b..665bef73d 100644
--- a/src/firejail/no_sandbox.c
+++ b/src/firejail/no_sandbox.c
@@ -204,7 +204,7 @@ void run_no_sandbox(int argc, char **argv) {
204 // force --shell=none in order to not break firecfg symbolic links 204 // force --shell=none in order to not break firecfg symbolic links
205 arg_shell_none = 1; 205 arg_shell_none = 1;
206 206
207 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); 207 build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index, true);
208 } 208 }
209 209
210 fwarning("an existing sandbox was detected. " 210 fwarning("an existing sandbox was detected. "
diff --git a/src/firejail/paths.c b/src/firejail/paths.c
index b800fa944..d58a9d272 100644
--- a/src/firejail/paths.c
+++ b/src/firejail/paths.c
@@ -136,7 +136,7 @@ int program_in_path(const char *program) {
136 // ('x' permission means something different for directories). 136 // ('x' permission means something different for directories).
137 // exec follows symlinks, so use stat, not lstat. 137 // exec follows symlinks, so use stat, not lstat.
138 struct stat st; 138 struct stat st;
139 if (stat(scratch, &st)) { 139 if (stat_as_user(scratch, &st)) {
140 perror(scratch); 140 perror(scratch);
141 exit(1); 141 exit(1);
142 } 142 }
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index ea8773a51..5b1478918 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -22,6 +22,11 @@
22#include "../include/syscall.h" 22#include "../include/syscall.h"
23#include <dirent.h> 23#include <dirent.h>
24#include <sys/stat.h> 24#include <sys/stat.h>
25
26#ifdef HAVE_GCOV
27#include <gcov.h>
28#endif
29
25extern char *xephyr_screen; 30extern char *xephyr_screen;
26 31
27#define MAX_READ 8192 // line buffer for profile files 32#define MAX_READ 8192 // line buffer for profile files
@@ -1275,56 +1280,69 @@ int profile_check_line(char *ptr, int lineno, const char *fname) {
1275 1280
1276 // private /etc list of files and directories 1281 // private /etc list of files and directories
1277 if (strncmp(ptr, "private-etc ", 12) == 0) { 1282 if (strncmp(ptr, "private-etc ", 12) == 0) {
1278 if (arg_writable_etc) { 1283 if (checkcfg(CFG_PRIVATE_ETC)) {
1279 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n"); 1284 if (arg_writable_etc) {
1280 exit(1); 1285 fprintf(stderr, "Error: --private-etc and --writable-etc are mutually exclusive\n");
1281 } 1286 exit(1);
1282 if (cfg.etc_private_keep) { 1287 }
1283 if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, ptr + 12) < 0 ) 1288 if (cfg.etc_private_keep) {
1284 errExit("asprintf"); 1289 if ( asprintf(&cfg.etc_private_keep, "%s,%s", cfg.etc_private_keep, ptr + 12) < 0 )
1285 } else { 1290 errExit("asprintf");
1286 cfg.etc_private_keep = ptr + 12; 1291 } else {
1292 cfg.etc_private_keep = ptr + 12;
1293 }
1294 arg_private_etc = 1;
1287 } 1295 }
1288 arg_private_etc = 1; 1296 else
1289 1297 warning_feature_disabled("private-etc");
1290 return 0; 1298 return 0;
1291 } 1299 }
1292 1300
1293 // private /opt list of files and directories 1301 // private /opt list of files and directories
1294 if (strncmp(ptr, "private-opt ", 12) == 0) { 1302 if (strncmp(ptr, "private-opt ", 12) == 0) {
1295 if (cfg.opt_private_keep) { 1303 if (checkcfg(CFG_PRIVATE_OPT)) {
1296 if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, ptr + 12) < 0 ) 1304 if (cfg.opt_private_keep) {
1297 errExit("asprintf"); 1305 if ( asprintf(&cfg.opt_private_keep, "%s,%s", cfg.opt_private_keep, ptr + 12) < 0 )
1298 } else { 1306 errExit("asprintf");
1299 cfg.opt_private_keep = ptr + 12; 1307 } else {
1308 cfg.opt_private_keep = ptr + 12;
1309 }
1310 arg_private_opt = 1;
1300 } 1311 }
1301 arg_private_opt = 1; 1312 else
1302 1313 warning_feature_disabled("private-opt");
1303 return 0; 1314 return 0;
1304 } 1315 }
1305 1316
1306 // private /srv list of files and directories 1317 // private /srv list of files and directories
1307 if (strncmp(ptr, "private-srv ", 12) == 0) { 1318 if (strncmp(ptr, "private-srv ", 12) == 0) {
1308 if (cfg.srv_private_keep) { 1319 if (checkcfg(CFG_PRIVATE_SRV)) {
1309 if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, ptr + 12) < 0 ) 1320 if (cfg.srv_private_keep) {
1310 errExit("asprintf"); 1321 if ( asprintf(&cfg.srv_private_keep, "%s,%s", cfg.srv_private_keep, ptr + 12) < 0 )
1311 } else { 1322 errExit("asprintf");
1312 cfg.srv_private_keep = ptr + 12; 1323 } else {
1324 cfg.srv_private_keep = ptr + 12;
1325 }
1326 arg_private_srv = 1;
1313 } 1327 }
1314 arg_private_srv = 1; 1328 else
1315 1329 warning_feature_disabled("private-srv");
1316 return 0; 1330 return 0;
1317 } 1331 }
1318 1332
1319 // private /bin list of files 1333 // private /bin list of files
1320 if (strncmp(ptr, "private-bin ", 12) == 0) { 1334 if (strncmp(ptr, "private-bin ", 12) == 0) {
1321 if (cfg.bin_private_keep) { 1335 if (checkcfg(CFG_PRIVATE_BIN)) {
1322 if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, ptr + 12) < 0 ) 1336 if (cfg.bin_private_keep) {
1323 errExit("asprintf"); 1337 if ( asprintf(&cfg.bin_private_keep, "%s,%s", cfg.bin_private_keep, ptr + 12) < 0 )
1324 } else { 1338 errExit("asprintf");
1325 cfg.bin_private_keep = ptr + 12; 1339 } else {
1340 cfg.bin_private_keep = ptr + 12;
1341 }
1342 arg_private_bin = 1;
1326 } 1343 }
1327 arg_private_bin = 1; 1344 else
1345 warning_feature_disabled("private-bin");
1328 return 0; 1346 return 0;
1329 } 1347 }
1330 1348
@@ -1740,7 +1758,7 @@ void profile_read(const char *fname) {
1740 if (strcmp(ptr, "quiet") == 0) { 1758 if (strcmp(ptr, "quiet") == 0) {
1741 if (is_in_ignore_list(ptr)) 1759 if (is_in_ignore_list(ptr))
1742 arg_quiet = 0; 1760 arg_quiet = 0;
1743 else 1761 else if (!arg_debug)
1744 arg_quiet = 1; 1762 arg_quiet = 1;
1745 free(ptr); 1763 free(ptr);
1746 continue; 1764 continue;
diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c
index 1b01a71c6..f8d4c2f3c 100644
--- a/src/firejail/pulseaudio.c
+++ b/src/firejail/pulseaudio.c
@@ -75,31 +75,34 @@ void pulseaudio_disable(void) {
75 closedir(dir); 75 closedir(dir);
76} 76}
77 77
78static void pulseaudio_fallback(const char *path) {
79 assert(path);
80
81 fmessage("Cannot mount tmpfs on %s/.config/pulse\n", cfg.homedir);
82 env_store_name_val("PULSE_CLIENTCONFIG", path, SETENV);
83}
84
85// disable shm in pulseaudio (issue #69) 78// disable shm in pulseaudio (issue #69)
86void pulseaudio_init(void) { 79void pulseaudio_init(void) {
87 struct stat s;
88
89 // do we have pulseaudio in the system? 80 // do we have pulseaudio in the system?
90 if (stat(PULSE_CLIENT_SYSCONF, &s) == -1) { 81 if (access(PULSE_CLIENT_SYSCONF, R_OK)) {
91 if (arg_debug) 82 if (arg_debug)
92 printf("%s not found\n", PULSE_CLIENT_SYSCONF); 83 printf("Cannot read %s\n", PULSE_CLIENT_SYSCONF);
93 return; 84 return;
94 } 85 }
95 86
87 // create ~/.config/pulse directory if not present
88 char *homeusercfg = NULL;
89 if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1)
90 errExit("asprintf");
91 if (create_empty_dir_as_user(homeusercfg, 0700))
92 fs_logger2("create", homeusercfg);
93
94 free(homeusercfg);
95 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
96 errExit("asprintf");
97 if (create_empty_dir_as_user(homeusercfg, 0700))
98 fs_logger2("create", homeusercfg);
99
96 // create the new user pulseaudio directory 100 // create the new user pulseaudio directory
101 // that will be mounted over ~/.config/pulse
97 if (mkdir(RUN_PULSE_DIR, 0700) == -1) 102 if (mkdir(RUN_PULSE_DIR, 0700) == -1)
98 errExit("mkdir"); 103 errExit("mkdir");
99 selinux_relabel_path(RUN_PULSE_DIR, RUN_PULSE_DIR); 104 selinux_relabel_path(RUN_PULSE_DIR, homeusercfg);
100 // mount it nosuid, noexec, nodev
101 fs_remount(RUN_PULSE_DIR, MOUNT_NOEXEC, 0); 105 fs_remount(RUN_PULSE_DIR, MOUNT_NOEXEC, 0);
102
103 // create the new client.conf file 106 // create the new client.conf file
104 char *pulsecfg = NULL; 107 char *pulsecfg = NULL;
105 if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1) 108 if (asprintf(&pulsecfg, "%s/client.conf", RUN_PULSE_DIR) == -1)
@@ -116,37 +119,14 @@ void pulseaudio_init(void) {
116 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700)) 119 if (set_perms(RUN_PULSE_DIR, getuid(), getgid(), 0700))
117 errExit("set_perms"); 120 errExit("set_perms");
118 121
119 // create ~/.config/pulse directory if not present
120 char *homeusercfg = NULL;
121 if (asprintf(&homeusercfg, "%s/.config", cfg.homedir) == -1)
122 errExit("asprintf");
123 if (create_empty_dir_as_user(homeusercfg, 0700))
124 fs_logger2("create", homeusercfg);
125
126 free(homeusercfg);
127 if (asprintf(&homeusercfg, "%s/.config/pulse", cfg.homedir) == -1)
128 errExit("asprintf");
129 if (create_empty_dir_as_user(homeusercfg, 0700))
130 fs_logger2("create", homeusercfg);
131
132 // if ~/.config/pulse exists and there are no symbolic links, mount the new directory 122 // if ~/.config/pulse exists and there are no symbolic links, mount the new directory
133 // else set environment variable 123 // else set environment variable
124 EUID_USER();
134 int fd = safer_openat(-1, homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 125 int fd = safer_openat(-1, homeusercfg, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
126 EUID_ROOT();
135 if (fd == -1) { 127 if (fd == -1) {
136 pulseaudio_fallback(pulsecfg); 128 fwarning("not mounting tmpfs on %s\n", homeusercfg);
137 goto out; 129 env_store_name_val("PULSE_CLIENTCONFIG", pulsecfg, SETENV);
138 }
139 // confirm the actual mount destination is owned by the user
140 if (fstat(fd, &s) == -1) { // FUSE
141 if (errno != EACCES)
142 errExit("fstat");
143 close(fd);
144 pulseaudio_fallback(pulsecfg);
145 goto out;
146 }
147 if (s.st_uid != getuid()) {
148 close(fd);
149 pulseaudio_fallback(pulsecfg);
150 goto out; 130 goto out;
151 } 131 }
152 // preserve a read-only mount 132 // preserve a read-only mount
@@ -158,17 +138,13 @@ void pulseaudio_init(void) {
158 // mount via the link in /proc/self/fd 138 // mount via the link in /proc/self/fd
159 if (arg_debug) 139 if (arg_debug)
160 printf("Mounting %s on %s\n", RUN_PULSE_DIR, homeusercfg); 140 printf("Mounting %s on %s\n", RUN_PULSE_DIR, homeusercfg);
161 char *proc; 141 if (bind_mount_path_to_fd(RUN_PULSE_DIR, fd))
162 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
163 errExit("asprintf");
164 if (mount(RUN_PULSE_DIR, proc, "none", MS_BIND, NULL) < 0)
165 errExit("mount pulseaudio"); 142 errExit("mount pulseaudio");
166 // check /proc/self/mountinfo to confirm the mount is ok 143 // check /proc/self/mountinfo to confirm the mount is ok
167 MountData *mptr = get_last_mount(); 144 MountData *mptr = get_last_mount();
168 if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) 145 if (strcmp(mptr->dir, homeusercfg) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
169 errLogExit("invalid pulseaudio mount"); 146 errLogExit("invalid pulseaudio mount");
170 fs_logger2("tmpfs", homeusercfg); 147 fs_logger2("tmpfs", homeusercfg);
171 free(proc);
172 close(fd); 148 close(fd);
173 149
174 char *p; 150 char *p;
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c
index 53e395b89..6f17231a4 100644
--- a/src/firejail/restrict_users.c
+++ b/src/firejail/restrict_users.c
@@ -104,12 +104,8 @@ static void sanitize_home(void) {
104 selinux_relabel_path(cfg.homedir, cfg.homedir); 104 selinux_relabel_path(cfg.homedir, cfg.homedir);
105 105
106 // bring back real user home directory 106 // bring back real user home directory
107 char *proc; 107 if (bind_mount_fd_to_path(fd, cfg.homedir))
108 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
109 errExit("asprintf");
110 if (mount(proc, cfg.homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
111 errExit("mount bind"); 108 errExit("mount bind");
112 free(proc);
113 close(fd); 109 close(fd);
114 110
115 if (!arg_private) 111 if (!arg_private)
@@ -154,12 +150,8 @@ static void sanitize_run(void) {
154 selinux_relabel_path(runuser, runuser); 150 selinux_relabel_path(runuser, runuser);
155 151
156 // bring back real run/user/$UID directory 152 // bring back real run/user/$UID directory
157 char *proc; 153 if (bind_mount_fd_to_path(fd, runuser))
158 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
159 errExit("asprintf");
160 if (mount(proc, runuser, NULL, MS_BIND|MS_REC, NULL) < 0)
161 errExit("mount bind"); 154 errExit("mount bind");
162 free(proc);
163 close(fd); 155 close(fd);
164 156
165 fs_logger2("whitelist", runuser); 157 fs_logger2("whitelist", runuser);
@@ -246,6 +238,11 @@ static void sanitize_passwd(void) {
246 // mount-bind tne new password file 238 // mount-bind tne new password file
247 if (mount(RUN_PASSWD_FILE, "/etc/passwd", "none", MS_BIND, "mode=400,gid=0") < 0) 239 if (mount(RUN_PASSWD_FILE, "/etc/passwd", "none", MS_BIND, "mode=400,gid=0") < 0)
248 errExit("mount"); 240 errExit("mount");
241
242 // blacklist RUN_PASSWD_FILE
243 if (mount(RUN_RO_FILE, RUN_PASSWD_FILE, "none", MS_BIND, "mode=400,gid=0") < 0)
244 errExit("mount");
245
249 fs_logger("create /etc/passwd"); 246 fs_logger("create /etc/passwd");
250 247
251 return; 248 return;
@@ -376,6 +373,11 @@ static void sanitize_group(void) {
376 // mount-bind tne new group file 373 // mount-bind tne new group file
377 if (mount(RUN_GROUP_FILE, "/etc/group", "none", MS_BIND, "mode=400,gid=0") < 0) 374 if (mount(RUN_GROUP_FILE, "/etc/group", "none", MS_BIND, "mode=400,gid=0") < 0)
378 errExit("mount"); 375 errExit("mount");
376
377 // blacklist RUN_GROUP_FILE
378 if (mount(RUN_RO_FILE, RUN_GROUP_FILE, "none", MS_BIND, "mode=400,gid=0") < 0)
379 errExit("mount");
380
379 fs_logger("create /etc/group"); 381 fs_logger("create /etc/group");
380 382
381 return; 383 return;
diff --git a/src/firejail/rlimit.c b/src/firejail/rlimit.c
index 78f00bc63..dd6fec972 100644
--- a/src/firejail/rlimit.c
+++ b/src/firejail/rlimit.c
@@ -21,6 +21,10 @@
21#include <sys/time.h> 21#include <sys/time.h>
22#include <sys/resource.h> 22#include <sys/resource.h>
23 23
24#ifdef HAVE_GCOV
25#include <gcov.h>
26#endif
27
24void set_rlimits(void) { 28void set_rlimits(void) {
25 EUID_ASSERT(); 29 EUID_ASSERT();
26 // resource limits 30 // resource limits
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index a6bcec02c..e06ba3617 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -49,6 +49,9 @@
49#include <sys/apparmor.h> 49#include <sys/apparmor.h>
50#endif 50#endif
51 51
52#ifdef HAVE_GCOV
53#include <gcov.h>
54#endif
52 55
53static int force_nonewprivs = 0; 56static int force_nonewprivs = 0;
54 57
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c
index 4a8dd1bf7..37111324a 100644
--- a/src/firejail/sbox.c
+++ b/src/firejail/sbox.c
@@ -265,7 +265,6 @@ int sbox_run(unsigned filtermask, int num, ...) {
265} 265}
266 266
267int sbox_run_v(unsigned filtermask, char * const arg[]) { 267int sbox_run_v(unsigned filtermask, char * const arg[]) {
268 EUID_ROOT();
269 assert(arg); 268 assert(arg);
270 269
271 if (arg_debug) { 270 if (arg_debug) {
@@ -285,6 +284,7 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) {
285 if (child < 0) 284 if (child < 0)
286 errExit("fork"); 285 errExit("fork");
287 if (child == 0) { 286 if (child == 0) {
287 EUID_ROOT();
288 sbox_do_exec_v(filtermask, arg); 288 sbox_do_exec_v(filtermask, arg);
289 } 289 }
290 290
@@ -293,7 +293,7 @@ int sbox_run_v(unsigned filtermask, char * const arg[]) {
293 errExit("waitpid"); 293 errExit("waitpid");
294 } 294 }
295 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { 295 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
296 fprintf(stderr, "Error: failed to run %s\n", arg[0]); 296 fprintf(stderr, "Error: failed to run %s, exiting...\n", arg[0]);
297 exit(1); 297 exit(1);
298 } 298 }
299 299
diff --git a/src/firejail/selinux.c b/src/firejail/selinux.c
index 06189d7f6..6969e7a3d 100644
--- a/src/firejail/selinux.c
+++ b/src/firejail/selinux.c
@@ -19,10 +19,13 @@
19*/ 19*/
20#if HAVE_SELINUX 20#if HAVE_SELINUX
21#include "firejail.h" 21#include "firejail.h"
22
23#include <sys/types.h> 22#include <sys/types.h>
24#include <sys/stat.h> 23#include <sys/stat.h>
24
25#include <fcntl.h> 25#include <fcntl.h>
26#ifndef O_PATH
27#define O_PATH 010000000
28#endif
26 29
27#include <selinux/context.h> 30#include <selinux/context.h>
28#include <selinux/label.h> 31#include <selinux/label.h>
@@ -52,8 +55,9 @@ void selinux_relabel_path(const char *path, const char *inside_path)
52 if (!label_hnd) 55 if (!label_hnd)
53 errExit("selabel_open"); 56 errExit("selabel_open");
54 57
55 /* Open the file as O_PATH, to pin it while we determine and adjust the label */ 58 /* Open the file as O_PATH, to pin it while we determine and adjust the label
56 fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH); 59 * Defeat symlink races by not allowing symbolic links */
60 fd = safer_openat(-1, path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
57 if (fd < 0) 61 if (fd < 0)
58 return; 62 return;
59 if (fstat(fd, &st) < 0) 63 if (fstat(fd, &st) < 0)
diff --git a/src/firejail/shutdown.c b/src/firejail/shutdown.c
index fbfe1765b..d1be6eed4 100644
--- a/src/firejail/shutdown.c
+++ b/src/firejail/shutdown.c
@@ -36,8 +36,10 @@ void shut(pid_t pid) {
36 } 36 }
37 free(comm); 37 free(comm);
38 } 38 }
39 else 39 else {
40 errExit("/proc/PID/comm"); 40 fprintf(stderr, "Error: cannot find process %d\n", pid);
41 exit(1);
42 }
41 43
42 // check privileges for non-root users 44 // check privileges for non-root users
43 uid_t uid = getuid(); 45 uid_t uid = getuid();
diff --git a/src/firejail/util.c b/src/firejail/util.c
index e2a4a1d90..68b76b8e8 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -44,6 +44,10 @@
44#include <linux/openat2.h> 44#include <linux/openat2.h>
45#endif 45#endif
46 46
47#ifdef HAVE_GCOV
48#include <gcov.h>
49#endif
50
47#define MAX_GROUPS 1024 51#define MAX_GROUPS 1024
48#define MAXBUF 4098 52#define MAXBUF 4098
49#define EMPTY_STRING ("") 53#define EMPTY_STRING ("")
@@ -435,11 +439,11 @@ void touch_file_as_user(const char *fname, mode_t mode) {
435 // drop privileges 439 // drop privileges
436 drop_privs(0); 440 drop_privs(0);
437 441
438 FILE *fp = fopen(fname, "wx"); 442 int fd = open(fname, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR);
439 if (fp) { 443 if (fd > -1) {
440 fprintf(fp, "\n"); 444 int err = fchmod(fd, mode);
441 SET_PERMS_STREAM(fp, -1, -1, mode); 445 (void) err;
442 fclose(fp); 446 close(fd);
443 } 447 }
444 else 448 else
445 fwarning("cannot create %s\n", fname); 449 fwarning("cannot create %s\n", fname);
@@ -458,6 +462,13 @@ int is_dir(const char *fname) {
458 if (*fname == '\0') 462 if (*fname == '\0')
459 return 0; 463 return 0;
460 464
465 int called_as_root = 0;
466 if (geteuid() == 0)
467 called_as_root = 1;
468
469 if (called_as_root)
470 EUID_USER();
471
461 // if fname doesn't end in '/', add one 472 // if fname doesn't end in '/', add one
462 int rv; 473 int rv;
463 struct stat s; 474 struct stat s;
@@ -473,6 +484,9 @@ int is_dir(const char *fname) {
473 free(tmp); 484 free(tmp);
474 } 485 }
475 486
487 if (called_as_root)
488 EUID_ROOT();
489
476 if (rv == -1) 490 if (rv == -1)
477 return 0; 491 return 0;
478 492
@@ -488,18 +502,83 @@ int is_link(const char *fname) {
488 if (*fname == '\0') 502 if (*fname == '\0')
489 return 0; 503 return 0;
490 504
491 char *dup = strdup(fname); 505 int called_as_root = 0;
492 if (!dup) 506 if (geteuid() == 0)
507 called_as_root = 1;
508
509 if (called_as_root)
510 EUID_USER();
511
512 // remove trailing '/' if any
513 char *tmp = strdup(fname);
514 if (!tmp)
493 errExit("strdup"); 515 errExit("strdup");
494 trim_trailing_slash_or_dot(dup); 516 trim_trailing_slash_or_dot(tmp);
495 517
496 char c; 518 char c;
497 ssize_t rv = readlink(dup, &c, 1); 519 ssize_t rv = readlink(tmp, &c, 1);
520 free(tmp);
521
522 if (called_as_root)
523 EUID_ROOT();
498 524
499 free(dup);
500 return (rv != -1); 525 return (rv != -1);
501} 526}
502 527
528char *realpath_as_user(const char *fname) {
529 assert(fname);
530
531 int called_as_root = 0;
532 if (geteuid() == 0)
533 called_as_root = 1;
534
535 if (called_as_root)
536 EUID_USER();
537
538 char *rv = realpath(fname, NULL);
539
540 if (called_as_root)
541 EUID_ROOT();
542
543 return rv;
544}
545
546int stat_as_user(const char *fname, struct stat *s) {
547 assert(fname);
548
549 int called_as_root = 0;
550 if (geteuid() == 0)
551 called_as_root = 1;
552
553 if (called_as_root)
554 EUID_USER();
555
556 int rv = stat(fname, s);
557
558 if (called_as_root)
559 EUID_ROOT();
560
561 return rv;
562}
563
564int lstat_as_user(const char *fname, struct stat *s) {
565 assert(fname);
566
567 int called_as_root = 0;
568 if (geteuid() == 0)
569 called_as_root = 1;
570
571 if (called_as_root)
572 EUID_USER();
573
574 int rv = lstat(fname, s);
575
576 if (called_as_root)
577 EUID_ROOT();
578
579 return rv;
580}
581
503// remove all slashes and single dots from the end of a path 582// remove all slashes and single dots from the end of a path
504// for example /foo/bar///././. -> /foo/bar 583// for example /foo/bar///././. -> /foo/bar
505void trim_trailing_slash_or_dot(char *path) { 584void trim_trailing_slash_or_dot(char *path) {
@@ -688,9 +767,11 @@ int find_child(pid_t parent, pid_t *child) {
688 if (parent == atoi(ptr)) { 767 if (parent == atoi(ptr)) {
689 // we don't want /usr/bin/xdg-dbus-proxy! 768 // we don't want /usr/bin/xdg-dbus-proxy!
690 char *cmdline = pid_proc_cmdline(pid); 769 char *cmdline = pid_proc_cmdline(pid);
691 if (strncmp(cmdline, XDG_DBUS_PROXY_PATH, strlen(XDG_DBUS_PROXY_PATH)) != 0) 770 if (cmdline) {
692 *child = pid; 771 if (strncmp(cmdline, XDG_DBUS_PROXY_PATH, strlen(XDG_DBUS_PROXY_PATH)) != 0)
693 free(cmdline); 772 *child = pid;
773 free(cmdline);
774 }
694 } 775 }
695 break; // stop reading the file 776 break; // stop reading the file
696 } 777 }
@@ -930,35 +1011,37 @@ static int remove_callback(const char *fpath, const struct stat *sb, int typefla
930 1011
931int remove_overlay_directory(void) { 1012int remove_overlay_directory(void) {
932 EUID_ASSERT(); 1013 EUID_ASSERT();
933 struct stat s;
934 sleep(1); 1014 sleep(1);
935 1015
936 char *path; 1016 char *path;
937 if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) 1017 if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1)
938 errExit("asprintf"); 1018 errExit("asprintf");
939 1019
940 if (lstat(path, &s) == 0) { 1020 if (access(path, F_OK) == 0) {
941 // deal with obvious problems such as symlinks and root ownership
942 if (!S_ISDIR(s.st_mode)) {
943 if (S_ISLNK(s.st_mode))
944 fprintf(stderr, "Error: %s is a symbolic link\n", path);
945 else
946 fprintf(stderr, "Error: %s is not a directory\n", path);
947 exit(1);
948 }
949 if (s.st_uid != getuid()) {
950 fprintf(stderr, "Error: %s is not owned by the current user\n", path);
951 exit(1);
952 }
953
954 pid_t child = fork(); 1021 pid_t child = fork();
955 if (child < 0) 1022 if (child < 0)
956 errExit("fork"); 1023 errExit("fork");
957 if (child == 0) { 1024 if (child == 0) {
958 // open ~/.firejail, fails if there is any symlink 1025 // open ~/.firejail
959 int fd = safer_openat(-1, path, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 1026 int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
960 if (fd == -1) 1027 if (fd == -1) {
961 errExit("safer_openat"); 1028 fprintf(stderr, "Error: cannot open %s\n", path);
1029 exit(1);
1030 }
1031 struct stat s;
1032 if (fstat(fd, &s) == -1)
1033 errExit("fstat");
1034 if (!S_ISDIR(s.st_mode)) {
1035 if (S_ISLNK(s.st_mode))
1036 fprintf(stderr, "Error: %s is a symbolic link\n", path);
1037 else
1038 fprintf(stderr, "Error: %s is not a directory\n", path);
1039 exit(1);
1040 }
1041 if (s.st_uid != getuid()) {
1042 fprintf(stderr, "Error: %s is not owned by the current user\n", path);
1043 exit(1);
1044 }
962 // chdir to ~/.firejail 1045 // chdir to ~/.firejail
963 if (fchdir(fd) == -1) 1046 if (fchdir(fd) == -1)
964 errExit("fchdir"); 1047 errExit("fchdir");
@@ -981,7 +1064,7 @@ int remove_overlay_directory(void) {
981 // wait for the child to finish 1064 // wait for the child to finish
982 waitpid(child, NULL, 0); 1065 waitpid(child, NULL, 0);
983 // check if ~/.firejail was deleted 1066 // check if ~/.firejail was deleted
984 if (stat(path, &s) == 0) 1067 if (access(path, F_OK) == 0)
985 return 1; 1068 return 1;
986 } 1069 }
987 return 0; 1070 return 0;
@@ -1014,9 +1097,8 @@ void flush_stdin(void) {
1014int create_empty_dir_as_user(const char *dir, mode_t mode) { 1097int create_empty_dir_as_user(const char *dir, mode_t mode) {
1015 assert(dir); 1098 assert(dir);
1016 mode &= 07777; 1099 mode &= 07777;
1017 struct stat s;
1018 1100
1019 if (stat(dir, &s)) { 1101 if (access(dir, F_OK) != 0) {
1020 if (arg_debug) 1102 if (arg_debug)
1021 printf("Creating empty %s directory\n", dir); 1103 printf("Creating empty %s directory\n", dir);
1022 pid_t child = fork(); 1104 pid_t child = fork();
@@ -1027,8 +1109,8 @@ int create_empty_dir_as_user(const char *dir, mode_t mode) {
1027 drop_privs(0); 1109 drop_privs(0);
1028 1110
1029 if (mkdir(dir, mode) == 0) { 1111 if (mkdir(dir, mode) == 0) {
1030 if (chmod(dir, mode) == -1) 1112 int err = chmod(dir, mode);
1031 {;} // do nothing 1113 (void) err;
1032 } 1114 }
1033 else if (arg_debug) 1115 else if (arg_debug)
1034 printf("Directory %s not created: %s\n", dir, strerror(errno)); 1116 printf("Directory %s not created: %s\n", dir, strerror(errno));
@@ -1038,7 +1120,7 @@ int create_empty_dir_as_user(const char *dir, mode_t mode) {
1038 _exit(0); 1120 _exit(0);
1039 } 1121 }
1040 waitpid(child, NULL, 0); 1122 waitpid(child, NULL, 0);
1041 if (stat(dir, &s) == 0) 1123 if (access(dir, F_OK) == 0)
1042 return 1; 1124 return 1;
1043 } 1125 }
1044 return 0; 1126 return 0;
@@ -1149,20 +1231,34 @@ unsigned extract_timeout(const char *str) {
1149} 1231}
1150 1232
1151void disable_file_or_dir(const char *fname) { 1233void disable_file_or_dir(const char *fname) {
1234 assert(fname);
1235
1236 EUID_USER();
1237 int fd = open(fname, O_PATH|O_CLOEXEC);
1238 EUID_ROOT();
1239 if (fd < 0)
1240 return;
1241
1152 struct stat s; 1242 struct stat s;
1153 if (stat(fname, &s) != -1) { 1243 if (fstat(fd, &s) < 0) { // FUSE
1154 if (arg_debug) 1244 if (errno != EACCES)
1155 printf("blacklist %s\n", fname); 1245 errExit("fstat");
1156 if (is_dir(fname)) { 1246 close(fd);
1157 if (mount(RUN_RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) 1247 return;
1158 errExit("disable directory");
1159 }
1160 else {
1161 if (mount(RUN_RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0)
1162 errExit("disable file");
1163 }
1164 fs_logger2("blacklist", fname);
1165 } 1248 }
1249
1250 if (arg_debug)
1251 printf("blacklist %s\n", fname);
1252 if (S_ISDIR(s.st_mode)) {
1253 if (bind_mount_path_to_fd(RUN_RO_DIR, fd) < 0)
1254 errExit("disable directory");
1255 }
1256 else {
1257 if (bind_mount_path_to_fd(RUN_RO_FILE, fd) < 0)
1258 errExit("disable file");
1259 }
1260 close(fd);
1261 fs_logger2("blacklist", fname);
1166} 1262}
1167 1263
1168void disable_file_path(const char *path, const char *file) { 1264void disable_file_path(const char *path, const char *file) {
@@ -1249,6 +1345,60 @@ int safer_openat(int dirfd, const char *path, int flags) {
1249 return fd; 1345 return fd;
1250} 1346}
1251 1347
1348int remount_by_fd(int dst, unsigned long mountflags) {
1349 char *proc;
1350 if (asprintf(&proc, "/proc/self/fd/%d", dst) < 0)
1351 errExit("asprintf");
1352
1353 int rv = mount(NULL, proc, NULL, mountflags|MS_BIND|MS_REMOUNT, NULL);
1354 if (rv < 0 && arg_debug)
1355 printf("Failed mount: %s\n", strerror(errno));
1356
1357 free(proc);
1358 return rv;
1359}
1360
1361int bind_mount_by_fd(int src, int dst) {
1362 char *proc_src, *proc_dst;
1363 if (asprintf(&proc_src, "/proc/self/fd/%d", src) < 0 ||
1364 asprintf(&proc_dst, "/proc/self/fd/%d", dst) < 0)
1365 errExit("asprintf");
1366
1367 int rv = mount(proc_src, proc_dst, NULL, MS_BIND|MS_REC, NULL);
1368 if (rv < 0 && arg_debug)
1369 printf("Failed mount: %s\n", strerror(errno));
1370
1371 free(proc_src);
1372 free(proc_dst);
1373 return rv;
1374}
1375
1376int bind_mount_fd_to_path(int src, const char *destname) {
1377 char *proc;
1378 if (asprintf(&proc, "/proc/self/fd/%d", src) < 0)
1379 errExit("asprintf");
1380
1381 int rv = mount(proc, destname, NULL, MS_BIND|MS_REC, NULL);
1382 if (rv < 0 && arg_debug)
1383 printf("Failed mount: %s\n", strerror(errno));
1384
1385 free(proc);
1386 return rv;
1387}
1388
1389int bind_mount_path_to_fd(const char *srcname, int dst) {
1390 char *proc;
1391 if (asprintf(&proc, "/proc/self/fd/%d", dst) < 0)
1392 errExit("asprintf");
1393
1394 int rv = mount(srcname, proc, NULL, MS_BIND|MS_REC, NULL);
1395 if (rv < 0 && arg_debug)
1396 printf("Failed mount: %s\n", strerror(errno));
1397
1398 free(proc);
1399 return rv;
1400}
1401
1252int has_handler(pid_t pid, int signal) { 1402int has_handler(pid_t pid, int signal) {
1253 if (signal > 0 && signal <= SIGRTMAX) { 1403 if (signal > 0 && signal <= SIGRTMAX) {
1254 char *fname; 1404 char *fname;
@@ -1358,14 +1508,14 @@ static int has_link(const char *dir) {
1358 return 0; 1508 return 0;
1359} 1509}
1360 1510
1361void check_homedir(void) { 1511void check_homedir(const char *dir) {
1362 assert(cfg.homedir); 1512 assert(dir);
1363 if (cfg.homedir[0] != '/') { 1513 if (dir[0] != '/') {
1364 fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); 1514 fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir);
1365 exit(1); 1515 exit(1);
1366 } 1516 }
1367 // symlinks are rejected in many places 1517 // symlinks are rejected in many places
1368 if (has_link(cfg.homedir)) { 1518 if (has_link(dir)) {
1369 fprintf(stderr, "No full support for symbolic links in path of user directory.\n" 1519 fprintf(stderr, "No full support for symbolic links in path of user directory.\n"
1370 "Please provide resolved path in password database (/etc/passwd).\n\n"); 1520 "Please provide resolved path in password database (/etc/passwd).\n\n");
1371 } 1521 }
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index 257d376a1..0619ff380 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -204,7 +204,6 @@ static int random_display_number(void) {
204void x11_start_xvfb(int argc, char **argv) { 204void x11_start_xvfb(int argc, char **argv) {
205 EUID_ASSERT(); 205 EUID_ASSERT();
206 int i; 206 int i;
207 struct stat s;
208 pid_t jail = 0; 207 pid_t jail = 0;
209 pid_t server = 0; 208 pid_t server = 0;
210 209
@@ -348,7 +347,7 @@ void x11_start_xvfb(int argc, char **argv) {
348 // wait for x11 server to start 347 // wait for x11 server to start
349 while (++n < 10) { 348 while (++n < 10) {
350 sleep(1); 349 sleep(1);
351 if (stat(fname, &s) == 0) 350 if (access(fname, F_OK) == 0)
352 break; 351 break;
353 }; 352 };
354 353
@@ -427,7 +426,6 @@ static char *extract_setting(int argc, char **argv, const char *argument) {
427void x11_start_xephyr(int argc, char **argv) { 426void x11_start_xephyr(int argc, char **argv) {
428 EUID_ASSERT(); 427 EUID_ASSERT();
429 int i; 428 int i;
430 struct stat s;
431 pid_t jail = 0; 429 pid_t jail = 0;
432 pid_t server = 0; 430 pid_t server = 0;
433 431
@@ -586,7 +584,7 @@ void x11_start_xephyr(int argc, char **argv) {
586 // wait for x11 server to start 584 // wait for x11 server to start
587 while (++n < 10) { 585 while (++n < 10) {
588 sleep(1); 586 sleep(1);
589 if (stat(fname, &s) == 0) 587 if (access(fname, F_OK) == 0)
590 break; 588 break;
591 }; 589 };
592 590
@@ -701,7 +699,6 @@ static char * get_title_arg_str() {
701static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, int display, char *display_str) { 699static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv, int display, char *display_str) {
702 EUID_ASSERT(); 700 EUID_ASSERT();
703 int i; 701 int i;
704 struct stat s;
705 pid_t client = 0; 702 pid_t client = 0;
706 pid_t server = 0; 703 pid_t server = 0;
707 704
@@ -818,7 +815,7 @@ static void __attribute__((noreturn)) x11_start_xpra_old(int argc, char **argv,
818 // wait for x11 server to start 815 // wait for x11 server to start
819 while (++n < 10) { 816 while (++n < 10) {
820 sleep(1); 817 sleep(1);
821 if (stat(fname, &s) == 0) 818 if (access(fname, F_OK) == 0)
822 break; 819 break;
823 } 820 }
824 821
@@ -1207,14 +1204,13 @@ void x11_xorg(void) {
1207 fmessage("Generating a new .Xauthority file\n"); 1204 fmessage("Generating a new .Xauthority file\n");
1208 mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid()); 1205 mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid());
1209 // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR 1206 // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR
1207 EUID_USER();
1210 char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX"; 1208 char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX";
1211 int fd = mkstemp(tmpfname); 1209 int fd = mkstemp(tmpfname);
1212 if (fd == -1) { 1210 if (fd == -1) {
1213 fprintf(stderr, "Error: cannot create .Xauthority file\n"); 1211 fprintf(stderr, "Error: cannot create .Xauthority file\n");
1214 exit(1); 1212 exit(1);
1215 } 1213 }
1216 if (fchown(fd, getuid(), getgid()) == -1)
1217 errExit("chown");
1218 close(fd); 1214 close(fd);
1219 1215
1220 // run xauth 1216 // run xauth
@@ -1224,16 +1220,14 @@ void x11_xorg(void) {
1224 else 1220 else
1225 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname, 1221 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname,
1226 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted"); 1222 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted");
1227 // remove xauth copy
1228 unlink(RUN_XAUTH_FILE);
1229 1223
1230 // ensure there is already a file ~/.Xauthority, so that bind-mount below will work. 1224 // ensure there is already a file ~/.Xauthority, so that bind-mount below will work.
1231 char *dest; 1225 char *dest;
1232 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) 1226 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
1233 errExit("asprintf"); 1227 errExit("asprintf");
1234 if (lstat(dest, &s) == -1) { 1228 if (access(dest, F_OK) == -1) {
1235 touch_file_as_user(dest, 0600); 1229 touch_file_as_user(dest, 0600);
1236 if (stat(dest, &s) == -1) { 1230 if (access(dest, F_OK) == -1) {
1237 fprintf(stderr, "Error: cannot create %s\n", dest); 1231 fprintf(stderr, "Error: cannot create %s\n", dest);
1238 exit(1); 1232 exit(1);
1239 } 1233 }
@@ -1276,21 +1270,16 @@ void x11_xorg(void) {
1276 // mount via the link in /proc/self/fd 1270 // mount via the link in /proc/self/fd
1277 if (arg_debug) 1271 if (arg_debug)
1278 printf("Mounting %s on %s\n", tmpfname, dest); 1272 printf("Mounting %s on %s\n", tmpfname, dest);
1279 char *proc_src, *proc_dst; 1273 EUID_ROOT();
1280 if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1) 1274 if (bind_mount_by_fd(src, dst)) {
1281 errExit("asprintf");
1282 if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1)
1283 errExit("asprintf");
1284 if (mount(proc_src, proc_dst, NULL, MS_BIND, NULL) == -1) {
1285 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); 1275 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n");
1286 exit(1); 1276 exit(1);
1287 } 1277 }
1278 EUID_USER();
1288 // check /proc/self/mountinfo to confirm the mount is ok 1279 // check /proc/self/mountinfo to confirm the mount is ok
1289 MountData *mptr = get_last_mount(); 1280 MountData *mptr = get_last_mount();
1290 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) 1281 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
1291 errLogExit("invalid .Xauthority mount"); 1282 errLogExit("invalid .Xauthority mount");
1292 free(proc_src);
1293 free(proc_dst);
1294 close(src); 1283 close(src);
1295 close(dst); 1284 close(dst);
1296 1285
@@ -1302,6 +1291,7 @@ void x11_xorg(void) {
1302 char *rp = realpath(envar, NULL); 1291 char *rp = realpath(envar, NULL);
1303 if (rp) { 1292 if (rp) {
1304 if (strcmp(rp, dest) != 0) 1293 if (strcmp(rp, dest) != 0)
1294 // disable_file_or_dir returns with EUID 0
1305 disable_file_or_dir(rp); 1295 disable_file_or_dir(rp);
1306 free(rp); 1296 free(rp);
1307 } 1297 }
@@ -1311,9 +1301,13 @@ void x11_xorg(void) {
1311 free(dest); 1301 free(dest);
1312 1302
1313 // mask RUN_XAUTHORITY_SEC_DIR 1303 // mask RUN_XAUTHORITY_SEC_DIR
1304 EUID_ROOT();
1314 if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) 1305 if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
1315 errExit("mounting tmpfs"); 1306 errExit("mounting tmpfs");
1316 fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR); 1307 fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR);
1308
1309 // cleanup
1310 unlink(RUN_XAUTH_FILE);
1317#endif 1311#endif
1318} 1312}
1319 1313
@@ -1327,7 +1321,7 @@ void fs_x11(void) {
1327 struct stat s1, s2; 1321 struct stat s1, s2;
1328 if (stat("/tmp", &s1) != 0 || lstat("/tmp/.X11-unix", &s2) != 0) 1322 if (stat("/tmp", &s1) != 0 || lstat("/tmp/.X11-unix", &s2) != 0)
1329 return; 1323 return;
1330 if ((s1.st_mode & S_ISVTX) == 0) { 1324 if ((s1.st_mode & S_ISVTX) != S_ISVTX) {
1331 fwarning("cannot mask X11 sockets: sticky bit not set on /tmp directory\n"); 1325 fwarning("cannot mask X11 sockets: sticky bit not set on /tmp directory\n");
1332 return; 1326 return;
1333 } 1327 }
@@ -1335,68 +1329,46 @@ void fs_x11(void) {
1335 fwarning("cannot mask X11 sockets: /tmp/.X11-unix not owned by root user\n"); 1329 fwarning("cannot mask X11 sockets: /tmp/.X11-unix not owned by root user\n");
1336 return; 1330 return;
1337 } 1331 }
1332
1333 // the mount source is under control of the user, so be careful and
1334 // mount without following symbolic links, using a file descriptor
1338 char *x11file; 1335 char *x11file;
1339 if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1) 1336 if (asprintf(&x11file, "/tmp/.X11-unix/X%d", display) == -1)
1340 errExit("asprintf"); 1337 errExit("asprintf");
1341 struct stat x11stat; 1338 int src = open(x11file, O_PATH|O_NOFOLLOW|O_CLOEXEC);
1342 if (lstat(x11file, &x11stat) != 0 || !S_ISSOCK(x11stat.st_mode)) { 1339 if (src < 0) {
1340 free(x11file);
1341 return;
1342 }
1343 struct stat s3;
1344 if (fstat(src, &s3) < 0)
1345 errExit("fstat");
1346 if (!S_ISSOCK(s3.st_mode)) {
1347 close(src);
1343 free(x11file); 1348 free(x11file);
1344 return; 1349 return;
1345 } 1350 }
1346 1351
1347 if (arg_debug || arg_debug_whitelists) 1352 if (arg_debug || arg_debug_whitelists)
1348 fprintf(stderr, "Masking all X11 sockets except %s\n", x11file); 1353 fprintf(stderr, "Masking all X11 sockets except %s\n", x11file);
1349
1350 // Move the real /tmp/.X11-unix to a scratch location
1351 // so we can still access x11file after we mount a
1352 // tmpfs over /tmp/.X11-unix.
1353 if (mkdir(RUN_WHITELIST_X11_DIR, 0700) == -1)
1354 errExit("mkdir");
1355 if (mount("/tmp/.X11-unix", RUN_WHITELIST_X11_DIR, 0, MS_BIND|MS_REC, 0) < 0)
1356 errExit("mount bind");
1357
1358 // This directory must be mode 1777 1354 // This directory must be mode 1777
1359 if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs", 1355 if (mount("tmpfs", "/tmp/.X11-unix", "tmpfs",
1360 MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME, 1356 MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_STRICTATIME,
1361 "mode=1777,uid=0,gid=0") < 0) 1357 "mode=1777,uid=0,gid=0") < 0)
1362 errExit("mounting tmpfs on /tmp/.X11-unix"); 1358 errExit("mounting tmpfs on /tmp/.X11-unix");
1359 selinux_relabel_path("/tmp/.X11-unix", "/tmp/.X11-unix");
1363 fs_logger("tmpfs /tmp/.X11-unix"); 1360 fs_logger("tmpfs /tmp/.X11-unix");
1364 1361
1365 // create an empty root-owned file which will have the desired socket bind-mounted over it 1362 // create an empty root-owned file which will have the desired socket bind-mounted over it
1366 int fd = open(x11file, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR); 1363 int dst = open(x11file, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR);
1367 if (fd < 0) 1364 if (dst < 0)
1368 errExit(x11file); 1365 errExit("open");
1369 close(fd);
1370 1366
1371 // the mount source is under control of the user, so be careful and 1367 if (bind_mount_by_fd(src, dst))
1372 // mount without following symbolic links, using a file descriptor
1373 char *wx11file;
1374 if (asprintf(&wx11file, "%s/X%d", RUN_WHITELIST_X11_DIR, display) == -1)
1375 errExit("asprintf");
1376 fd = safer_openat(-1, wx11file, O_PATH|O_NOFOLLOW|O_CLOEXEC);
1377 if (fd == -1)
1378 errExit("opening X11 socket");
1379 // confirm once more we are mounting a socket
1380 if (fstat(fd, &x11stat) == -1)
1381 errExit("fstat");
1382 if (!S_ISSOCK(x11stat.st_mode)) {
1383 errno = ENOTSOCK;
1384 errExit("mounting X11 socket");
1385 }
1386 char *proc;
1387 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
1388 errExit("asprintf");
1389 if (mount(proc, x11file, NULL, MS_BIND|MS_REC, NULL) < 0)
1390 errExit("mount bind"); 1368 errExit("mount bind");
1369 close(src);
1370 close(dst);
1391 fs_logger2("whitelist", x11file); 1371 fs_logger2("whitelist", x11file);
1392 close(fd);
1393 free(proc);
1394
1395 // block access to RUN_WHITELIST_X11_DIR
1396 if (mount(RUN_RO_DIR, RUN_WHITELIST_X11_DIR, 0, MS_BIND, 0) < 0)
1397 errExit("mount");
1398 fs_logger2("blacklist", RUN_WHITELIST_X11_DIR);
1399 free(wx11file);
1400 free(x11file); 1372 free(x11file);
1401#endif 1373#endif
1402} 1374}
diff --git a/src/firemon/interface.c b/src/firemon/interface.c
index e04b6f431..b93d4a5a2 100644
--- a/src/firemon/interface.c
+++ b/src/firemon/interface.c
@@ -33,6 +33,10 @@
33//#include <net/route.h> 33//#include <net/route.h>
34//#include <linux/if_bridge.h> 34//#include <linux/if_bridge.h>
35 35
36#ifdef HAVE_GCOV
37#include <gcov.h>
38#endif
39
36// print IP addresses for all interfaces 40// print IP addresses for all interfaces
37static void net_ifprint(void) { 41static void net_ifprint(void) {
38 uint32_t ip; 42 uint32_t ip;
diff --git a/src/firemon/netstats.c b/src/firemon/netstats.c
index 850959eb3..23d228e26 100644
--- a/src/firemon/netstats.c
+++ b/src/firemon/netstats.c
@@ -24,6 +24,10 @@
24#include <sys/stat.h> 24#include <sys/stat.h>
25#include <unistd.h> 25#include <unistd.h>
26 26
27#ifdef HAVE_GCOV
28#include <gcov.h>
29#endif
30
27#define MAXBUF 4096 31#define MAXBUF 4096
28 32
29// ip -s link: device stats 33// ip -s link: device stats
diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c
index 8085d2d29..4e809681e 100644
--- a/src/firemon/procevent.c
+++ b/src/firemon/procevent.c
@@ -30,6 +30,10 @@
30#include <fcntl.h> 30#include <fcntl.h>
31#include <sys/uio.h> 31#include <sys/uio.h>
32 32
33#ifdef HAVE_GCOV
34#include <gcov.h>
35#endif
36
33#define PIDS_BUFLEN 4096 37#define PIDS_BUFLEN 4096
34#define SERVER_PORT 889 // 889-899 is left unassigned by IANA 38#define SERVER_PORT 889 // 889-899 is left unassigned by IANA
35 39
diff --git a/src/firemon/top.c b/src/firemon/top.c
index a25e3c0d8..9d6f34991 100644
--- a/src/firemon/top.c
+++ b/src/firemon/top.c
@@ -24,6 +24,10 @@
24#include <sys/stat.h> 24#include <sys/stat.h>
25#include <unistd.h> 25#include <unistd.h>
26 26
27#ifdef HAVE_GCOV
28#include <gcov.h>
29#endif
30
27static unsigned pgs_rss = 0; 31static unsigned pgs_rss = 0;
28static unsigned pgs_shared = 0; 32static unsigned pgs_shared = 0;
29static unsigned clocktick = 0; 33static unsigned clocktick = 0;
diff --git a/src/include/rundefs.h b/src/include/rundefs.h
index a172dd511..3db750da3 100644
--- a/src/include/rundefs.h
+++ b/src/include/rundefs.h
@@ -79,12 +79,8 @@
79#define PATH_SECCOMP_MDWX_32 LIBDIR "/firejail/seccomp.mdwx.32" 79#define PATH_SECCOMP_MDWX_32 LIBDIR "/firejail/seccomp.mdwx.32"
80#define PATH_SECCOMP_BLOCK_SECONDARY LIBDIR "/firejail/seccomp.block_secondary" // secondary arch blocking filter built during make 80#define PATH_SECCOMP_BLOCK_SECONDARY LIBDIR "/firejail/seccomp.block_secondary" // secondary arch blocking filter built during make
81 81
82
83#define RUN_DEV_DIR RUN_MNT_DIR "/dev" 82#define RUN_DEV_DIR RUN_MNT_DIR "/dev"
84#define RUN_DEVLOG_FILE RUN_MNT_DIR "/devlog" 83#define RUN_DEVLOG_FILE RUN_MNT_DIR "/devlog"
85
86#define RUN_WHITELIST_X11_DIR RUN_MNT_DIR "/orig-x11"
87
88#define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" // private options 84#define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" // private options
89#define RUN_XAUTH_FILE RUN_MNT_DIR "/xauth" // x11=xorg 85#define RUN_XAUTH_FILE RUN_MNT_DIR "/xauth" // x11=xorg
90#define RUN_XAUTHORITY_SEC_DIR RUN_MNT_DIR "/.sec.Xauthority" // x11=xorg 86#define RUN_XAUTHORITY_SEC_DIR RUN_MNT_DIR "/.sec.Xauthority" // x11=xorg
diff --git a/src/jailcheck/access.c b/src/jailcheck/access.c
index c18d64a82..3c2f46495 100644
--- a/src/jailcheck/access.c
+++ b/src/jailcheck/access.c
@@ -36,7 +36,7 @@ void access_setup(const char *directory) {
36 assert(user_home_dir); 36 assert(user_home_dir);
37 37
38 if (files_cnt >= MAX_TEST_FILES) { 38 if (files_cnt >= MAX_TEST_FILES) {
39 fprintf(stderr, "Error: maximum number of test directories exceded\n"); 39 fprintf(stderr, "Error: maximum number of test directories exceeded\n");
40 exit(1); 40 exit(1);
41 } 41 }
42 42
diff --git a/src/jailcheck/jailcheck.h b/src/jailcheck/jailcheck.h
index 32be1c978..be3104da3 100644
--- a/src/jailcheck/jailcheck.h
+++ b/src/jailcheck/jailcheck.h
@@ -53,6 +53,8 @@ void apparmor_test(pid_t pid);
53// seccomp.c 53// seccomp.c
54void seccomp_test(pid_t pid); 54void seccomp_test(pid_t pid);
55 55
56// network.c
57void network_test(void);
56// utils.c 58// utils.c
57char *get_sudo_user(void); 59char *get_sudo_user(void);
58char *get_homedir(const char *user, uid_t *uid, gid_t *gid); 60char *get_homedir(const char *user, uid_t *uid, gid_t *gid);
diff --git a/src/jailcheck/main.c b/src/jailcheck/main.c
index 4d642bf96..812ac5808 100644
--- a/src/jailcheck/main.c
+++ b/src/jailcheck/main.c
@@ -157,6 +157,7 @@ int main(int argc, char **argv) {
157 seccomp_test(pid); 157 seccomp_test(pid);
158 fflush(0); 158 fflush(0);
159 159
160 // filesystem tests
160 pid_t child = fork(); 161 pid_t child = fork();
161 if (child == -1) 162 if (child == -1)
162 errExit("fork"); 163 errExit("fork");
@@ -185,6 +186,28 @@ int main(int argc, char **argv) {
185 } 186 }
186 int status; 187 int status;
187 wait(&status); 188 wait(&status);
189
190 // network test
191 child = fork();
192 if (child == -1)
193 errExit("fork");
194 if (child == 0) {
195 int rv = join_namespace(pid, "net");
196 if (rv == 0)
197 network_test();
198 else {
199 printf(" Error: I cannot join the process network stack\n");
200 exit(1);
201 }
202
203 // drop privileges in order not to trigger cleanup()
204 if (setgid(user_gid) != 0)
205 errExit("setgid");
206 if (setuid(user_uid) != 0)
207 errExit("setuid");
208 return 0;
209 }
210 wait(&status);
188 } 211 }
189 } 212 }
190 213
diff --git a/src/jailcheck/network.c b/src/jailcheck/network.c
new file mode 100644
index 000000000..636344e77
--- /dev/null
+++ b/src/jailcheck/network.c
@@ -0,0 +1,56 @@
1/*
2 * Copyright (C) 2014-2021 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "jailcheck.h"
21#include <netdb.h>
22#include <arpa/inet.h>
23#include <ifaddrs.h>
24#include <net/if.h>
25#include <linux/connector.h>
26#include <linux/netlink.h>
27#include <linux/if_link.h>
28#include <linux/sockios.h>
29#include <sys/ioctl.h>
30
31
32void network_test(void) {
33 // I am root running in a network namespace
34 struct ifaddrs *ifaddr, *ifa;
35 int found = 0;
36
37 // walk through the linked list
38 if (getifaddrs(&ifaddr) == -1)
39 errExit("getifaddrs");
40 for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
41 if (strcmp(ifa->ifa_name, "lo") == 0)
42 continue;
43 found = 1;
44 break;
45 }
46
47 freeifaddrs(ifaddr);
48
49 if (found)
50 printf(" Networking: enabled\n");
51 else
52 printf(" Networking: disabled\n");
53}
54
55
56
diff --git a/src/jailcheck/sysfiles.c b/src/jailcheck/sysfiles.c
index caeb580af..9a0d6350e 100644
--- a/src/jailcheck/sysfiles.c
+++ b/src/jailcheck/sysfiles.c
@@ -34,7 +34,7 @@ void sysfiles_setup(const char *file) {
34 assert(file); 34 assert(file);
35 35
36 if (files_cnt >= MAX_TEST_FILES) { 36 if (files_cnt >= MAX_TEST_FILES) {
37 fprintf(stderr, "Error: maximum number of system test files exceded\n"); 37 fprintf(stderr, "Error: maximum number of system test files exceeded\n");
38 exit(1); 38 exit(1);
39 } 39 }
40 40
diff --git a/src/lib/ldd_utils.c b/src/lib/ldd_utils.c
index cd60d74e4..c5dde85b0 100644
--- a/src/lib/ldd_utils.c
+++ b/src/lib/ldd_utils.c
@@ -50,7 +50,7 @@ int is_lib_64(const char *exe) {
50 unsigned char buf[EI_NIDENT]; 50 unsigned char buf[EI_NIDENT];
51 ssize_t len = 0; 51 ssize_t len = 0;
52 while (len < EI_NIDENT) { 52 while (len < EI_NIDENT) {
53 ssize_t sz = read(fd, buf, EI_NIDENT); 53 ssize_t sz = read(fd, buf + len, EI_NIDENT - len);
54 if (sz <= 0) 54 if (sz <= 0)
55 goto doexit; 55 goto doexit;
56 len += sz; 56 len += sz;
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index 12e841af5..db58e0910 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -420,7 +420,7 @@ Make directory or file read-only.
420Make directory or file read-write. 420Make directory or file read-write.
421.TP 421.TP
422\fBtmpfs directory 422\fBtmpfs directory
423Mount an empty tmpfs filesystem on top of directory. This option is available only when running the sandbox as root. 423Mount an empty tmpfs filesystem on top of directory. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions.
424.TP 424.TP
425\fBtracelog 425\fBtracelog
426Blacklist violations logged to syslog. 426Blacklist violations logged to syslog.
@@ -428,8 +428,9 @@ Blacklist violations logged to syslog.
428\fBwhitelist file_or_directory 428\fBwhitelist file_or_directory
429Whitelist directory or file. A temporary file system is mounted on the top directory, and the 429Whitelist directory or file. A temporary file system is mounted on the top directory, and the
430whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, 430whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent,
431everything else is discarded when the sandbox is closed. The top directory could be 431everything else is discarded when the sandbox is closed. The top directory can be
432user home, /dev, /etc, /media, /mnt, /opt, /srv, /sys/module, /usr/share, /var, and /tmp. 432all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and
433all directories in /usr.
433.br 434.br
434 435
435.br 436.br
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index c72a1dbd8..d18811316 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -2568,14 +2568,13 @@ Kill the sandbox automatically after the time has elapsed. The time is specified
2568$ firejail \-\-timeout=01:30:00 firefox 2568$ firejail \-\-timeout=01:30:00 firefox
2569.TP 2569.TP
2570\fB\-\-tmpfs=dirname 2570\fB\-\-tmpfs=dirname
2571Mount a writable tmpfs filesystem on directory dirname. This option is available only when running the sandbox as root. 2571Mount a writable tmpfs filesystem on directory dirname. Directories outside user home or not owned by the user are not allowed. Sandboxes running as root are exempt from these restrictions. File globbing is supported, see \fBFILE GLOBBING\fR section for more details.
2572File globbing is supported, see \fBFILE GLOBBING\fR section for more details.
2573.br 2572.br
2574 2573
2575.br 2574.br
2576Example: 2575Example:
2577.br 2576.br
2578# firejail \-\-tmpfs=/var 2577$ firejail \-\-tmpfs=~/.local/share
2579.TP 2578.TP
2580\fB\-\-top 2579\fB\-\-top
2581Monitor the most CPU-intensive sandboxes, see \fBMONITORING\fR section for more details. 2580Monitor the most CPU-intensive sandboxes, see \fBMONITORING\fR section for more details.
@@ -2725,8 +2724,9 @@ $ firejail \-\-net=br0 --veth-name=if0
2725\fB\-\-whitelist=dirname_or_filename 2724\fB\-\-whitelist=dirname_or_filename
2726Whitelist directory or file. A temporary file system is mounted on the top directory, and the 2725Whitelist directory or file. A temporary file system is mounted on the top directory, and the
2727whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, 2726whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent,
2728everything else is discarded when the sandbox is closed. The top directory could be 2727everything else is discarded when the sandbox is closed. The top directory can be
2729user home, /dev, /etc, /media, /mnt, /opt, /run/user/$UID, /srv, /sys/module, /tmp, /usr/share and /var. 2728all directories in / (except /proc and /sys), /sys/module, /run/user/$UID, $HOME and
2729all directories in /usr.
2730.br 2730.br
2731 2731
2732.br 2732.br
diff --git a/src/man/jailcheck.txt b/src/man/jailcheck.txt
index c80e305cc..483f47fb9 100644
--- a/src/man/jailcheck.txt
+++ b/src/man/jailcheck.txt
@@ -23,6 +23,8 @@ them from inside the sandbox.
23.TP 23.TP
24\fB5. Seccomp test 24\fB5. Seccomp test
25.TP 25.TP
26\fB6. Networking test
27.TP
26The program is started as root using sudo. 28The program is started as root using sudo.
27 29
28.SH OPTIONS 30.SH OPTIONS
@@ -56,6 +58,8 @@ $ sudo jailcheck
56.br 58.br
57 Warning: I can run programs in /home/netblue 59 Warning: I can run programs in /home/netblue
58.br 60.br
61 Networking: disabled
62.br
59 63
60.br 64.br
612055:netblue::firejail /usr/bin/ssh -X netblue@x.y.z.net 652055:netblue::firejail /usr/bin/ssh -X netblue@x.y.z.net
@@ -64,12 +68,16 @@ $ sudo jailcheck
64.br 68.br
65 Warning: I can read ~/.ssh 69 Warning: I can read ~/.ssh
66.br 70.br
71 Networking: enabled
72.br
67 73
68.br 74.br
692186:netblue:libreoffice:firejail --appimage /opt/LibreOffice-fresh.appimage 752186:netblue:libreoffice:firejail --appimage /opt/LibreOffice-fresh.appimage
70.br 76.br
71 Virtual dirs: /tmp, /var/tmp, /dev, 77 Virtual dirs: /tmp, /var/tmp, /dev,
72.br 78.br
79 Networking: enabled
80.br
73 81
74.br 82.br
7526090:netblue::/usr/bin/firejail /opt/firefox/firefox 8326090:netblue::/usr/bin/firejail /opt/firefox/firefox
@@ -78,6 +86,8 @@ $ sudo jailcheck
78.br 86.br
79 /run/user/1000, 87 /run/user/1000,
80.br 88.br
89 Networking: enabled
90.br
81 91
82.br 92.br
8326160:netblue:tor:firejail --private=~/tor-browser_en-US ./start-tor 9326160:netblue:tor:firejail --private=~/tor-browser_en-US ./start-tor
@@ -90,6 +100,8 @@ $ sudo jailcheck
90.br 100.br
91 Warning: I can run programs in /home/netblue 101 Warning: I can run programs in /home/netblue
92.br 102.br
103 Networking: enabled
104.br
93 105
94 106
95.SH LICENSE 107.SH LICENSE
diff --git a/test/fs/fscheck-tmpfs.exp b/test/fs/fscheck-tmpfs.exp
index 8dd08aa72..78b6efb76 100755
--- a/test/fs/fscheck-tmpfs.exp
+++ b/test/fs/fscheck-tmpfs.exp
@@ -41,7 +41,7 @@ after 500
41send -- "firejail --noprofile --tmpfs=/tmp/fjtest-dir\r" 41send -- "firejail --noprofile --tmpfs=/tmp/fjtest-dir\r"
42expect { 42expect {
43 timeout {puts "TESTING ERROR 5\n";exit} 43 timeout {puts "TESTING ERROR 5\n";exit}
44 "Error" 44 "Warning: you are not allowed to mount a tmpfs"
45} 45}
46after 500 46after 500
47 47