aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--RELNOTES3
-rwxr-xr-xcontrib/fix_private-bin.py2
-rwxr-xr-xcontrib/fjclip.py1
-rwxr-xr-xcontrib/gdb-firejail.sh21
-rw-r--r--etc/celluloid.profile3
-rw-r--r--etc/conplay.profile14
-rw-r--r--etc/disable-common.inc2
-rw-r--r--etc/disable-programs.inc1
-rw-r--r--etc/firejail.config8
-rw-r--r--etc/gajim.profile1
-rw-r--r--etc/galculator.profile2
-rw-r--r--etc/less.profile4
-rw-r--r--etc/mpg123-alsa.profile9
-rw-r--r--etc/mpg123-id3dump.profile12
-rw-r--r--etc/mpg123-jack.profile9
-rw-r--r--etc/mpg123-nas.profile9
-rw-r--r--etc/mpg123-openal.profile9
-rw-r--r--etc/mpg123-oss.profile9
-rw-r--r--etc/mpg123-portaudio.profile9
-rw-r--r--etc/mpg123-pulse.profile9
-rw-r--r--etc/mpg123-strip.profile9
-rw-r--r--etc/mpg123.bin.profile9
-rw-r--r--etc/mpg123.profile38
-rw-r--r--etc/mpsyt.profile3
-rw-r--r--etc/mpv.profile4
-rw-r--r--etc/mumble.profile2
-rw-r--r--etc/obs.profile2
-rw-r--r--etc/out123.profile9
-rw-r--r--etc/pavucontrol.profile2
-rw-r--r--etc/qpdfview.profile3
-rw-r--r--etc/riot-desktop.profile3
-rw-r--r--etc/smplayer.profile1
-rw-r--r--etc/wire-desktop.profile2
-rw-r--r--etc/youtube-dl.profile4
-rw-r--r--src/fcopy/main.c19
-rw-r--r--src/firecfg/firecfg.config13
-rw-r--r--src/firejail/appimage.c11
-rw-r--r--src/firejail/checkcfg.c8
-rw-r--r--src/firejail/firejail.h2
-rw-r--r--src/firejail/fs.c129
-rw-r--r--src/firejail/fs_dev.c4
-rw-r--r--src/firejail/fs_home.c98
-rw-r--r--src/firejail/fs_whitelist.c20
-rw-r--r--src/firejail/main.c68
-rw-r--r--src/firejail/restrict_users.c16
-rw-r--r--src/firejail/sandbox.c6
-rw-r--r--src/firejail/sbox.c42
-rw-r--r--src/firejail/util.c54
-rw-r--r--src/lib/pid.c3
-rw-r--r--src/libpostexecseccomp/libpostexecseccomp.c4
-rw-r--r--src/libtrace/libtrace.c179
-rw-r--r--src/man/firejail.txt6
53 files changed, 600 insertions, 313 deletions
diff --git a/README.md b/README.md
index 22d094d04..e1dc875ab 100644
--- a/README.md
+++ b/README.md
@@ -115,4 +115,5 @@ We also keep a list of profile fixes for previous released versions in [etc-fixe
115 115
116## New profiles: 116## New profiles:
117 117
118gnome-sound-recorder, godot, jerry, keepassxc-cli, keepassxc-proxy, klatexformula, klatexformula_cmdl, links, newsbeuter, OpenArena, pandoc, qgis, rhythmbox-client, tcpdump, teams-for-linux, tshark, xlinks, zeal 118gnome-sound-recorder, godot, jerry, keepassxc-cli, keepassxc-proxy, klatexformula, klatexformula_cmdl, links, newsbeuter, OpenArena, pandoc, qgis, rhythmbox-client, tcpdump, teams-for-linux, tshark, xlinks, zeal,
119mpg123,
diff --git a/RELNOTES b/RELNOTES
index c35b2971a..d5baa3bc4 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,10 +1,11 @@
1firejail (0.9.61) baseline; urgency=low 1firejail (0.9.61) baseline; urgency=low
2 * work in progress 2 * work in progress
3 * added file-copy-limit in /etc/firejail/firejail.config
3 * profile templates 4 * profile templates
4 * new profiles: qgis, klatexformula, klatexformula_cmdl, links, xlinks 5 * new profiles: qgis, klatexformula, klatexformula_cmdl, links, xlinks
5 * new profiles: pandoc, teams-for-linux, OpenArena, gnome-sound-recorder 6 * new profiles: pandoc, teams-for-linux, OpenArena, gnome-sound-recorder
6 * new profiles: godot, tcpdump, tshark, newsbeuter, keepassxc-cli 7 * new profiles: godot, tcpdump, tshark, newsbeuter, keepassxc-cli
7 * new profiles: keepassxc-proxy, rhythmbox-client, jerry, zeal 8 * new profiles: keepassxc-proxy, rhythmbox-client, jerry, zeal, mpg123
8 -- netblue30 <netblue30@yahoo.com> Sat, 1 Jun 2019 08:00:00 -0500 9 -- netblue30 <netblue30@yahoo.com> Sat, 1 Jun 2019 08:00:00 -0500
9 10
10firejail (0.9.60) baseline; urgency=low 11firejail (0.9.60) baseline; urgency=low
diff --git a/contrib/fix_private-bin.py b/contrib/fix_private-bin.py
index 65bfba52d..c6c6f908d 100755
--- a/contrib/fix_private-bin.py
+++ b/contrib/fix_private-bin.py
@@ -61,7 +61,6 @@ def fixSymlinkedBins(files, replMap):
61 if shouldUpdate: 61 if shouldUpdate:
62 with open(filename, "w") as file: 62 with open(filename, "w") as file:
63 file.writelines(lines) 63 file.writelines(lines)
64 pass
65 64
66 65
67def createSetOfBinaries(files): 66def createSetOfBinaries(files):
@@ -70,7 +69,6 @@ def createSetOfBinaries(files):
70 """ 69 """
71 s = set() 70 s = set()
72 for filename in files: 71 for filename in files:
73 lines = None
74 with open(filename, "r") as file: 72 with open(filename, "r") as file:
75 for line in file: 73 for line in file:
76 if privRx.search(line): 74 if privRx.search(line):
diff --git a/contrib/fjclip.py b/contrib/fjclip.py
index 3d0c56dc6..30323b1d5 100755
--- a/contrib/fjclip.py
+++ b/contrib/fjclip.py
@@ -1,6 +1,5 @@
1#!/usr/bin/env python 1#!/usr/bin/env python
2 2
3import re
4import sys 3import sys
5import subprocess 4import subprocess
6import fjdisplay 5import fjdisplay
diff --git a/contrib/gdb-firejail.sh b/contrib/gdb-firejail.sh
new file mode 100755
index 000000000..3ee3fffb3
--- /dev/null
+++ b/contrib/gdb-firejail.sh
@@ -0,0 +1,21 @@
1#!/bin/bash
2set -x
3
4# gdb setuid helper script.
5# This script forks a background process as the current user which will
6# immediately send itself a `STOP` signal. Then gdb running as root will
7# attach to that process, which will send it the `CONT` signal to continue
8# execution. Then the backgrounded process will exec the program with the
9# given arguments. This will allow the root gdb to trace the unprivileged
10# setuid firejail process from the absolute beginning.
11
12if [ -z "${1##*/firejail}" ]; then
13 FIREJAIL=$1
14else
15 # First argument is not named firejail, then add default unless environment
16 # variable already set.
17 set -- ${FIREJAIL:=$(which firejail)} "$@"
18fi
19
20bash -c "kill -STOP \$\$; exec \"\$0\" \"\$@\"" "$@" &
21sudo gdb -e "$FIREJAIL" -p "$!" \ No newline at end of file
diff --git a/etc/celluloid.profile b/etc/celluloid.profile
index 89543d6cc..6b7db6b44 100644
--- a/etc/celluloid.profile
+++ b/etc/celluloid.profile
@@ -6,8 +6,9 @@ include celluloid.local
6# Persistent global definitions 6# Persistent global definitions
7include globals.local 7include globals.local
8 8
9noblacklist ${HOME}/.config/gnome-mpv
10noblacklist ${HOME}/.config/celluloid 9noblacklist ${HOME}/.config/celluloid
10noblacklist ${HOME}/.config/gnome-mpv
11noblacklist ${HOME}/.config/youtube-dl
11noblacklist ${MUSIC} 12noblacklist ${MUSIC}
12noblacklist ${VIDEOS} 13noblacklist ${VIDEOS}
13 14
diff --git a/etc/conplay.profile b/etc/conplay.profile
new file mode 100644
index 000000000..101ce2f17
--- /dev/null
+++ b/etc/conplay.profile
@@ -0,0 +1,14 @@
1# Firejail profile for conplay
2# Persistent local customizations
3include conplay.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8## system-wide profile
9#+ overrides
10# Allow perl (blacklisted by disable-interpreters.inc)
11include allow-perl.inc
12
13# Redirect
14include mpg123.profile
diff --git a/etc/disable-common.inc b/etc/disable-common.inc
index ae82d72b5..7ca5a6b89 100644
--- a/etc/disable-common.inc
+++ b/etc/disable-common.inc
@@ -134,6 +134,8 @@ blacklist ${RUNUSER}/kdesud_*
134# gnome 134# gnome
135# contains extensions, last used times of applications, and notifications 135# contains extensions, last used times of applications, and notifications
136blacklist ${HOME}/.local/share/gnome-shell 136blacklist ${HOME}/.local/share/gnome-shell
137# no direct modification of dconf database
138read-only ${HOME}/.config/dconf
137 139
138# systemd 140# systemd
139blacklist ${HOME}/.config/systemd 141blacklist ${HOME}/.config/systemd
diff --git a/etc/disable-programs.inc b/etc/disable-programs.inc
index 3e6706101..c061e94a2 100644
--- a/etc/disable-programs.inc
+++ b/etc/disable-programs.inc
@@ -319,6 +319,7 @@ blacklist ${HOME}/.config/xviewer
319blacklist ${HOME}/.config/yandex-browser 319blacklist ${HOME}/.config/yandex-browser
320blacklist ${HOME}/.config/yandex-browser-beta 320blacklist ${HOME}/.config/yandex-browser-beta
321blacklist ${HOME}/.config/yelp 321blacklist ${HOME}/.config/yelp
322blacklist ${HOME}/.config/youtube-dl
322blacklist ${HOME}/.config/zathura 323blacklist ${HOME}/.config/zathura
323blacklist ${HOME}/.config/zoomus.conf 324blacklist ${HOME}/.config/zoomus.conf
324blacklist ${HOME}/.conkeror.mozdev.org 325blacklist ${HOME}/.conkeror.mozdev.org
diff --git a/etc/firejail.config b/etc/firejail.config
index dbe4fb1ea..4c0cb2a41 100644
--- a/etc/firejail.config
+++ b/etc/firejail.config
@@ -2,6 +2,9 @@
2# keyword-argument pairs, one per line. Most features are enabled by default. 2# keyword-argument pairs, one per line. Most features are enabled by default.
3# Use 'yes' or 'no' as configuration values. 3# Use 'yes' or 'no' as configuration values.
4 4
5# Allow symbolic links in path of user home directories, default disabled.
6# homedir-symlink no
7
5# Enable AppArmor functionality, default enabled. 8# Enable AppArmor functionality, default enabled.
6# apparmor yes 9# apparmor yes
7 10
@@ -35,6 +38,11 @@
35# cannot be overridden by --noblacklist or --ignore. 38# cannot be overridden by --noblacklist or --ignore.
36# disable-mnt no 39# disable-mnt no
37 40
41# Set the limit for file copy in several --private-* options. The size is set
42# in megabytes. By default we allow up to 500MB.
43# Note: the files are copied in RAM.
44# file-copy-limit 500
45
38# Enable or disable file transfer support, default enabled. 46# Enable or disable file transfer support, default enabled.
39# file-transfer yes 47# file-transfer yes
40 48
diff --git a/etc/gajim.profile b/etc/gajim.profile
index 74ab9f8b7..85d9b9bd9 100644
--- a/etc/gajim.profile
+++ b/etc/gajim.profile
@@ -20,6 +20,7 @@ include disable-exec.inc
20include disable-interpreters.inc 20include disable-interpreters.inc
21include disable-passwdmgr.inc 21include disable-passwdmgr.inc
22include disable-programs.inc 22include disable-programs.inc
23# Comment the following line if you need to whitelist other folders than ~/Downloads
23include disable-xdg.inc 24include disable-xdg.inc
24 25
25mkdir ${HOME}/.cache/gajim 26mkdir ${HOME}/.cache/gajim
diff --git a/etc/galculator.profile b/etc/galculator.profile
index 3dda48192..f757aed69 100644
--- a/etc/galculator.profile
+++ b/etc/galculator.profile
@@ -47,4 +47,4 @@ private-etc alternatives,fonts
47private-lib 47private-lib
48private-tmp 48private-tmp
49 49
50memory-deny-write-execute 50#memory-deny-write-execute - breaks on Arch (see issue #1803)
diff --git a/etc/less.profile b/etc/less.profile
index e6366ad28..0f31d344b 100644
--- a/etc/less.profile
+++ b/etc/less.profile
@@ -8,13 +8,13 @@ include less.local
8include globals.local 8include globals.local
9 9
10noblacklist ${HOME}/.lesshst 10noblacklist ${HOME}/.lesshst
11read-only ${HOME}
12read-write ${HOME}/.lesshst
11 13
12include disable-common.inc
13include disable-devel.inc 14include disable-devel.inc
14include disable-exec.inc 15include disable-exec.inc
15include disable-interpreters.inc 16include disable-interpreters.inc
16include disable-passwdmgr.inc 17include disable-passwdmgr.inc
17include disable-programs.inc
18 18
19apparmor 19apparmor
20caps.drop all 20caps.drop all
diff --git a/etc/mpg123-alsa.profile b/etc/mpg123-alsa.profile
new file mode 100644
index 000000000..378435af1
--- /dev/null
+++ b/etc/mpg123-alsa.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-alsa
2# Persistent local customizations
3include mpg123-alsa.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123-id3dump.profile b/etc/mpg123-id3dump.profile
new file mode 100644
index 000000000..370a57b3c
--- /dev/null
+++ b/etc/mpg123-id3dump.profile
@@ -0,0 +1,12 @@
1# Firejail profile for mpg123-id3dump
2# Persistent local customizations
3include mpg123-id3dump.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8machine-id
9nosound
10
11# Redirect
12include mpg123.profile
diff --git a/etc/mpg123-jack.profile b/etc/mpg123-jack.profile
new file mode 100644
index 000000000..e36a2e5b3
--- /dev/null
+++ b/etc/mpg123-jack.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-jack
2# Persistent local customizations
3include mpg123-jack.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123-nas.profile b/etc/mpg123-nas.profile
new file mode 100644
index 000000000..cdbf0b1d2
--- /dev/null
+++ b/etc/mpg123-nas.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-nas
2# Persistent local customizations
3include mpg123-nas.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123-openal.profile b/etc/mpg123-openal.profile
new file mode 100644
index 000000000..e5585feaa
--- /dev/null
+++ b/etc/mpg123-openal.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-openal
2# Persistent local customizations
3include mpg123-openal.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123-oss.profile b/etc/mpg123-oss.profile
new file mode 100644
index 000000000..dcb92ecd6
--- /dev/null
+++ b/etc/mpg123-oss.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-oss
2# Persistent local customizations
3include mpg123-oss.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123-portaudio.profile b/etc/mpg123-portaudio.profile
new file mode 100644
index 000000000..319843504
--- /dev/null
+++ b/etc/mpg123-portaudio.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-portaudio
2# Persistent local customizations
3include mpg123-portaudio.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123-pulse.profile b/etc/mpg123-pulse.profile
new file mode 100644
index 000000000..31063a96b
--- /dev/null
+++ b/etc/mpg123-pulse.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-pulse
2# Persistent local customizations
3include mpg123-pulse.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123-strip.profile b/etc/mpg123-strip.profile
new file mode 100644
index 000000000..62de57c22
--- /dev/null
+++ b/etc/mpg123-strip.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123-strip
2# Persistent local customizations
3include mpg123-strip.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123.bin.profile b/etc/mpg123.bin.profile
new file mode 100644
index 000000000..0a01d0829
--- /dev/null
+++ b/etc/mpg123.bin.profile
@@ -0,0 +1,9 @@
1# Firejail profile for mpg123.bin
2# Persistent local customizations
3include mpg123.bin.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/mpg123.profile b/etc/mpg123.profile
new file mode 100644
index 000000000..8a8907c39
--- /dev/null
+++ b/etc/mpg123.profile
@@ -0,0 +1,38 @@
1# Firejail profile for mpg123
2# Description: MPEG audio player/decoder
3# This file is overwritten after every install/update
4# Persistent local customizations
5include mpg123.local
6# Persistent global definitions
7include globals.local
8
9noblacklist ${MUSIC}
10noblacklist ${VIDEOS}
11
12include disable-common.inc
13include disable-devel.inc
14include disable-exec.inc
15include disable-interpreters.inc
16include disable-passwdmgr.inc
17include disable-programs.inc
18include disable-xdg.inc
19
20include whitelist-var-common.inc
21
22apparmor
23caps.drop all
24netfilter
25nodbus
26nogroups
27nonewprivs
28noroot
29nou2f
30protocol unix,inet,inet6,netlink
31seccomp
32shell none
33
34#private-bin mpg123*
35private-dev
36private-tmp
37
38memory-deny-write-execute
diff --git a/etc/mpsyt.profile b/etc/mpsyt.profile
index f0309da9a..878a5f654 100644
--- a/etc/mpsyt.profile
+++ b/etc/mpsyt.profile
@@ -8,6 +8,7 @@ include globals.local
8 8
9noblacklist ${HOME}/.config/mps-youtube 9noblacklist ${HOME}/.config/mps-youtube
10noblacklist ${HOME}/.config/mpv 10noblacklist ${HOME}/.config/mpv
11noblacklist ${HOME}/.config/youtube-dl
11noblacklist ${HOME}/.mplayer 12noblacklist ${HOME}/.mplayer
12noblacklist ${HOME}/.netrc 13noblacklist ${HOME}/.netrc
13noblacklist ${HOME}/mps 14noblacklist ${HOME}/mps
@@ -29,10 +30,12 @@ include disable-xdg.inc
29 30
30mkdir ${HOME}/.config/mps-youtube 31mkdir ${HOME}/.config/mps-youtube
31mkdir ${HOME}/.config/mpv 32mkdir ${HOME}/.config/mpv
33mkdir ${HOME}/.config/youtube-dl
32mkdir ${HOME}/.mplayer 34mkdir ${HOME}/.mplayer
33mkdir ${HOME}/mps 35mkdir ${HOME}/mps
34whitelist ${HOME}/.config/mps-youtube 36whitelist ${HOME}/.config/mps-youtube
35whitelist ${HOME}/.config/mpv 37whitelist ${HOME}/.config/mpv
38whitelist ${HOME}/.config/youtube-dl
36whitelist ${HOME}/.mplayer 39whitelist ${HOME}/.mplayer
37whitelist ${HOME}/.netrc 40whitelist ${HOME}/.netrc
38whitelist ${HOME}/mps 41whitelist ${HOME}/mps
diff --git a/etc/mpv.profile b/etc/mpv.profile
index 07a6ba42b..d8163d20a 100644
--- a/etc/mpv.profile
+++ b/etc/mpv.profile
@@ -8,6 +8,7 @@ include mpv.local
8include globals.local 8include globals.local
9 9
10noblacklist ${HOME}/.config/mpv 10noblacklist ${HOME}/.config/mpv
11noblacklist ${HOME}/.config/youtube-dl
11noblacklist ${HOME}/.netrc 12noblacklist ${HOME}/.netrc
12 13
13# Allow python (blacklisted by disable-interpreters.inc) 14# Allow python (blacklisted by disable-interpreters.inc)
@@ -42,5 +43,6 @@ shell none
42tracelog 43tracelog
43 44
44private-bin env,mpv,python*,youtube-dl 45private-bin env,mpv,python*,youtube-dl
45private-cache 46# Causes slow OSD, see #2838
47#private-cache
46private-dev 48private-dev
diff --git a/etc/mumble.profile b/etc/mumble.profile
index 2d8607e53..94ccbad0c 100644
--- a/etc/mumble.profile
+++ b/etc/mumble.profile
@@ -43,4 +43,4 @@ disable-mnt
43private-bin mumble 43private-bin mumble
44private-tmp 44private-tmp
45 45
46memory-deny-write-execute 46#memory-deny-write-execute - breaks on Arch (see issue #1803)
diff --git a/etc/obs.profile b/etc/obs.profile
index 038242cae..4277bdab3 100644
--- a/etc/obs.profile
+++ b/etc/obs.profile
@@ -36,7 +36,7 @@ seccomp
36shell none 36shell none
37tracelog 37tracelog
38 38
39private-bin obs,python* 39private-bin bash,obs,obs-ffmpeg-mux,python*,sh
40private-cache 40private-cache
41private-dev 41private-dev
42private-tmp 42private-tmp
diff --git a/etc/out123.profile b/etc/out123.profile
new file mode 100644
index 000000000..4754c05ba
--- /dev/null
+++ b/etc/out123.profile
@@ -0,0 +1,9 @@
1# Firejail profile for out123
2# Persistent local customizations
3include out123.local
4# Persistent global definitions
5# added by included profile
6#include globals.local
7
8# Redirect
9include mpg123.profile
diff --git a/etc/pavucontrol.profile b/etc/pavucontrol.profile
index 621fef49f..e74394b22 100644
--- a/etc/pavucontrol.profile
+++ b/etc/pavucontrol.profile
@@ -45,4 +45,4 @@ private-etc alternatives,asound.conf,avahi,fonts,machine-id,pulse
45private-lib 45private-lib
46private-tmp 46private-tmp
47 47
48memory-deny-write-execute 48#memory-deny-write-execute - breaks on Arch (see issue #1803)
diff --git a/etc/qpdfview.profile b/etc/qpdfview.profile
index 6cb3fe4cd..abbd76aff 100644
--- a/etc/qpdfview.profile
+++ b/etc/qpdfview.profile
@@ -22,6 +22,7 @@ include whitelist-var-common.inc
22 22
23caps.drop all 23caps.drop all
24machine-id 24machine-id
25nodbus
25nodvd 26nodvd
26nogroups 27nogroups
27nonewprivs 28nonewprivs
@@ -38,5 +39,3 @@ tracelog
38private-bin qpdfview 39private-bin qpdfview
39private-dev 40private-dev
40private-tmp 41private-tmp
41
42memory-deny-write-execute
diff --git a/etc/riot-desktop.profile b/etc/riot-desktop.profile
index e91d25196..e6af4c2cb 100644
--- a/etc/riot-desktop.profile
+++ b/etc/riot-desktop.profile
@@ -7,5 +7,8 @@ include riot-desktop.local
7# added by included profile 7# added by included profile
8#include globals.local 8#include globals.local
9 9
10ignore seccomp
11seccomp.drop @clock,@cpu-emulation,@debug,@module,@obsolete,@raw-io,@reboot,@resources,@swap,acct,add_key,bpf,fanotify_init,io_cancel,io_destroy,io_getevents,io_setup,io_submit,ioprio_set,kcmp,keyctl,mincore,mount,name_to_handle_at,nfsservctl,ni_syscall,open_by_handle_at,pivot_root,remap_file_pages,request_key,setdomainname,sethostname,syslog,umount,umount2,userfaultfd,vhangup,vmsplice
12
10# Redirect 13# Redirect
11include riot-web.profile 14include riot-web.profile
diff --git a/etc/smplayer.profile b/etc/smplayer.profile
index f83caee8a..c7324e6ca 100644
--- a/etc/smplayer.profile
+++ b/etc/smplayer.profile
@@ -7,6 +7,7 @@ include smplayer.local
7include globals.local 7include globals.local
8 8
9noblacklist ${HOME}/.config/smplayer 9noblacklist ${HOME}/.config/smplayer
10noblacklist ${HOME}/.config/youtube-dl
10noblacklist ${HOME}/.mplayer 11noblacklist ${HOME}/.mplayer
11 12
12# Allow python (blacklisted by disable-interpreters.inc) 13# Allow python (blacklisted by disable-interpreters.inc)
diff --git a/etc/wire-desktop.profile b/etc/wire-desktop.profile
index f41453bf3..490255fa6 100644
--- a/etc/wire-desktop.profile
+++ b/etc/wire-desktop.profile
@@ -34,7 +34,7 @@ shell none
34# it is not in PATH. To use Wire with firejail, run "firejail /opt/wire-desktop/wire-desktop" 34# it is not in PATH. To use Wire with firejail, run "firejail /opt/wire-desktop/wire-desktop"
35 35
36disable-mnt 36disable-mnt
37private-bin bash,electron,env,sh,wire-desktop 37private-bin bash,electron,electron4,env,sh,wire-desktop
38private-dev 38private-dev
39private-etc alternatives,ca-certificates,crypto-policies,fonts,machine-id,pki,resolv.conf,ssl 39private-etc alternatives,ca-certificates,crypto-policies,fonts,machine-id,pki,resolv.conf,ssl
40private-tmp 40private-tmp
diff --git a/etc/youtube-dl.profile b/etc/youtube-dl.profile
index 28b5f2376..6fc519bee 100644
--- a/etc/youtube-dl.profile
+++ b/etc/youtube-dl.profile
@@ -7,9 +7,10 @@ include youtube-dl.local
7# Persistent global definitions 7# Persistent global definitions
8include globals.local 8include globals.local
9 9
10# breaks when installed via pip 10# breaks when installed under ${HOME} via `pip install --user` (see #2833)
11ignore noexec ${HOME} 11ignore noexec ${HOME}
12 12
13noblacklist ${HOME}/.config/youtube-dl
13noblacklist ${HOME}/.netrc 14noblacklist ${HOME}/.netrc
14noblacklist ${MUSIC} 15noblacklist ${MUSIC}
15noblacklist ${VIDEOS} 16noblacklist ${VIDEOS}
@@ -48,7 +49,6 @@ seccomp
48shell none 49shell none
49tracelog 50tracelog
50 51
51disable-mnt
52private-bin env,ffmpeg,python*,youtube-dl 52private-bin env,ffmpeg,python*,youtube-dl
53private-cache 53private-cache
54private-dev 54private-dev
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
index 9fca2a39b..3f507a361 100644
--- a/src/fcopy/main.c
+++ b/src/fcopy/main.c
@@ -25,9 +25,11 @@
25#include <pwd.h> 25#include <pwd.h>
26 26
27int arg_quiet = 0; 27int arg_quiet = 0;
28int arg_debug = 0;
28static int arg_follow_link = 0; 29static int arg_follow_link = 0;
29 30
30#define COPY_LIMIT (500 * 1024 *1024) 31static int copy_limit = 500 * 1024 *1024; // 500 MB
32#define COPY_LIMIT (
31static int size_limit_reached = 0; 33static int size_limit_reached = 0;
32static unsigned file_cnt = 0; 34static unsigned file_cnt = 0;
33static unsigned size_cnt = 0; 35static unsigned size_cnt = 0;
@@ -184,8 +186,8 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str
184 mode_t mode = s.st_mode; 186 mode_t mode = s.st_mode;
185 187
186 // recalculate size 188 // recalculate size
187 if ((s.st_size + size_cnt) > COPY_LIMIT) { 189 if ((s.st_size + size_cnt) > copy_limit) {
188 fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (COPY_LIMIT / 1024) / 1024); 190 fprintf(stderr, "Error fcopy: size limit of %dMB reached\n", (copy_limit / 1024) / 1024);
189 size_limit_reached = 1; 191 size_limit_reached = 1;
190 free(outfname); 192 free(outfname);
191 return 0; 193 return 0;
@@ -330,6 +332,9 @@ int main(int argc, char **argv) {
330 char *quiet = getenv("FIREJAIL_QUIET"); 332 char *quiet = getenv("FIREJAIL_QUIET");
331 if (quiet && strcmp(quiet, "yes") == 0) 333 if (quiet && strcmp(quiet, "yes") == 0)
332 arg_quiet = 1; 334 arg_quiet = 1;
335 char *debug = getenv("FIREJAIL_DEBUG");
336 if (debug && strcmp(debug, "yes") == 0)
337 arg_debug = 1;
333 338
334 char *src; 339 char *src;
335 char *dest; 340 char *dest;
@@ -384,6 +389,14 @@ int main(int argc, char **argv) {
384 exit(1); 389 exit(1);
385 } 390 }
386 391
392 // extract copy limit size from env variable, if any
393 char *cl = getenv("FIREJAIL_FILE_COPY_LIMIT");
394 if (cl) {
395 copy_limit = atoi(cl) * 1024 * 1024;
396 if (arg_debug)
397 printf("file copy limit %d bytes\n", copy_limit);
398 }
399
387 // copy files 400 // copy files
388 if ((arg_follow_link ? stat : lstat)(src, &s) == -1) { 401 if ((arg_follow_link ? stat : lstat)(src, &s) == -1) {
389 fprintf(stderr, "Error fcopy: src %s: %s\n", src, strerror(errno)); 402 fprintf(stderr, "Error fcopy: src %s: %s\n", src, strerror(errno));
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index 04bf123ad..95ad95e95 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -119,6 +119,7 @@ code
119code-oss 119code-oss
120conkeror 120conkeror
121conky 121conky
122conplay
122corebird 123corebird
123crawl 124crawl
124crawl-tiles 125crawl-tiles
@@ -379,6 +380,17 @@ mp3splt
379mp3splt-gtk 380mp3splt-gtk
380mp3wrap 381mp3wrap
381mpDris2 382mpDris2
383mpg123
384mpg123.bin
385mpg123-alsa
386mpg123-id3dump
387mpg123-jack
388mpg123-nas
389mpg123-openal
390mpg123-oss
391mpg123-portaudio
392mpg123-pulse
393mpg123-strip
382mplayer 394mplayer
383mpsyt 395mpsyt
384mpv 396mpv
@@ -432,6 +444,7 @@ opera
432opera-beta 444opera-beta
433orage 445orage
434ostrichriders 446ostrichriders
447out123
435palemoon 448palemoon
436pandoc 449pandoc
437parole 450parole
diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c
index 7c60d9189..1da765d8f 100644
--- a/src/firejail/appimage.c
+++ b/src/firejail/appimage.c
@@ -126,16 +126,25 @@ void appimage_set(const char *appimage) {
126 printf("appimage mounted on %s\n", mntdir); 126 printf("appimage mounted on %s\n", mntdir);
127 EUID_USER(); 127 EUID_USER();
128 128
129 char* abspath = realpath(appimage, NULL);
130 if (abspath == NULL)
131 errExit("Failed to obtain absolute path");
132
129 // set environment 133 // set environment
130 if (setenv("APPIMAGE", appimage, 1) < 0) 134 if (setenv("APPIMAGE", abspath, 1) < 0)
131 errExit("setenv"); 135 errExit("setenv");
132 if (mntdir && setenv("APPDIR", mntdir, 1) < 0) 136 if (mntdir && setenv("APPDIR", mntdir, 1) < 0)
133 errExit("setenv"); 137 errExit("setenv");
138 if (size != 0 && setenv("ARGV0", appimage, 1) < 0)
139 errExit("setenv");
140 if (setenv("OWD", cfg.cwd, 1) < 0)
141 errExit("setenv");
134 142
135 // build new command line 143 // build new command line
136 if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1) 144 if (asprintf(&cfg.command_line, "%s/AppRun", mntdir) == -1)
137 errExit("asprintf"); 145 errExit("asprintf");
138 146
147 free(abspath);
139 free(mode); 148 free(mode);
140#ifdef HAVE_GCOV 149#ifdef HAVE_GCOV
141 __gcov_flush(); 150 __gcov_flush();
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c
index b11d795a9..84054fe76 100644
--- a/src/firejail/checkcfg.c
+++ b/src/firejail/checkcfg.c
@@ -50,6 +50,7 @@ int checkcfg(int val) {
50 cfg_val[CFG_DISABLE_MNT] = 0; 50 cfg_val[CFG_DISABLE_MNT] = 0;
51 cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES; 51 cfg_val[CFG_ARP_PROBES] = DEFAULT_ARP_PROBES;
52 cfg_val[CFG_XPRA_ATTACH] = 0; 52 cfg_val[CFG_XPRA_ATTACH] = 0;
53 cfg_val[CFG_HOMEDIR_SYMLINK] = 0;
53 54
54 // open configuration file 55 // open configuration file
55 const char *fname = SYSCONFDIR "/firejail.config"; 56 const char *fname = SYSCONFDIR "/firejail.config";
@@ -85,6 +86,7 @@ int checkcfg(int val) {
85 ptr = line_remove_spaces(buf); 86 ptr = line_remove_spaces(buf);
86 if (!ptr) 87 if (!ptr)
87 continue; 88 continue;
89 PARSE_YESNO(CFG_HOMEDIR_SYMLINK, "homedir-symlink")
88 PARSE_YESNO(CFG_FILE_TRANSFER, "file-transfer") 90 PARSE_YESNO(CFG_FILE_TRANSFER, "file-transfer")
89 PARSE_YESNO(CFG_DBUS, "dbus") 91 PARSE_YESNO(CFG_DBUS, "dbus")
90 PARSE_YESNO(CFG_JOIN, "join") 92 PARSE_YESNO(CFG_JOIN, "join")
@@ -207,6 +209,12 @@ int checkcfg(int val) {
207 goto errout; 209 goto errout;
208 cfg_val[CFG_ARP_PROBES] = arp_probes; 210 cfg_val[CFG_ARP_PROBES] = arp_probes;
209 } 211 }
212
213 // file copy limit
214 else if (strncmp(ptr, "file-copy-limit ", 16) == 0) {
215 if (setenv("FIREJAIL_FILE_COPY_LIMIT", ptr + 16, 1) == -1)
216 errExit("setenv");
217 }
210 else 218 else
211 goto errout; 219 goto errout;
212 220
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 630adc3d7..4bd70697e 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -720,6 +720,8 @@ enum {
720 CFG_PRIVATE_CACHE, 720 CFG_PRIVATE_CACHE,
721 CFG_CGROUP, 721 CFG_CGROUP,
722 CFG_NAME_CHANGE, 722 CFG_NAME_CHANGE,
723 CFG_HOMEDIR_SYMLINK,
724 // CFG_FILE_COPY_LIMIT - file copy limit handled using setenv/getenv
723 CFG_MAX // this should always be the last entry 725 CFG_MAX // this should always be the last entry
724}; 726};
725extern char *xephyr_screen; 727extern char *xephyr_screen;
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 9a15d825e..ce2ca5e2a 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -441,6 +441,8 @@ static int get_mount_flags(const char *path, unsigned long *flags) {
441// mount a writable tmpfs on directory 441// mount a writable tmpfs on directory
442void fs_tmpfs(const char *dir, unsigned check_owner) { 442void fs_tmpfs(const char *dir, unsigned check_owner) {
443 assert(dir); 443 assert(dir);
444 if (arg_debug)
445 printf("Mounting tmpfs on %s\n", dir);
444 // get a file descriptor for dir, fails if there is any symlink 446 // get a file descriptor for dir, fails if there is any symlink
445 int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 447 int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
446 if (fd == -1) 448 if (fd == -1)
@@ -449,12 +451,9 @@ void fs_tmpfs(const char *dir, unsigned check_owner) {
449 if (fstat(fd, &s) == -1) 451 if (fstat(fd, &s) == -1)
450 errExit("fstat"); 452 errExit("fstat");
451 if (check_owner && s.st_uid != getuid()) { 453 if (check_owner && s.st_uid != getuid()) {
452 fwarning("no tmpfs mounted on %s: not owned by the current user\n", dir); 454 fprintf(stderr, "Error: cannot mount tmpfs on %s: not owned by the current user\n", dir);
453 close(fd); 455 exit(1);
454 return;
455 } 456 }
456 if (arg_debug)
457 printf("Mounting tmpfs on %s\n", dir);
458 // preserve ownership, mode 457 // preserve ownership, mode
459 char *options; 458 char *options;
460 if (asprintf(&options, "mode=%o,uid=%u,gid=%u", s.st_mode & 07777, s.st_uid, s.st_gid) == -1) 459 if (asprintf(&options, "mode=%o,uid=%u,gid=%u", s.st_mode & 07777, s.st_uid, s.st_gid) == -1)
@@ -1127,11 +1126,36 @@ void fs_overlayfs(void) {
1127 1126
1128#ifdef HAVE_CHROOT 1127#ifdef HAVE_CHROOT
1129// exit if error 1128// exit if error
1129static void fs_check_chroot_subdir(const char *subdir, int parentfd, int check_writable) {
1130 assert(subdir);
1131 int fd = openat(parentfd, subdir, O_PATH|O_CLOEXEC);
1132 if (fd == -1) {
1133 if (errno == ENOENT)
1134 fprintf(stderr, "Error: cannot find /%s in chroot directory\n", subdir);
1135 else {
1136 perror("open");
1137 fprintf(stderr, "Error: cannot open /%s in chroot directory\n", subdir);
1138 }
1139 exit(1);
1140 }
1141 struct stat s;
1142 if (fstat(fd, &s) == -1)
1143 errExit("fstat");
1144 close(fd);
1145 if (!S_ISDIR(s.st_mode) || s.st_uid != 0) {
1146 fprintf(stderr, "Error: chroot /%s should be a directory owned by root\n", subdir);
1147 exit(1);
1148 }
1149 if (check_writable && ((S_IWGRP|S_IWOTH) & s.st_mode) != 0) {
1150 fprintf(stderr, "Error: only root user should be given write permission on chroot /%s\n", subdir);
1151 exit(1);
1152 }
1153}
1154
1155// exit if error
1130void fs_check_chroot_dir(const char *rootdir) { 1156void fs_check_chroot_dir(const char *rootdir) {
1131 EUID_ASSERT(); 1157 EUID_ASSERT();
1132 assert(rootdir); 1158 assert(rootdir);
1133 char *dir = EMPTY_STRING;
1134 struct stat s;
1135 1159
1136 char *overlay; 1160 char *overlay;
1137 if (asprintf(&overlay, "%s/.firejail", cfg.homedir) == -1) 1161 if (asprintf(&overlay, "%s/.firejail", cfg.homedir) == -1)
@@ -1150,6 +1174,7 @@ void fs_check_chroot_dir(const char *rootdir) {
1150 } 1174 }
1151 // rootdir has to be owned by root and is not allowed to be generally writable, 1175 // rootdir has to be owned by root and is not allowed to be generally writable,
1152 // this also excludes /tmp, /var/tmp and such 1176 // this also excludes /tmp, /var/tmp and such
1177 struct stat s;
1153 if (fstat(parentfd, &s) == -1) 1178 if (fstat(parentfd, &s) == -1)
1154 errExit("fstat"); 1179 errExit("fstat");
1155 if (s.st_uid != 0) { 1180 if (s.st_uid != 0) {
@@ -1161,64 +1186,12 @@ void fs_check_chroot_dir(const char *rootdir) {
1161 exit(1); 1186 exit(1);
1162 } 1187 }
1163 1188
1164 // check /dev 1189 // check subdirectories in rootdir
1165 dir = "dev"; 1190 fs_check_chroot_subdir("dev", parentfd, 0);
1166 int fd = openat(parentfd, dir, O_PATH|O_CLOEXEC); 1191 fs_check_chroot_subdir("etc", parentfd, 1);
1167 if (fd == -1) 1192 fs_check_chroot_subdir("proc", parentfd, 0);
1168 goto error1; 1193 fs_check_chroot_subdir("tmp", parentfd, 0);
1169 if (fstat(fd, &s) == -1) 1194 fs_check_chroot_subdir("var/tmp", parentfd, 0);
1170 errExit("fstat");
1171 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1172 goto error2;
1173 close(fd);
1174
1175 // check /var/tmp
1176 dir = "var/tmp";
1177 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1178 if (fd == -1)
1179 goto error1;
1180 if (fstat(fd, &s) == -1)
1181 errExit("fstat");
1182 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1183 goto error2;
1184 close(fd);
1185
1186 // check /proc
1187 dir = "proc";
1188 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1189 if (fd == -1)
1190 goto error1;
1191 if (fstat(fd, &s) == -1)
1192 errExit("fstat");
1193 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1194 goto error2;
1195 close(fd);
1196
1197 // check /tmp
1198 dir = "tmp";
1199 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1200 if (fd == -1)
1201 goto error1;
1202 if (fstat(fd, &s) == -1)
1203 errExit("fstat");
1204 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1205 goto error2;
1206 close(fd);
1207
1208 // check /etc
1209 dir = "etc";
1210 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1211 if (fd == -1)
1212 goto error1;
1213 if (fstat(fd, &s) == -1)
1214 errExit("fstat");
1215 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1216 goto error2;
1217 if (((S_IWGRP|S_IWOTH) & s.st_mode) != 0) {
1218 fprintf(stderr, "Error: only root user should be given write permission on chroot /etc\n");
1219 exit(1);
1220 }
1221 close(fd);
1222 1195
1223 // there should be no checking on <chrootdir>/etc/resolv.conf 1196 // there should be no checking on <chrootdir>/etc/resolv.conf
1224 // the file is replaced with the real /etc/resolv.conf anyway 1197 // the file is replaced with the real /etc/resolv.conf anyway
@@ -1249,32 +1222,10 @@ void fs_check_chroot_dir(const char *rootdir) {
1249#endif 1222#endif
1250 1223
1251 // check x11 socket directory 1224 // check x11 socket directory
1252 if (getenv("FIREJAIL_X11")) { 1225 if (getenv("FIREJAIL_X11"))
1253 dir = "tmp/.X11-unix"; 1226 fs_check_chroot_subdir("tmp/.X11-unix", parentfd, 0);
1254 fd = openat(parentfd, dir, O_PATH|O_CLOEXEC);
1255 if (fd == -1)
1256 goto error1;
1257 if (fstat(fd, &s) == -1)
1258 errExit("fstat");
1259 if (!S_ISDIR(s.st_mode) || s.st_uid != 0)
1260 goto error2;
1261 close(fd);
1262 }
1263 1227
1264 close(parentfd); 1228 close(parentfd);
1265 return;
1266
1267error1:
1268 if (errno == ENOENT)
1269 fprintf(stderr, "Error: cannot find /%s in chroot directory\n", dir);
1270 else {
1271 perror("open");
1272 fprintf(stderr, "Error: cannot open /%s in chroot directory\n", dir);
1273 }
1274 exit(1);
1275error2:
1276 fprintf(stderr, "Error: chroot /%s should be a directory owned by root\n", dir);
1277 exit(1);
1278} 1229}
1279 1230
1280// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf 1231// chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c
index bd036908a..d807f527d 100644
--- a/src/firejail/fs_dev.c
+++ b/src/firejail/fs_dev.c
@@ -137,8 +137,8 @@ static void deventry_mount(void) {
137} 137}
138 138
139static void create_char_dev(const char *path, mode_t mode, int major, int minor) { 139static void create_char_dev(const char *path, mode_t mode, int major, int minor) {
140 dev_t dev = makedev(major, minor); 140 dev_t device = makedev(major, minor);
141 if (mknod(path, S_IFCHR | mode, dev) == -1) 141 if (mknod(path, S_IFCHR | mode, device) == -1)
142 goto errexit; 142 goto errexit;
143 if (chmod(path, mode) < 0) 143 if (chmod(path, mode) < 0)
144 goto errexit; 144 goto errexit;
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 3f6d78db4..01a807883 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -239,13 +239,16 @@ void fs_private_homedir(void) {
239 // mount bind private_homedir on top of homedir 239 // mount bind private_homedir on top of homedir
240 if (arg_debug) 240 if (arg_debug)
241 printf("Mount-bind %s on top of %s\n", private_homedir, homedir); 241 printf("Mount-bind %s on top of %s\n", private_homedir, homedir);
242 // get a file descriptor for private_homedir, fails if there is any symlink 242 // get file descriptors for homedir and private_homedir, fails if there is any symlink
243 int fd = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 243 int src = safe_fd(private_homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
244 if (fd == -1) 244 if (src == -1)
245 errExit("safe_fd");
246 int dst = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
247 if (dst == -1)
245 errExit("safe_fd"); 248 errExit("safe_fd");
246 // check if new home directory is owned by the user 249 // check if new home directory is owned by the user
247 struct stat s; 250 struct stat s;
248 if (fstat(fd, &s) == -1) 251 if (fstat(src, &s) == -1)
249 errExit("fstat"); 252 errExit("fstat");
250 if (s.st_uid != getuid()) { 253 if (s.st_uid != getuid()) {
251 fprintf(stderr, "Error: private directory is not owned by the current user\n"); 254 fprintf(stderr, "Error: private directory is not owned by the current user\n");
@@ -253,17 +256,27 @@ void fs_private_homedir(void) {
253 } 256 }
254 if ((S_IRWXU & s.st_mode) != S_IRWXU) 257 if ((S_IRWXU & s.st_mode) != S_IRWXU)
255 fwarning("no full permissions on private directory\n"); 258 fwarning("no full permissions on private directory\n");
256 // mount via the link in /proc/self/fd 259 // mount via the links in /proc/self/fd
257 char *proc; 260 char *proc_src, *proc_dst;
258 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 261 if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1)
262 errExit("asprintf");
263 if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1)
259 errExit("asprintf"); 264 errExit("asprintf");
260 if (mount(proc, homedir, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0) 265 if (mount(proc_src, proc_dst, NULL, MS_NOSUID | MS_NODEV | MS_BIND | MS_REC, NULL) < 0)
261 errExit("mount bind"); 266 errExit("mount bind");
262 free(proc); 267 free(proc_src);
263 close(fd); 268 free(proc_dst);
264 269 close(src);
265 fs_logger3("mount-bind", private_homedir, cfg.homedir); 270 close(dst);
266 fs_logger2("whitelist", cfg.homedir); 271 // check /proc/self/mountinfo to confirm the mount is ok
272 MountData *mptr = get_last_mount();
273 size_t len = strlen(homedir);
274 if (strncmp(mptr->dir, homedir, len) != 0 ||
275 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/'))
276 errLogExit("invalid private mount");
277
278 fs_logger3("mount-bind", private_homedir, homedir);
279 fs_logger2("whitelist", homedir);
267// preserve mode and ownership 280// preserve mode and ownership
268// if (chown(homedir, s.st_uid, s.st_gid) == -1) 281// if (chown(homedir, s.st_uid, s.st_gid) == -1)
269// errExit("mount-bind chown"); 282// errExit("mount-bind chown");
@@ -310,13 +323,13 @@ void fs_private(void) {
310 int aflag = store_asoundrc(); 323 int aflag = store_asoundrc();
311 324
312 // mask /home 325 // mask /home
313 if (arg_debug)
314 printf("Mounting a new /home directory\n");
315 if (u == 0 && arg_allusers) // allow --allusers when starting the sandbox as root 326 if (u == 0 && arg_allusers) // allow --allusers when starting the sandbox as root
316 ; 327 ;
317 else { 328 else {
329 if (arg_debug)
330 printf("Mounting a new /home directory\n");
318 if (arg_allusers) 331 if (arg_allusers)
319 fwarning("--allusers disabled by --private or --whitelist\n"); 332 fwarning("allusers option disabled by private or whitelist option\n");
320 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME, "mode=755,gid=0") < 0) 333 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_STRICTATIME, "mode=755,gid=0") < 0)
321 errExit("mounting home directory"); 334 errExit("mounting home directory");
322 fs_logger("tmpfs /home"); 335 fs_logger("tmpfs /home");
@@ -330,19 +343,24 @@ void fs_private(void) {
330 fs_logger("tmpfs /root"); 343 fs_logger("tmpfs /root");
331 344
332 if (u != 0) { 345 if (u != 0) {
333 // create /home/user 346 if (strncmp(homedir, "/home/", 6) == 0) {
334 if (arg_debug) 347 // create /home/user
335 printf("Create a new user directory\n"); 348 if (arg_debug)
336 if (mkdir(homedir, S_IRWXU) == -1) { 349 printf("Create a new user directory\n");
337 if (mkpath_as_root(homedir) == -1) 350 if (mkdir(homedir, S_IRWXU) == -1) {
338 errExit("mkpath"); 351 if (mkpath_as_root(homedir) == -1)
339 if (mkdir(homedir, S_IRWXU) == -1 && errno != EEXIST) 352 errExit("mkpath");
340 errExit("mkdir"); 353 if (mkdir(homedir, S_IRWXU) == -1 && errno != EEXIST)
354 errExit("mkdir");
355 }
356 if (chown(homedir, u, g) < 0)
357 errExit("chown");
358 fs_logger2("mkdir", homedir);
359 fs_logger2("tmpfs", homedir);
341 } 360 }
342 if (chown(homedir, u, g) < 0) 361 else
343 errExit("chown"); 362 // user directory is outside /home, mask it as well
344 fs_logger2("mkdir", homedir); 363 fs_tmpfs(homedir, 1);
345 fs_logger2("tmpfs", homedir);
346 } 364 }
347 365
348 skel(homedir, u, g); 366 skel(homedir, u, g);
@@ -464,14 +482,14 @@ static void duplicate(char *name) {
464 } 482 }
465 else if (S_ISDIR(s.st_mode)) { 483 else if (S_ISDIR(s.st_mode)) {
466 // create the directory in RUN_HOME_DIR 484 // create the directory in RUN_HOME_DIR
467 char *name; 485 char *path;
468 char *ptr = strrchr(fname, '/'); 486 char *ptr = strrchr(fname, '/');
469 ptr++; 487 ptr++;
470 if (asprintf(&name, "%s/%s", RUN_HOME_DIR, ptr) == -1) 488 if (asprintf(&path, "%s/%s", RUN_HOME_DIR, ptr) == -1)
471 errExit("asprintf"); 489 errExit("asprintf");
472 mkdir_attr(name, 0755, getuid(), getgid()); 490 mkdir_attr(path, 0755, getuid(), getgid());
473 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, name); 491 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, path);
474 free(name); 492 free(path);
475 } 493 }
476 else 494 else
477 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR); 495 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR);
@@ -528,8 +546,20 @@ void fs_private_home_list(void) {
528 if (arg_debug) 546 if (arg_debug)
529 printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); 547 printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir);
530 548
531 if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) 549 int fd = safe_fd(homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
550 if (fd == -1)
551 errExit("safe_fd");
552 char *proc;
553 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
554 errExit("asprintf");
555 if (mount(RUN_HOME_DIR, proc, NULL, MS_BIND|MS_REC, NULL) < 0)
532 errExit("mount bind"); 556 errExit("mount bind");
557 free(proc);
558 close(fd);
559 // check /proc/self/mountinfo to confirm the mount is ok
560 MountData *mptr = get_last_mount();
561 if (strcmp(mptr->dir, homedir) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
562 errLogExit("invalid private-home mount");
533 fs_logger2("tmpfs", homedir); 563 fs_logger2("tmpfs", homedir);
534 564
535 if (uid != 0) { 565 if (uid != 0) {
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index bce44b9e5..a950d1124 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -237,11 +237,6 @@ static void whitelist_path(ProfileEntry *entry) {
237 return; 237 return;
238 } 238 }
239 239
240#ifdef TEST_MOUNTINFO
241 printf("TEST_MOUNTINFO\n");
242 path = "/etc/.";
243#endif
244
245 // create path of the mount target if necessary 240 // create path of the mount target if necessary
246 int fd2 = mkpath(path, 0755); 241 int fd2 = mkpath(path, 0755);
247 if (fd2 == -1) { 242 if (fd2 == -1) {
@@ -305,7 +300,10 @@ static void whitelist_path(ProfileEntry *entry) {
305 300
306 // check the last mount operation 301 // check the last mount operation
307 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found 302 MountData *mptr = get_last_mount(); // will do exit(1) if the mount cannot be found
308 303#ifdef TEST_MOUNTINFO
304 printf("TEST_MOUNTINFO\n");
305 mptr->dir = "foo";
306#endif
309 // confirm the file was mounted on the right target 307 // confirm the file was mounted on the right target
310 // strcmp does not work here, because mptr->dir can be a child mount 308 // strcmp does not work here, because mptr->dir can be a child mount
311 size_t path_len = strlen(path); 309 size_t path_len = strlen(path);
@@ -712,8 +710,16 @@ void fs_whitelist(void) {
712 if (stat(cfg.homedir, &s) == 0) { 710 if (stat(cfg.homedir, &s) == 0) {
713 // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR 711 // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR
714 mkdir_attr(RUN_WHITELIST_HOME_USER_DIR, 0755, getuid(), getgid()); 712 mkdir_attr(RUN_WHITELIST_HOME_USER_DIR, 0755, getuid(), getgid());
715 if (mount(cfg.homedir, RUN_WHITELIST_HOME_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) 713 int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
714 if (fd == -1)
715 errExit("safe_fd");
716 char *proc;
717 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
718 errExit("asprintf");
719 if (mount(proc, RUN_WHITELIST_HOME_USER_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
716 errExit("mount bind"); 720 errExit("mount bind");
721 free(proc);
722 close(fd);
717 723
718 // mount a tmpfs and initialize /home/user, overrides --allusers 724 // mount a tmpfs and initialize /home/user, overrides --allusers
719 fs_private(); 725 fs_private();
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 34c6f4044..d00147c74 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -26,7 +26,6 @@
26#include <sys/mount.h> 26#include <sys/mount.h>
27#include <sys/wait.h> 27#include <sys/wait.h>
28#include <sys/stat.h> 28#include <sys/stat.h>
29#include <fcntl.h>
30#include <dirent.h> 29#include <dirent.h>
31#include <pwd.h> 30#include <pwd.h>
32#include <errno.h> 31#include <errno.h>
@@ -38,6 +37,20 @@
38#include <net/if.h> 37#include <net/if.h>
39#include <sys/utsname.h> 38#include <sys/utsname.h>
40 39
40#include <fcntl.h>
41#ifndef O_PATH
42#define O_PATH 010000000
43#endif
44
45#ifdef __ia64__
46/* clone(2) has a different interface on ia64, as it needs to know
47 the size of the stack */
48int __clone2(int (*fn)(void *),
49 void *child_stack_base, size_t stack_size,
50 int flags, void *arg, ...
51 /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );
52#endif
53
41uid_t firejail_uid = 0; 54uid_t firejail_uid = 0;
42gid_t firejail_gid = 0; 55gid_t firejail_gid = 0;
43 56
@@ -233,6 +246,41 @@ static pid_t require_pid(const char *name) {
233 return pid; 246 return pid;
234} 247}
235 248
249// return 1 if there is a link somewhere in path of directory
250static int has_link(const char *dir) {
251 assert(dir);
252 int fd = safe_fd(dir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
253 if (fd == -1) {
254 if (errno == ENOTDIR && is_dir(dir))
255 return 1;
256 }
257 else
258 close(fd);
259 return 0;
260}
261
262static void build_cfg_homedir(const char *dir) {
263 EUID_ASSERT();
264 assert(dir);
265 if (dir[0] != '/') {
266 fprintf(stderr, "Error: invalid user directory \"%s\"\n", dir);
267 exit(1);
268 }
269 // symlinks are rejected in many places, provide a solution for home directories
270 if (checkcfg(CFG_HOMEDIR_SYMLINK)) {
271 cfg.homedir = realpath(dir, NULL);
272 if (cfg.homedir)
273 return;
274 }
275 else if (has_link(dir)) {
276 fprintf(stderr, "Error: path of user directory contains a symbolic link. "
277 "Please provide resolved path in password database (/etc/passwd) "
278 "or enable symbolic link resolution in Firejail configuration file.\n");
279 exit(1);
280 }
281 cfg.homedir = clean_pathname(dir);
282}
283
236// init configuration 284// init configuration
237static void init_cfg(int argc, char **argv) { 285static void init_cfg(int argc, char **argv) {
238 EUID_ASSERT(); 286 EUID_ASSERT();
@@ -256,15 +304,12 @@ static void init_cfg(int argc, char **argv) {
256 errExit("strdup"); 304 errExit("strdup");
257 305
258 // build home directory name 306 // build home directory name
259 cfg.homedir = NULL; 307 if (pw->pw_dir == NULL) {
260 if (pw->pw_dir != NULL) {
261 cfg.homedir = clean_pathname(pw->pw_dir);
262 assert(cfg.homedir);
263 }
264 else {
265 fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username); 308 fprintf(stderr, "Error: user %s doesn't have a user directory assigned\n", cfg.username);
266 exit(1); 309 exit(1);
267 } 310 }
311 build_cfg_homedir(pw->pw_dir);
312 assert(cfg.homedir);
268 313
269 cfg.cwd = getcwd(NULL, 0); 314 cfg.cwd = getcwd(NULL, 0);
270 if (!cfg.cwd && errno != ENOENT) 315 if (!cfg.cwd && errno != ENOENT)
@@ -917,7 +962,6 @@ int main(int argc, char **argv) {
917 962
918 // check if the user is allowed to use firejail 963 // check if the user is allowed to use firejail
919 init_cfg(argc, argv); 964 init_cfg(argc, argv);
920 assert(cfg.homedir);
921 965
922 // get starting timestamp, process --quiet 966 // get starting timestamp, process --quiet
923 start_timestamp = getticks(); 967 start_timestamp = getticks();
@@ -2541,10 +2585,18 @@ int main(int argc, char **argv) {
2541 2585
2542 EUID_ASSERT(); 2586 EUID_ASSERT();
2543 EUID_ROOT(); 2587 EUID_ROOT();
2588#ifdef __ia64__
2589 child = __clone2(sandbox,
2590 child_stack,
2591 STACK_SIZE,
2592 flags,
2593 NULL);
2594#else
2544 child = clone(sandbox, 2595 child = clone(sandbox,
2545 child_stack + STACK_SIZE, 2596 child_stack + STACK_SIZE,
2546 flags, 2597 flags,
2547 NULL); 2598 NULL);
2599#endif
2548 if (child == -1) 2600 if (child == -1)
2549 errExit("clone"); 2601 errExit("clone");
2550 EUID_USER(); 2602 EUID_USER();
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c
index 5c5ace90b..ee2e497cb 100644
--- a/src/firejail/restrict_users.c
+++ b/src/firejail/restrict_users.c
@@ -25,9 +25,13 @@
25#include <fnmatch.h> 25#include <fnmatch.h>
26#include <glob.h> 26#include <glob.h>
27#include <dirent.h> 27#include <dirent.h>
28#include <fcntl.h>
29#include <errno.h> 28#include <errno.h>
30 29
30#include <fcntl.h>
31#ifndef O_PATH
32# define O_PATH 010000000
33#endif
34
31#define MAXBUF 1024 35#define MAXBUF 1024
32 36
33// linked list of users 37// linked list of users
@@ -79,8 +83,16 @@ static void sanitize_home(void) {
79 errExit("mkdir"); 83 errExit("mkdir");
80 84
81 // keep a copy of the user home directory 85 // keep a copy of the user home directory
82 if (mount(cfg.homedir, RUN_WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) 86 int fd = safe_fd(cfg.homedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
87 if (fd == -1)
88 errExit("safe_fd");
89 char *proc;
90 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
91 errExit("asprintf");
92 if (mount(proc, RUN_WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
83 errExit("mount bind"); 93 errExit("mount bind");
94 free(proc);
95 close(fd);
84 96
85 // mount tmpfs in the new home 97 // mount tmpfs in the new home
86 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0) 98 if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index f91e5ab7c..288726d22 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -268,6 +268,7 @@ static int monitor_application(pid_t app_pid) {
268 if (cfg.timeout) { 268 if (cfg.timeout) {
269 options = WNOHANG; 269 options = WNOHANG;
270 timeout = cfg.timeout; 270 timeout = cfg.timeout;
271 sleep(1);
271 } 272 }
272 273
273 int status = 0; 274 int status = 0;
@@ -302,8 +303,11 @@ static int monitor_application(pid_t app_pid) {
302 // handle --timeout 303 // handle --timeout
303 if (options) { 304 if (options) {
304 if (--timeout == 0) { 305 if (--timeout == 0) {
306 // SIGTERM might fail if the process ignores it (SIG_IGN)
307 // we give it 100ms to close properly and after that we SIGKILL it
305 kill(-1, SIGTERM); 308 kill(-1, SIGTERM);
306 sleep(1); 309 usleep(100000);
310 kill(-1, SIGKILL);
307 flush_stdin(); 311 flush_stdin();
308 _exit(1); 312 _exit(1);
309 } 313 }
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c
index 7dca9aa99..a41e32569 100644
--- a/src/firejail/sbox.c
+++ b/src/firejail/sbox.c
@@ -104,7 +104,7 @@ static struct sock_fprog prog = {
104 .filter = filter, 104 .filter = filter,
105}; 105};
106 106
107int sbox_run(unsigned filter, int num, ...) { 107int sbox_run(unsigned filtermask, int num, ...) {
108 EUID_ROOT(); 108 EUID_ROOT();
109 109
110 int i; 110 int i;
@@ -129,10 +129,26 @@ int sbox_run(unsigned filter, int num, ...) {
129 if (child < 0) 129 if (child < 0)
130 errExit("fork"); 130 errExit("fork");
131 if (child == 0) { 131 if (child == 0) {
132 // clean the new process 132 // preserve firejail-specific env vars
133 char *cl = getenv("FIREJAIL_FILE_COPY_LIMIT");
134 if (cl) {
135 // duplicate the value, who knows what's going to happen with it in clearenv!
136 cl = strdup(cl);
137 if (!cl)
138 errExit("strdup");
139 }
133 clearenv(); 140 clearenv();
141 if (cl) {
142 if (setenv("FIREJAIL_FILE_COPY_LIMIT", cl, 1) == -1)
143 errExit("setenv");
144 free(cl);
145 }
146 if (arg_quiet) // --quiet is passed as an environment variable
147 setenv("FIREJAIL_QUIET", "yes", 1);
148 if (arg_debug) // --debug is passed as an environment variable
149 setenv("FIREJAIL_DEBUG", "yes", 1);
134 150
135 if (filter & SBOX_STDIN_FROM_FILE) { 151 if (filtermask & SBOX_STDIN_FROM_FILE) {
136 int fd; 152 int fd;
137 if((fd = open(SBOX_STDIN_FILE, O_RDONLY)) == -1) { 153 if((fd = open(SBOX_STDIN_FILE, O_RDONLY)) == -1) {
138 fprintf(stderr,"Error: cannot open %s\n", SBOX_STDIN_FILE); 154 fprintf(stderr,"Error: cannot open %s\n", SBOX_STDIN_FILE);
@@ -141,7 +157,7 @@ int sbox_run(unsigned filter, int num, ...) {
141 dup2(fd,STDIN_FILENO); 157 dup2(fd,STDIN_FILENO);
142 close(fd); 158 close(fd);
143 } 159 }
144 else if ((filter & SBOX_ALLOW_STDIN) == 0) { 160 else if ((filtermask & SBOX_ALLOW_STDIN) == 0) {
145 int fd = open("/dev/null",O_RDWR, 0); 161 int fd = open("/dev/null",O_RDWR, 0);
146 if (fd != -1) { 162 if (fd != -1) {
147 dup2(fd, STDIN_FILENO); 163 dup2(fd, STDIN_FILENO);
@@ -159,17 +175,17 @@ int sbox_run(unsigned filter, int num, ...) {
159 umask(027); 175 umask(027);
160 176
161 // apply filters 177 // apply filters
162 if (filter & SBOX_CAPS_NONE) { 178 if (filtermask & SBOX_CAPS_NONE) {
163 caps_drop_all(); 179 caps_drop_all();
164 } 180 }
165 else if (filter & SBOX_CAPS_NETWORK) { 181 else if (filtermask & SBOX_CAPS_NETWORK) {
166#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files 182#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
167 uint64_t set = ((uint64_t) 1) << CAP_NET_ADMIN; 183 uint64_t set = ((uint64_t) 1) << CAP_NET_ADMIN;
168 set |= ((uint64_t) 1) << CAP_NET_RAW; 184 set |= ((uint64_t) 1) << CAP_NET_RAW;
169 caps_set(set); 185 caps_set(set);
170#endif 186#endif
171 } 187 }
172 else if (filter & SBOX_CAPS_HIDEPID) { 188 else if (filtermask & SBOX_CAPS_HIDEPID) {
173#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files 189#ifndef HAVE_GCOV // the following filter will prevent GCOV from saving info in .gcda files
174 uint64_t set = ((uint64_t) 1) << CAP_SYS_PTRACE; 190 uint64_t set = ((uint64_t) 1) << CAP_SYS_PTRACE;
175 set |= ((uint64_t) 1) << CAP_SYS_PACCT; 191 set |= ((uint64_t) 1) << CAP_SYS_PACCT;
@@ -177,7 +193,7 @@ int sbox_run(unsigned filter, int num, ...) {
177#endif 193#endif
178 } 194 }
179 195
180 if (filter & SBOX_SECCOMP) { 196 if (filtermask & SBOX_SECCOMP) {
181 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { 197 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
182 perror("prctl(NO_NEW_PRIVS)"); 198 perror("prctl(NO_NEW_PRIVS)");
183 } 199 }
@@ -186,22 +202,16 @@ int sbox_run(unsigned filter, int num, ...) {
186 } 202 }
187 } 203 }
188 204
189 if (filter & SBOX_ROOT) { 205 if (filtermask & SBOX_ROOT) {
190 // elevate privileges in order to get grsecurity working 206 // elevate privileges in order to get grsecurity working
191 if (setreuid(0, 0)) 207 if (setreuid(0, 0))
192 errExit("setreuid"); 208 errExit("setreuid");
193 if (setregid(0, 0)) 209 if (setregid(0, 0))
194 errExit("setregid"); 210 errExit("setregid");
195 } 211 }
196 else if (filter & SBOX_USER) 212 else if (filtermask & SBOX_USER)
197 drop_privs(1); 213 drop_privs(1);
198 214
199 clearenv();
200
201 // --quiet is passed as an environment variable
202 if (arg_quiet)
203 setenv("FIREJAIL_QUIET", "yes", 1);
204
205 if (arg[0]) // get rid of scan-build warning 215 if (arg[0]) // get rid of scan-build warning
206 execvp(arg[0], arg); 216 execvp(arg[0], arg);
207 else 217 else
diff --git a/src/firejail/util.c b/src/firejail/util.c
index fff0bbf2f..918077235 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -50,7 +50,7 @@ void errLogExit(char* fmt, ...) {
50 char *msg1; 50 char *msg1;
51 char *msg2 = "Access error"; 51 char *msg2 = "Access error";
52 if (vasprintf(&msg1, fmt, args) != -1 && 52 if (vasprintf(&msg1, fmt, args) != -1 &&
53 asprintf(&msg2, "Access error: pid %d, last mount name:%s dir:%s type:%s - %s", getuid(), m->fsname, m->dir, m->fstype, msg1) != -1) 53 asprintf(&msg2, "Access error: uid %d, last mount name:%s dir:%s type:%s - %s", getuid(), m->fsname, m->dir, m->fstype, msg1) != -1)
54 syslog(LOG_CRIT, "%s", msg2); 54 syslog(LOG_CRIT, "%s", msg2);
55 va_end(args); 55 va_end(args);
56 closelog(); 56 closelog();
@@ -487,7 +487,6 @@ char *line_remove_spaces(const char *buf) {
487 size_t len = strlen(buf); 487 size_t len = strlen(buf);
488 if (len == 0) 488 if (len == 0)
489 return NULL; 489 return NULL;
490 assert(len + 1 != 0 && buf[len] == '\0');
491 490
492 // allocate memory for the new string 491 // allocate memory for the new string
493 char *rv = malloc(len + 1); 492 char *rv = malloc(len + 1);
@@ -554,15 +553,13 @@ char *split_comma(char *str) {
554char *clean_pathname(const char *path) { 553char *clean_pathname(const char *path) {
555 assert(path); 554 assert(path);
556 size_t len = strlen(path); 555 size_t len = strlen(path);
557 assert(len + 1 != 0 && path[len] == '\0');
558
559 char *rv = malloc(len + 1); 556 char *rv = malloc(len + 1);
560 if (!rv) 557 if (!rv)
561 errExit("malloc"); 558 errExit("malloc");
562 559
563 if (len > 0) { 560 if (len > 0) {
564 size_t i, j, cnt; 561 size_t i = 0, j = 0, cnt = 0;
565 for (i = 0, j = 0, cnt = 0; i < len; i++) { 562 for (; i < len; i++) {
566 if (path[i] == '/') 563 if (path[i] == '/')
567 cnt++; 564 cnt++;
568 else 565 else
@@ -1142,56 +1139,47 @@ void disable_file_path(const char *path, const char *file) {
1142 free(fname); 1139 free(fname);
1143} 1140}
1144 1141
1145// The returned file descriptor should be suitable for privileged operations on 1142// open file without following any symbolic link
1146// user controlled paths 1143// returns a file descriptor on success, or -1 if a symlink is found
1147int safe_fd(const char *path, int flags) { 1144int safe_fd(const char *path, int flags) {
1148 assert(path); 1145 assert(path);
1149
1150 // reject empty string, relative path
1151 if (*path != '/') 1146 if (*path != '/')
1152 goto errexit; 1147 goto errexit;
1153 // reject ".."
1154 if (strstr(path, "..")) 1148 if (strstr(path, ".."))
1155 goto errexit; 1149 goto errexit;
1156 char *p = strrchr(path, '/');
1157 assert(p);
1158 // reject trailing slash, root directory
1159 if (*(p + 1) == '\0')
1160 goto errexit;
1161 // reject trailing dot
1162 if (*(p + 1) == '.' && *(p + 2) == '\0')
1163 goto errexit;
1164
1165 // work with a copy of path
1166 char *dup = strdup(path);
1167 if (!dup)
1168 errExit("strdup");
1169 1150
1170 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC); 1151 int parentfd = open("/", O_PATH|O_DIRECTORY|O_CLOEXEC);
1171 if (parentfd == -1) 1152 if (parentfd == -1)
1172 errExit("open"); 1153 errExit("open");
1173
1174 // traverse the path and return -1 if a symlink is encountered
1175 int fd = -1; 1154 int fd = -1;
1176 char *current_tok = EMPTY_STRING; 1155
1156 char *last_tok = EMPTY_STRING;
1157 char *dup = strdup(path);
1158 if (!dup)
1159 errExit("strdup");
1177 char *tok = strtok(dup, "/"); 1160 char *tok = strtok(dup, "/");
1178 assert(tok); 1161 if (!tok) { // root directory
1162 free(dup);
1163 return parentfd;
1164 }
1165
1179 while (tok) { 1166 while (tok) {
1180 // open the element, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link 1167 // open the element, assuming it is a directory; this fails with ENOTDIR if it is a symbolic link
1168 // if token is a single dot, the previous directory is reopened
1181 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); 1169 fd = openat(parentfd, tok, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC);
1182 if (fd == -1) { 1170 if (fd == -1) {
1183 // if the following token is NULL, the current token is the final path element 1171 // if the following token is NULL, the current token is the final path element
1184 // try again to open it, this time using the passed flags, and return -1 or the descriptor 1172 // try again to open it, this time using the passed flags, and return -1 or the descriptor
1185 current_tok = tok; 1173 last_tok = tok;
1186 tok = strtok(NULL, "/"); 1174 tok = strtok(NULL, "/");
1187 if (!tok) 1175 if (!tok)
1188 fd = openat(parentfd, current_tok, flags|O_NOFOLLOW); 1176 fd = openat(parentfd, last_tok, flags|O_NOFOLLOW);
1189 close(parentfd); 1177 close(parentfd);
1190 free(dup); 1178 free(dup);
1191 return fd; // -1 if open failed 1179 return fd; // -1 if open failed
1192 } 1180 }
1193 // move on to next path segment 1181 // move on to next path segment
1194 current_tok = tok; 1182 last_tok = tok;
1195 tok = strtok(NULL, "/"); 1183 tok = strtok(NULL, "/");
1196 if (tok) { 1184 if (tok) {
1197 close(parentfd); 1185 close(parentfd);
@@ -1202,13 +1190,13 @@ int safe_fd(const char *path, int flags) {
1202 // we are here because the last path element exists and is of file type directory 1190 // we are here because the last path element exists and is of file type directory
1203 // reopen it using the passed flags 1191 // reopen it using the passed flags
1204 close(fd); 1192 close(fd);
1205 fd = openat(parentfd, current_tok, flags|O_NOFOLLOW); 1193 fd = openat(parentfd, last_tok, flags|O_NOFOLLOW);
1206 close(parentfd); 1194 close(parentfd);
1207 free(dup); 1195 free(dup);
1208 return fd; // -1 if open failed 1196 return fd; // -1 if open failed
1209 1197
1210errexit: 1198errexit:
1211 fprintf(stderr, "Error: cannot open \"%s\", invalid filename\n", path); 1199 fprintf(stderr, "Error: cannot open \"%s\": invalid path\n", path);
1212 exit(1); 1200 exit(1);
1213} 1201}
1214 1202
diff --git a/src/lib/pid.c b/src/lib/pid.c
index c4235ede3..04bc8d132 100644
--- a/src/lib/pid.c
+++ b/src/lib/pid.c
@@ -329,10 +329,9 @@ void pid_read(pid_t mon_pid) {
329 } 329 }
330 } 330 }
331 331
332 pid_t child = -1;
333 struct dirent *entry; 332 struct dirent *entry;
334 char *end; 333 char *end;
335 while (child < 0 && (entry = readdir(dir))) { 334 while ((entry = readdir(dir))) {
336 pid_t pid = strtol(entry->d_name, &end, 10); 335 pid_t pid = strtol(entry->d_name, &end, 10);
337 pid %= max_pids; 336 pid %= max_pids;
338 if (end == entry->d_name || *end) 337 if (end == entry->d_name || *end)
diff --git a/src/libpostexecseccomp/libpostexecseccomp.c b/src/libpostexecseccomp/libpostexecseccomp.c
index 3983510ec..b2f64f18e 100644
--- a/src/libpostexecseccomp/libpostexecseccomp.c
+++ b/src/libpostexecseccomp/libpostexecseccomp.c
@@ -40,9 +40,7 @@ static void load_seccomp(void) {
40 return; 40 return;
41 } 41 }
42 unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); 42 unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter);
43 struct sock_filter *filter = MAP_FAILED; 43 struct sock_filter *filter = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
44 if (size != 0)
45 filter = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
46 close(fd); 44 close(fd);
47 45
48 if (filter == MAP_FAILED) { 46 if (filter == MAP_FAILED) {
diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c
index 397761c74..60fdb5470 100644
--- a/src/libtrace/libtrace.c
+++ b/src/libtrace/libtrace.c
@@ -41,54 +41,45 @@ typedef FILE *(*orig_fopen64_t)(const char *pathname, const char *mode);
41static orig_fopen64_t orig_fopen64 = NULL; 41static orig_fopen64_t orig_fopen64 = NULL;
42 42
43// 43//
44// pid 44// library constructor/destructor
45// 45//
46static FILE *ftty = NULL;
46static pid_t mypid = 0; 47static pid_t mypid = 0;
47static inline pid_t pid(void) {
48 if (!mypid)
49 mypid = getpid();
50 return mypid;
51}
52
53//
54// process name
55//
56#define MAXNAME 16 48#define MAXNAME 16
57static char myname[MAXNAME]; 49static char myname[MAXNAME] = {'\0', };
58static int nameinit = 0; 50
59static char *name(void) { 51static void init(void) __attribute__((constructor));
60 if (!nameinit) { 52void init(void) {
61 // initialize the name of the process based on /proc/PID/comm 53 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
62 memset(myname, 0, MAXNAME); 54
63 55 // tty
64 pid_t p = pid(); 56 ftty = orig_fopen("/dev/tty", "w");
65 char *fname; 57
66 if (asprintf(&fname, "/proc/%u/comm", p) == -1) 58 // pid
67 return "unknown"; 59 mypid = getpid();
68 60
69 // read file 61 // process name
70 if (!orig_fopen) 62 char *fname;
71 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen"); 63 if (asprintf(&fname, "/proc/%u/comm", mypid) == -1)
72 FILE *fp = orig_fopen(fname, "r"); 64 strncpy(myname, "unknown", MAXNAME-1);
73 if (!fp) 65
74 return "unknown"; 66 // read file
75 if (fgets(myname, MAXNAME, fp) == NULL) { 67 FILE *fp = orig_fopen(fname, "r");
76 fclose(fp); 68 if (!fp || fgets(myname, MAXNAME, fp) == NULL)
77 free(fname); 69 strncpy(myname, "unknown", MAXNAME-1);
78 return "unknown"; 70
79 } 71 // clean '\n'
80 72 char *ptr = strchr(myname, '\n');
81 // clean '\n' 73 if (ptr)
82 char *ptr = strchr(myname, '\n'); 74 *ptr = '\0';
83 if (ptr) 75
84 *ptr = '\0'; 76 fclose(fp);
85 77 free(fname);
86 fclose(fp); 78}
87 free(fname);
88 nameinit = 1;
89 }
90 79
91 return myname; 80static void fini(void) __attribute__((destructor));
81void fini(void) {
82 fclose(ftty);
92} 83}
93 84
94// 85//
@@ -235,23 +226,23 @@ static char *translate(XTable *table, int val) {
235static void print_sockaddr(int sockfd, const char *call, const struct sockaddr *addr, int rv) { 226static void print_sockaddr(int sockfd, const char *call, const struct sockaddr *addr, int rv) {
236 if (addr->sa_family == AF_INET) { 227 if (addr->sa_family == AF_INET) {
237 struct sockaddr_in *a = (struct sockaddr_in *) addr; 228 struct sockaddr_in *a = (struct sockaddr_in *) addr;
238 printf("%u:%s:%s %d %s port %u:%d\n", pid(), name(), call, sockfd, inet_ntoa(a->sin_addr), ntohs(a->sin_port), rv); 229 fprintf(ftty, "%u:%s:%s %d %s port %u:%d\n", mypid, myname, call, sockfd, inet_ntoa(a->sin_addr), ntohs(a->sin_port), rv);
239 } 230 }
240 else if (addr->sa_family == AF_INET6) { 231 else if (addr->sa_family == AF_INET6) {
241 struct sockaddr_in6 *a = (struct sockaddr_in6 *) addr; 232 struct sockaddr_in6 *a = (struct sockaddr_in6 *) addr;
242 char str[INET6_ADDRSTRLEN]; 233 char str[INET6_ADDRSTRLEN];
243 inet_ntop(AF_INET6, &(a->sin6_addr), str, INET6_ADDRSTRLEN); 234 inet_ntop(AF_INET6, &(a->sin6_addr), str, INET6_ADDRSTRLEN);
244 printf("%u:%s:%s %d %s:%d\n", pid(), name(), call, sockfd, str, rv); 235 fprintf(ftty, "%u:%s:%s %d %s:%d\n", mypid, myname, call, sockfd, str, rv);
245 } 236 }
246 else if (addr->sa_family == AF_UNIX) { 237 else if (addr->sa_family == AF_UNIX) {
247 struct sockaddr_un *a = (struct sockaddr_un *) addr; 238 struct sockaddr_un *a = (struct sockaddr_un *) addr;
248 if (a->sun_path[0]) 239 if (a->sun_path[0])
249 printf("%u:%s:%s %d %s:%d\n", pid(), name(), call, sockfd, a->sun_path, rv); 240 fprintf(ftty, "%u:%s:%s %d %s:%d\n", mypid, myname, call, sockfd, a->sun_path, rv);
250 else 241 else
251 printf("%u:%s:%s %d @%s:%d\n", pid(), name(), call, sockfd, a->sun_path + 1, rv); 242 fprintf(ftty, "%u:%s:%s %d @%s:%d\n", mypid, myname, call, sockfd, a->sun_path + 1, rv);
252 } 243 }
253 else { 244 else {
254 printf("%u:%s:%s %d family %d:%d\n", pid(), name(), call, sockfd, addr->sa_family, rv); 245 fprintf(ftty, "%u:%s:%s %d family %d:%d\n", mypid, myname, call, sockfd, addr->sa_family, rv);
255 } 246 }
256} 247}
257 248
@@ -267,7 +258,7 @@ int open(const char *pathname, int flags, mode_t mode) {
267 orig_open = (orig_open_t)dlsym(RTLD_NEXT, "open"); 258 orig_open = (orig_open_t)dlsym(RTLD_NEXT, "open");
268 259
269 int rv = orig_open(pathname, flags, mode); 260 int rv = orig_open(pathname, flags, mode);
270 printf("%u:%s:open %s:%d\n", pid(), name(), pathname, rv); 261 fprintf(ftty, "%u:%s:open %s:%d\n", mypid, myname, pathname, rv);
271 return rv; 262 return rv;
272} 263}
273 264
@@ -278,7 +269,7 @@ int open64(const char *pathname, int flags, mode_t mode) {
278 orig_open64 = (orig_open64_t)dlsym(RTLD_NEXT, "open64"); 269 orig_open64 = (orig_open64_t)dlsym(RTLD_NEXT, "open64");
279 270
280 int rv = orig_open64(pathname, flags, mode); 271 int rv = orig_open64(pathname, flags, mode);
281 printf("%u:%s:open64 %s:%d\n", pid(), name(), pathname, rv); 272 fprintf(ftty, "%u:%s:open64 %s:%d\n", mypid, myname, pathname, rv);
282 return rv; 273 return rv;
283} 274}
284 275
@@ -290,7 +281,7 @@ int openat(int dirfd, const char *pathname, int flags, mode_t mode) {
290 orig_openat = (orig_openat_t)dlsym(RTLD_NEXT, "openat"); 281 orig_openat = (orig_openat_t)dlsym(RTLD_NEXT, "openat");
291 282
292 int rv = orig_openat(dirfd, pathname, flags, mode); 283 int rv = orig_openat(dirfd, pathname, flags, mode);
293 printf("%u:%s:openat %s:%d\n", pid(), name(), pathname, rv); 284 fprintf(ftty, "%u:%s:openat %s:%d\n", mypid, myname, pathname, rv);
294 return rv; 285 return rv;
295} 286}
296 287
@@ -301,7 +292,7 @@ int openat64(int dirfd, const char *pathname, int flags, mode_t mode) {
301 orig_openat64 = (orig_openat64_t)dlsym(RTLD_NEXT, "openat64"); 292 orig_openat64 = (orig_openat64_t)dlsym(RTLD_NEXT, "openat64");
302 293
303 int rv = orig_openat64(dirfd, pathname, flags, mode); 294 int rv = orig_openat64(dirfd, pathname, flags, mode);
304 printf("%u:%s:openat64 %s:%d\n", pid(), name(), pathname, rv); 295 fprintf(ftty, "%u:%s:openat64 %s:%d\n", mypid, myname, pathname, rv);
305 return rv; 296 return rv;
306} 297}
307 298
@@ -312,7 +303,7 @@ FILE *fopen(const char *pathname, const char *mode) {
312 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen"); 303 orig_fopen = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen");
313 304
314 FILE *rv = orig_fopen(pathname, mode); 305 FILE *rv = orig_fopen(pathname, mode);
315 printf("%u:%s:fopen %s:%p\n", pid(), name(), pathname, rv); 306 fprintf(ftty, "%u:%s:fopen %s:%p\n", mypid, myname, pathname, rv);
316 return rv; 307 return rv;
317} 308}
318 309
@@ -322,7 +313,7 @@ FILE *fopen64(const char *pathname, const char *mode) {
322 orig_fopen64 = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen64"); 313 orig_fopen64 = (orig_fopen_t)dlsym(RTLD_NEXT, "fopen64");
323 314
324 FILE *rv = orig_fopen64(pathname, mode); 315 FILE *rv = orig_fopen64(pathname, mode);
325 printf("%u:%s:fopen64 %s:%p\n", pid(), name(), pathname, rv); 316 fprintf(ftty, "%u:%s:fopen64 %s:%p\n", mypid, myname, pathname, rv);
326 return rv; 317 return rv;
327} 318}
328#endif /* __GLIBC__ */ 319#endif /* __GLIBC__ */
@@ -336,7 +327,7 @@ FILE *freopen(const char *pathname, const char *mode, FILE *stream) {
336 orig_freopen = (orig_freopen_t)dlsym(RTLD_NEXT, "freopen"); 327 orig_freopen = (orig_freopen_t)dlsym(RTLD_NEXT, "freopen");
337 328
338 FILE *rv = orig_freopen(pathname, mode, stream); 329 FILE *rv = orig_freopen(pathname, mode, stream);
339 printf("%u:%s:freopen %s:%p\n", pid(), name(), pathname, rv); 330 fprintf(ftty, "%u:%s:freopen %s:%p\n", mypid, myname, pathname, rv);
340 return rv; 331 return rv;
341} 332}
342 333
@@ -348,7 +339,7 @@ FILE *freopen64(const char *pathname, const char *mode, FILE *stream) {
348 orig_freopen64 = (orig_freopen64_t)dlsym(RTLD_NEXT, "freopen64"); 339 orig_freopen64 = (orig_freopen64_t)dlsym(RTLD_NEXT, "freopen64");
349 340
350 FILE *rv = orig_freopen64(pathname, mode, stream); 341 FILE *rv = orig_freopen64(pathname, mode, stream);
351 printf("%u:%s:freopen64 %s:%p\n", pid(), name(), pathname, rv); 342 fprintf(ftty, "%u:%s:freopen64 %s:%p\n", mypid, myname, pathname, rv);
352 return rv; 343 return rv;
353} 344}
354#endif /* __GLIBC__ */ 345#endif /* __GLIBC__ */
@@ -361,7 +352,7 @@ int unlink(const char *pathname) {
361 orig_unlink = (orig_unlink_t)dlsym(RTLD_NEXT, "unlink"); 352 orig_unlink = (orig_unlink_t)dlsym(RTLD_NEXT, "unlink");
362 353
363 int rv = orig_unlink(pathname); 354 int rv = orig_unlink(pathname);
364 printf("%u:%s:unlink %s:%d\n", pid(), name(), pathname, rv); 355 fprintf(ftty, "%u:%s:unlink %s:%d\n", mypid, myname, pathname, rv);
365 return rv; 356 return rv;
366} 357}
367 358
@@ -372,7 +363,7 @@ int unlinkat(int dirfd, const char *pathname, int flags) {
372 orig_unlinkat = (orig_unlinkat_t)dlsym(RTLD_NEXT, "unlinkat"); 363 orig_unlinkat = (orig_unlinkat_t)dlsym(RTLD_NEXT, "unlinkat");
373 364
374 int rv = orig_unlinkat(dirfd, pathname, flags); 365 int rv = orig_unlinkat(dirfd, pathname, flags);
375 printf("%u:%s:unlinkat %s:%d\n", pid(), name(), pathname, rv); 366 fprintf(ftty, "%u:%s:unlinkat %s:%d\n", mypid, myname, pathname, rv);
376 return rv; 367 return rv;
377} 368}
378 369
@@ -384,7 +375,7 @@ int mkdir(const char *pathname, mode_t mode) {
384 orig_mkdir = (orig_mkdir_t)dlsym(RTLD_NEXT, "mkdir"); 375 orig_mkdir = (orig_mkdir_t)dlsym(RTLD_NEXT, "mkdir");
385 376
386 int rv = orig_mkdir(pathname, mode); 377 int rv = orig_mkdir(pathname, mode);
387 printf("%u:%s:mkdir %s:%d\n", pid(), name(), pathname, rv); 378 fprintf(ftty, "%u:%s:mkdir %s:%d\n", mypid, myname, pathname, rv);
388 return rv; 379 return rv;
389} 380}
390 381
@@ -395,7 +386,7 @@ int mkdirat(int dirfd, const char *pathname, mode_t mode) {
395 orig_mkdirat = (orig_mkdirat_t)dlsym(RTLD_NEXT, "mkdirat"); 386 orig_mkdirat = (orig_mkdirat_t)dlsym(RTLD_NEXT, "mkdirat");
396 387
397 int rv = orig_mkdirat(dirfd, pathname, mode); 388 int rv = orig_mkdirat(dirfd, pathname, mode);
398 printf("%u:%s:mkdirat %s:%d\n", pid(), name(), pathname, rv); 389 fprintf(ftty, "%u:%s:mkdirat %s:%d\n", mypid, myname, pathname, rv);
399 return rv; 390 return rv;
400} 391}
401 392
@@ -406,56 +397,56 @@ int rmdir(const char *pathname) {
406 orig_rmdir = (orig_rmdir_t)dlsym(RTLD_NEXT, "rmdir"); 397 orig_rmdir = (orig_rmdir_t)dlsym(RTLD_NEXT, "rmdir");
407 398
408 int rv = orig_rmdir(pathname); 399 int rv = orig_rmdir(pathname);
409 printf("%u:%s:rmdir %s:%d\n", pid(), name(), pathname, rv); 400 fprintf(ftty, "%u:%s:rmdir %s:%d\n", mypid, myname, pathname, rv);
410 return rv; 401 return rv;
411} 402}
412 403
413// stat 404// stat
414typedef int (*orig_stat_t)(const char *pathname, struct stat *buf); 405typedef int (*orig_stat_t)(const char *pathname, struct stat *statbuf);
415static orig_stat_t orig_stat = NULL; 406static orig_stat_t orig_stat = NULL;
416int stat(const char *pathname, struct stat *buf) { 407int stat(const char *pathname, struct stat *statbuf) {
417 if (!orig_stat) 408 if (!orig_stat)
418 orig_stat = (orig_stat_t)dlsym(RTLD_NEXT, "stat"); 409 orig_stat = (orig_stat_t)dlsym(RTLD_NEXT, "stat");
419 410
420 int rv = orig_stat(pathname, buf); 411 int rv = orig_stat(pathname, statbuf);
421 printf("%u:%s:stat %s:%d\n", pid(), name(), pathname, rv); 412 fprintf(ftty, "%u:%s:stat %s:%d\n", mypid, myname, pathname, rv);
422 return rv; 413 return rv;
423} 414}
424 415
425#ifdef __GLIBC__ 416#ifdef __GLIBC__
426typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf); 417typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *statbuf);
427static orig_stat64_t orig_stat64 = NULL; 418static orig_stat64_t orig_stat64 = NULL;
428int stat64(const char *pathname, struct stat64 *buf) { 419int stat64(const char *pathname, struct stat64 *statbuf) {
429 if (!orig_stat64) 420 if (!orig_stat64)
430 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64"); 421 orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64");
431 422
432 int rv = orig_stat64(pathname, buf); 423 int rv = orig_stat64(pathname, statbuf);
433 printf("%u:%s:stat64 %s:%d\n", pid(), name(), pathname, rv); 424 fprintf(ftty, "%u:%s:stat64 %s:%d\n", mypid, myname, pathname, rv);
434 return rv; 425 return rv;
435} 426}
436#endif /* __GLIBC__ */ 427#endif /* __GLIBC__ */
437 428
438// lstat 429// lstat
439typedef int (*orig_lstat_t)(const char *pathname, struct stat *buf); 430typedef int (*orig_lstat_t)(const char *pathname, struct stat *statbuf);
440static orig_lstat_t orig_lstat = NULL; 431static orig_lstat_t orig_lstat = NULL;
441int lstat(const char *pathname, struct stat *buf) { 432int lstat(const char *pathname, struct stat *statbuf) {
442 if (!orig_lstat) 433 if (!orig_lstat)
443 orig_lstat = (orig_lstat_t)dlsym(RTLD_NEXT, "lstat"); 434 orig_lstat = (orig_lstat_t)dlsym(RTLD_NEXT, "lstat");
444 435
445 int rv = orig_lstat(pathname, buf); 436 int rv = orig_lstat(pathname, statbuf);
446 printf("%u:%s:lstat %s:%d\n", pid(), name(), pathname, rv); 437 fprintf(ftty, "%u:%s:lstat %s:%d\n", mypid, myname, pathname, rv);
447 return rv; 438 return rv;
448} 439}
449 440
450#ifdef __GLIBC__ 441#ifdef __GLIBC__
451typedef int (*orig_lstat64_t)(const char *pathname, struct stat64 *buf); 442typedef int (*orig_lstat64_t)(const char *pathname, struct stat64 *statbuf);
452static orig_lstat64_t orig_lstat64 = NULL; 443static orig_lstat64_t orig_lstat64 = NULL;
453int lstat64(const char *pathname, struct stat64 *buf) { 444int lstat64(const char *pathname, struct stat64 *statbuf) {
454 if (!orig_lstat64) 445 if (!orig_lstat64)
455 orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64"); 446 orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64");
456 447
457 int rv = orig_lstat64(pathname, buf); 448 int rv = orig_lstat64(pathname, statbuf);
458 printf("%u:%s:lstat64 %s:%d\n", pid(), name(), pathname, rv); 449 fprintf(ftty, "%u:%s:lstat64 %s:%d\n", mypid, myname, pathname, rv);
459 return rv; 450 return rv;
460} 451}
461#endif /* __GLIBC__ */ 452#endif /* __GLIBC__ */
@@ -468,7 +459,7 @@ DIR *opendir(const char *pathname) {
468 orig_opendir = (orig_opendir_t)dlsym(RTLD_NEXT, "opendir"); 459 orig_opendir = (orig_opendir_t)dlsym(RTLD_NEXT, "opendir");
469 460
470 DIR *rv = orig_opendir(pathname); 461 DIR *rv = orig_opendir(pathname);
471 printf("%u:%s:opendir %s:%p\n", pid(), name(), pathname, rv); 462 fprintf(ftty, "%u:%s:opendir %s:%p\n", mypid, myname, pathname, rv);
472 return rv; 463 return rv;
473} 464}
474 465
@@ -480,7 +471,7 @@ int access(const char *pathname, int mode) {
480 orig_access = (orig_access_t)dlsym(RTLD_NEXT, "access"); 471 orig_access = (orig_access_t)dlsym(RTLD_NEXT, "access");
481 472
482 int rv = orig_access(pathname, mode); 473 int rv = orig_access(pathname, mode);
483 printf("%u:%s:access %s:%d\n", pid(), name(), pathname, rv); 474 fprintf(ftty, "%u:%s:access %s:%d\n", mypid, myname, pathname, rv);
484 return rv; 475 return rv;
485} 476}
486 477
@@ -501,14 +492,14 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
501// socket 492// socket
502typedef int (*orig_socket_t)(int domain, int type, int protocol); 493typedef int (*orig_socket_t)(int domain, int type, int protocol);
503static orig_socket_t orig_socket = NULL; 494static orig_socket_t orig_socket = NULL;
504static char buf[1024]; 495static char socketbuf[1024];
505int socket(int domain, int type, int protocol) { 496int socket(int domain, int type, int protocol) {
506 if (!orig_socket) 497 if (!orig_socket)
507 orig_socket = (orig_socket_t)dlsym(RTLD_NEXT, "socket"); 498 orig_socket = (orig_socket_t)dlsym(RTLD_NEXT, "socket");
508 499
509 int rv = orig_socket(domain, type, protocol); 500 int rv = orig_socket(domain, type, protocol);
510 char *ptr = buf; 501 char *ptr = socketbuf;
511 ptr += sprintf(ptr, "%u:%s:socket ", pid(), name()); 502 ptr += sprintf(ptr, "%u:%s:socket ", mypid, myname);
512 char *str = translate(socket_domain, domain); 503 char *str = translate(socket_domain, domain);
513 if (str == NULL) 504 if (str == NULL)
514 ptr += sprintf(ptr, "%d ", domain); 505 ptr += sprintf(ptr, "%d ", domain);
@@ -538,7 +529,7 @@ int socket(int domain, int type, int protocol) {
538 sprintf(ptr, "%s", str); 529 sprintf(ptr, "%s", str);
539 } 530 }
540 531
541 printf("%s:%d\n", buf, rv); 532 fprintf(ftty, "%s:%d\n", socketbuf, rv);
542 return rv; 533 return rv;
543} 534}
544 535
@@ -576,7 +567,7 @@ int system(const char *command) {
576 orig_system = (orig_system_t)dlsym(RTLD_NEXT, "system"); 567 orig_system = (orig_system_t)dlsym(RTLD_NEXT, "system");
577 568
578 int rv = orig_system(command); 569 int rv = orig_system(command);
579 printf("%u:%s:system %s:%d\n", pid(), name(), command, rv); 570 fprintf(ftty, "%u:%s:system %s:%d\n", mypid, myname, command, rv);
580 571
581 return rv; 572 return rv;
582} 573}
@@ -588,7 +579,7 @@ int setuid(uid_t uid) {
588 orig_setuid = (orig_setuid_t)dlsym(RTLD_NEXT, "setuid"); 579 orig_setuid = (orig_setuid_t)dlsym(RTLD_NEXT, "setuid");
589 580
590 int rv = orig_setuid(uid); 581 int rv = orig_setuid(uid);
591 printf("%u:%s:setuid %d:%d\n", pid(), name(), uid, rv); 582 fprintf(ftty, "%u:%s:setuid %d:%d\n", mypid, myname, uid, rv);
592 583
593 return rv; 584 return rv;
594} 585}
@@ -600,7 +591,7 @@ int setgid(gid_t gid) {
600 orig_setgid = (orig_setgid_t)dlsym(RTLD_NEXT, "setgid"); 591 orig_setgid = (orig_setgid_t)dlsym(RTLD_NEXT, "setgid");
601 592
602 int rv = orig_setgid(gid); 593 int rv = orig_setgid(gid);
603 printf("%u:%s:setgid %d:%d\n", pid(), name(), gid, rv); 594 fprintf(ftty, "%u:%s:setgid %d:%d\n", mypid, myname, gid, rv);
604 595
605 return rv; 596 return rv;
606} 597}
@@ -612,7 +603,7 @@ int setfsuid(uid_t uid) {
612 orig_setfsuid = (orig_setfsuid_t)dlsym(RTLD_NEXT, "setfsuid"); 603 orig_setfsuid = (orig_setfsuid_t)dlsym(RTLD_NEXT, "setfsuid");
613 604
614 int rv = orig_setfsuid(uid); 605 int rv = orig_setfsuid(uid);
615 printf("%u:%s:setfsuid %d:%d\n", pid(), name(), uid, rv); 606 fprintf(ftty, "%u:%s:setfsuid %d:%d\n", mypid, myname, uid, rv);
616 607
617 return rv; 608 return rv;
618} 609}
@@ -624,7 +615,7 @@ int setfsgid(gid_t gid) {
624 orig_setfsgid = (orig_setfsgid_t)dlsym(RTLD_NEXT, "setfsgid"); 615 orig_setfsgid = (orig_setfsgid_t)dlsym(RTLD_NEXT, "setfsgid");
625 616
626 int rv = orig_setfsgid(gid); 617 int rv = orig_setfsgid(gid);
627 printf("%u:%s:setfsgid %d:%d\n", pid(), name(), gid, rv); 618 fprintf(ftty, "%u:%s:setfsgid %d:%d\n", mypid, myname, gid, rv);
628 619
629 return rv; 620 return rv;
630} 621}
@@ -636,7 +627,7 @@ int setreuid(uid_t ruid, uid_t euid) {
636 orig_setreuid = (orig_setreuid_t)dlsym(RTLD_NEXT, "setreuid"); 627 orig_setreuid = (orig_setreuid_t)dlsym(RTLD_NEXT, "setreuid");
637 628
638 int rv = orig_setreuid(ruid, euid); 629 int rv = orig_setreuid(ruid, euid);
639 printf("%u:%s:setreuid %d %d:%d\n", pid(), name(), ruid, euid, rv); 630 fprintf(ftty, "%u:%s:setreuid %d %d:%d\n", mypid, myname, ruid, euid, rv);
640 631
641 return rv; 632 return rv;
642} 633}
@@ -648,7 +639,7 @@ int setregid(gid_t rgid, gid_t egid) {
648 orig_setregid = (orig_setregid_t)dlsym(RTLD_NEXT, "setregid"); 639 orig_setregid = (orig_setregid_t)dlsym(RTLD_NEXT, "setregid");
649 640
650 int rv = orig_setregid(rgid, egid); 641 int rv = orig_setregid(rgid, egid);
651 printf("%u:%s:setregid %d %d:%d\n", pid(), name(), rgid, egid, rv); 642 fprintf(ftty, "%u:%s:setregid %d %d:%d\n", mypid, myname, rgid, egid, rv);
652 643
653 return rv; 644 return rv;
654} 645}
@@ -660,7 +651,7 @@ int setresuid(uid_t ruid, uid_t euid, uid_t suid) {
660 orig_setresuid = (orig_setresuid_t)dlsym(RTLD_NEXT, "setresuid"); 651 orig_setresuid = (orig_setresuid_t)dlsym(RTLD_NEXT, "setresuid");
661 652
662 int rv = orig_setresuid(ruid, euid, suid); 653 int rv = orig_setresuid(ruid, euid, suid);
663 printf("%u:%s:setresuid %d %d %d:%d\n", pid(), name(), ruid, euid, suid, rv); 654 fprintf(ftty, "%u:%s:setresuid %d %d %d:%d\n", mypid, myname, ruid, euid, suid, rv);
664 655
665 return rv; 656 return rv;
666} 657}
@@ -672,7 +663,7 @@ int setresgid(gid_t rgid, gid_t egid, gid_t sgid) {
672 orig_setresgid = (orig_setresgid_t)dlsym(RTLD_NEXT, "setresgid"); 663 orig_setresgid = (orig_setresgid_t)dlsym(RTLD_NEXT, "setresgid");
673 664
674 int rv = orig_setresgid(rgid, egid, sgid); 665 int rv = orig_setresgid(rgid, egid, sgid);
675 printf("%u:%s:setresgid %d %d %d:%d\n", pid(), name(), rgid, egid, sgid, rv); 666 fprintf(ftty, "%u:%s:setresgid %d %d %d:%d\n", mypid, myname, rgid, egid, sgid, rv);
676 667
677 return rv; 668 return rv;
678} 669}
@@ -687,6 +678,6 @@ static void log_exec(int argc, char** argv) {
687 int rv = readlink("/proc/self/exe", buf, PATH_MAX); 678 int rv = readlink("/proc/self/exe", buf, PATH_MAX);
688 if (rv != -1) { 679 if (rv != -1) {
689 buf[rv] = '\0'; // readlink does not add a '\0' at the end 680 buf[rv] = '\0'; // readlink does not add a '\0' at the end
690 printf("%u:%s:exec %s:0\n", pid(), name(), buf); 681 fprintf(ftty, "%u:%s:exec %s:0\n", mypid, myname, buf);
691 } 682 }
692} 683}
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 201339c8b..951618669 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -8,6 +8,12 @@ Start a sandbox:
8firejail [OPTIONS] [program and arguments] 8firejail [OPTIONS] [program and arguments]
9.RE 9.RE
10.PP 10.PP
11Start an AppImage program:
12.PP
13.RS
14firejail [OPTIONS] --appimage [appimage-file and arguments]
15.RE
16.PP
11File transfer from an existing sandbox 17File transfer from an existing sandbox
12.PP 18.PP
13.RS 19.RS