diff options
55 files changed, 908 insertions, 748 deletions
@@ -310,6 +310,8 @@ DiGitHubCap (https://github.com/DiGitHubCap) | |||
310 | - fix qt5ct colour schemes and QSS | 310 | - fix qt5ct colour schemes and QSS |
311 | Disconnect3d (https://github.com/disconnect3d) | 311 | Disconnect3d (https://github.com/disconnect3d) |
312 | - code cleanup | 312 | - code cleanup |
313 | dm9pZCAq (https://github.com/dm9pZCAq) | ||
314 | - fix for compilation under musl | ||
313 | dmfreemon (https://github.com/dmfreemon) | 315 | dmfreemon (https://github.com/dmfreemon) |
314 | - add sandbox name or name of private directory to the window title when xpra is used | 316 | - add sandbox name or name of private directory to the window title when xpra is used |
315 | - handle malloc() failures; use gnu_basename() instead of basenaem() | 317 | - handle malloc() failures; use gnu_basename() instead of basenaem() |
@@ -22,43 +22,23 @@ implemented directly in Linux kernel and available on any Linux computer. | |||
22 | <table><tr> | 22 | <table><tr> |
23 | 23 | ||
24 | <td> | 24 | <td> |
25 | <a href="http://www.youtube.com/watch?feature=player_embedded&v=8jfXL0ePV7U | 25 | <a href="https://www.brighteon.com/1928415c-2bce-40b2-a81f-7861a3734913" target="_blank"> |
26 | " target="_blank"><img src="http://img.youtube.com/vi/8jfXL0ePV7U/0.jpg" | 26 | <img src="https://video.brighteon.com/file/Brighteon-staging/thumbnail/682ae17c-3fd8-4813-9c4e-6917c7cd2a5c.0000001.jpg" |
27 | alt="Firejail Introduction" width="240" height="180" border="10" /><br/>Firejail Intro</a> | 27 | alt="Introduction" width="240" height="142" border="10" /><br/>Introduction</a> |
28 | </td> | 28 | </td> |
29 | 29 | ||
30 | <td> | 30 | <td> |
31 | <a href="http://www.youtube.com/watch?feature=player_embedded&v=J1ZsXrpAgBU | 31 | <a href="https://www.brighteon.com/c20c32ac-1953-438f-8640-a414dcb318d6" target="_blank"> |
32 | " target="_blank"><img src="http://img.youtube.com/vi/J1ZsXrpAgBU/0.jpg" | 32 | <img src="https://photos.brighteon.com/thumbnail/ecd8b0ca-7564-4993-a676-bbe4aa21cffc" |
33 | alt="Firejail Demo" width="240" height="180" border="10" /><br/>Firejail Demo</a> | 33 | alt="Technology" width="240" height="142" border="10" /><br/>Technology</a> |
34 | </td> | 34 | </td> |
35 | 35 | ||
36 | <td> | 36 | <td> |
37 | <a href="http://www.youtube.com/watch?feature=player_embedded&v=EyEz65RYfw4 | 37 | <a href="https://www.brighteon.com/94ae1731-2352-4cda-bb48-7cc7a6ad32f8" target="_blank"> |
38 | " target="_blank"><img src="http://img.youtube.com/vi/EyEz65RYfw4/0.jpg" | 38 | <img src="https://photos.brighteon.com/thumbnail/5c90254c-61f3-4927-ac57-ae279dc543cf" |
39 | alt="Debian Install" width="240" height="180" border="10" /><br/>Debian Install</a> | 39 | alt="Deep Dive" width="240" height="142" border="10" /><br/>Deep Dive</a> |
40 | </td> | 40 | </td> |
41 | 41 | ||
42 | |||
43 | </tr><tr> | ||
44 | <td> | ||
45 | <a href="http://www.youtube.com/watch?feature=player_embedded&v=Uy2ZTHc4s0w | ||
46 | " target="_blank"><img src="http://img.youtube.com/vi/Uy2ZTHc4s0w/0.jpg" | ||
47 | alt="Arch Linux Install" width="240" height="180" border="10" /><br/>Arch Linux Install</a> | ||
48 | |||
49 | </td> | ||
50 | <td> | ||
51 | <a href="http://www.youtube.com/watch?feature=player_embedded&v=xuMxRx0zSfQ | ||
52 | " target="_blank"><img src="http://img.youtube.com/vi/xuMxRx0zSfQ/0.jpg" | ||
53 | alt="Disable Network Access" width="240" height="180" border="10" /><br/>Disable Network Access</a> | ||
54 | |||
55 | </td> | ||
56 | <td> | ||
57 | <a href="http://www.youtube.com/watch?feature=player_embedded&v=N-Mso2bSr3o | ||
58 | " target="_blank"><img src="http://img.youtube.com/vi/N-Mso2bSr3o/0.jpg" | ||
59 | alt="Firejail Security Deep Dive" width="240" height="180" border="10" /><br/>Firejail Security Deep Dive</a> | ||
60 | |||
61 | </td> | ||
62 | </tr></table> | 42 | </tr></table> |
63 | 43 | ||
64 | Project webpage: https://firejail.wordpress.com/ | 44 | Project webpage: https://firejail.wordpress.com/ |
@@ -239,30 +219,30 @@ A small tool to print profile statistics. Compile as usual and run in /etc/profi | |||
239 | $ sudo cp src/profstats/profstats /etc/firejail/. | 219 | $ sudo cp src/profstats/profstats /etc/firejail/. |
240 | $ cd /etc/firejail | 220 | $ cd /etc/firejail |
241 | $ ./profstats *.profile | 221 | $ ./profstats *.profile |
242 | profiles 1150 | 222 | profiles 1167 |
243 | include local profile 1150 (include profile-name.local) | 223 | include local profile 1167 (include profile-name.local) |
244 | include globals 1120 (include globals.local) | 224 | include globals 1136 (include globals.local) |
245 | blacklist ~/.ssh 1026 (include disable-common.inc) | 225 | blacklist ~/.ssh 1042 (include disable-common.inc) |
246 | seccomp 1050 | 226 | seccomp 1062 |
247 | capabilities 1146 | 227 | capabilities 1163 |
248 | noexec 1030 (include disable-exec.inc) | 228 | noexec 1049 (include disable-exec.inc) |
249 | noroot 959 | 229 | noroot 971 |
250 | memory-deny-write-execute 253 | 230 | memory-deny-write-execute 256 |
251 | apparmor 681 | 231 | apparmor 693 |
252 | private-bin 667 | 232 | private-bin 677 |
253 | private-dev 1009 | 233 | private-dev 1027 |
254 | private-etc 523 | 234 | private-etc 532 |
255 | private-tmp 883 | 235 | private-tmp 897 |
256 | whitelist home directory 547 | 236 | whitelist home directory 557 |
257 | whitelist var 818 (include whitelist-var-common.inc) | 237 | whitelist var 836 (include whitelist-var-common.inc) |
258 | whitelist run/user 616 (include whitelist-runuser-common.inc | 238 | whitelist run/user 1137 (include whitelist-runuser-common.inc |
259 | or blacklist ${RUNUSER}) | 239 | or blacklist ${RUNUSER}) |
260 | whitelist usr/share 591 (include whitelist-usr-share-common.inc | 240 | whitelist usr/share 609 (include whitelist-usr-share-common.inc |
261 | net none 391 | 241 | net none 396 |
262 | dbus-user none 641 | 242 | dbus-user none 656 |
263 | dbus-user filter 105 | 243 | dbus-user filter 108 |
264 | dbus-system none 792 | 244 | dbus-system none 808 |
265 | dbus-system filter 7 | 245 | dbus-system filter 10 |
266 | ``` | 246 | ``` |
267 | 247 | ||
268 | ### New profiles: | 248 | ### New profiles: |
@@ -711,6 +711,7 @@ ac_subst_files='' | |||
711 | ac_user_opts=' | 711 | ac_user_opts=' |
712 | enable_option_checking | 712 | enable_option_checking |
713 | enable_analyzer | 713 | enable_analyzer |
714 | enable_sanitizer | ||
714 | enable_apparmor | 715 | enable_apparmor |
715 | enable_selinux | 716 | enable_selinux |
716 | enable_dbusproxy | 717 | enable_dbusproxy |
@@ -1368,6 +1369,8 @@ Optional Features: | |||
1368 | --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) | 1369 | --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) |
1369 | --enable-FEATURE[=ARG] include FEATURE [ARG=yes] | 1370 | --enable-FEATURE[=ARG] include FEATURE [ARG=yes] |
1370 | --enable-analyzer enable GCC static analyzer | 1371 | --enable-analyzer enable GCC static analyzer |
1372 | --enable-sanitizer=[address | memory | undefined] | ||
1373 | enable a compiler-based sanitizer (debug) | ||
1371 | --enable-apparmor enable apparmor | 1374 | --enable-apparmor enable apparmor |
1372 | --enable-selinux SELinux labeling support | 1375 | --enable-selinux SELinux labeling support |
1373 | --disable-dbusproxy disable dbus proxy | 1376 | --disable-dbusproxy disable dbus proxy |
@@ -3294,6 +3297,57 @@ if test "x$enable_analyzer" = "xyes"; then : | |||
3294 | 3297 | ||
3295 | fi | 3298 | fi |
3296 | 3299 | ||
3300 | # Check whether --enable-sanitizer was given. | ||
3301 | if test "${enable_sanitizer+set}" = set; then : | ||
3302 | enableval=$enable_sanitizer; | ||
3303 | else | ||
3304 | enable_sanitizer=no | ||
3305 | fi | ||
3306 | |||
3307 | if test "x$enable_sanitizer" != "xno" ; then : | ||
3308 | as_CACHEVAR=`$as_echo "ax_cv_check_cflags__-fsanitize=$enable_sanitizer" | $as_tr_sh` | ||
3309 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fsanitize=$enable_sanitizer" >&5 | ||
3310 | $as_echo_n "checking whether C compiler accepts -fsanitize=$enable_sanitizer... " >&6; } | ||
3311 | if eval \${$as_CACHEVAR+:} false; then : | ||
3312 | $as_echo_n "(cached) " >&6 | ||
3313 | else | ||
3314 | |||
3315 | ax_check_save_flags=$CFLAGS | ||
3316 | CFLAGS="$CFLAGS -fsanitize=$enable_sanitizer" | ||
3317 | cat confdefs.h - <<_ACEOF >conftest.$ac_ext | ||
3318 | /* end confdefs.h. */ | ||
3319 | |||
3320 | int | ||
3321 | main () | ||
3322 | { | ||
3323 | |||
3324 | ; | ||
3325 | return 0; | ||
3326 | } | ||
3327 | _ACEOF | ||
3328 | if ac_fn_c_try_compile "$LINENO"; then : | ||
3329 | eval "$as_CACHEVAR=yes" | ||
3330 | else | ||
3331 | eval "$as_CACHEVAR=no" | ||
3332 | fi | ||
3333 | rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext | ||
3334 | CFLAGS=$ax_check_save_flags | ||
3335 | fi | ||
3336 | eval ac_res=\$$as_CACHEVAR | ||
3337 | { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 | ||
3338 | $as_echo "$ac_res" >&6; } | ||
3339 | if eval test \"x\$"$as_CACHEVAR"\" = x"yes"; then : | ||
3340 | |||
3341 | EXTRA_CFLAGS="$EXTRA_CFLAGS -fsanitize=$enable_sanitizer -fno-omit-frame-pointer" | ||
3342 | EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fsanitize=$enable_sanitizer" | ||
3343 | |||
3344 | else | ||
3345 | as_fn_error $? "sanitizer not supported: $enable_sanitizer" "$LINENO" 5 | ||
3346 | |||
3347 | fi | ||
3348 | |||
3349 | fi | ||
3350 | |||
3297 | HAVE_APPARMOR="" | 3351 | HAVE_APPARMOR="" |
3298 | # Check whether --enable-apparmor was given. | 3352 | # Check whether --enable-apparmor was given. |
3299 | if test "${enable_apparmor+set}" = set; then : | 3353 | if test "${enable_apparmor+set}" = set; then : |
diff --git a/configure.ac b/configure.ac index 5fde6d402..fc5823143 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -45,6 +45,15 @@ AS_IF([test "x$enable_analyzer" = "xyes"], [ | |||
45 | EXTRA_CFLAGS="$EXTRA_CFLAGS -fanalyzer -Wno-analyzer-malloc-leak" | 45 | EXTRA_CFLAGS="$EXTRA_CFLAGS -fanalyzer -Wno-analyzer-malloc-leak" |
46 | ]) | 46 | ]) |
47 | 47 | ||
48 | AC_ARG_ENABLE([sanitizer], | ||
49 | AS_HELP_STRING([--enable-sanitizer=@<:@address | memory | undefined@:>@], [enable a compiler-based sanitizer (debug)]), [], [enable_sanitizer=no]) | ||
50 | AS_IF([test "x$enable_sanitizer" != "xno" ], | ||
51 | [AX_CHECK_COMPILE_FLAG([-fsanitize=$enable_sanitizer], [ | ||
52 | EXTRA_CFLAGS="$EXTRA_CFLAGS -fsanitize=$enable_sanitizer -fno-omit-frame-pointer" | ||
53 | EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fsanitize=$enable_sanitizer" | ||
54 | ], [AC_MSG_ERROR([sanitizer not supported: $enable_sanitizer])] | ||
55 | )]) | ||
56 | |||
48 | HAVE_APPARMOR="" | 57 | HAVE_APPARMOR="" |
49 | AC_ARG_ENABLE([apparmor], | 58 | AC_ARG_ENABLE([apparmor], |
50 | AS_HELP_STRING([--enable-apparmor], [enable apparmor])) | 59 | AS_HELP_STRING([--enable-apparmor], [enable apparmor])) |
diff --git a/etc/inc/disable-proc.inc b/etc/inc/disable-proc.inc new file mode 100644 index 000000000..81a8883f3 --- /dev/null +++ b/etc/inc/disable-proc.inc | |||
@@ -0,0 +1,82 @@ | |||
1 | # This file is overwritten during software install. | ||
2 | # Persistent customizations should go in a .local file. | ||
3 | include disable-proc.local | ||
4 | |||
5 | blacklist /proc/acpi | ||
6 | blacklist /proc/asound | ||
7 | blacklist /proc/bootconfig | ||
8 | blacklist /proc/buddyinfo | ||
9 | blacklist /proc/cgroups | ||
10 | blacklist /proc/cmdline | ||
11 | blacklist /proc/config.gz | ||
12 | blacklist /proc/consoles | ||
13 | #blacklist /proc/cpuinfo | ||
14 | blacklist /proc/crypto | ||
15 | blacklist /proc/devices | ||
16 | blacklist /proc/diskstats | ||
17 | blacklist /proc/dma | ||
18 | #blacklist /proc/driver | ||
19 | blacklist /proc/dynamic_debug | ||
20 | blacklist /proc/execdomains | ||
21 | blacklist /proc/fb | ||
22 | #blacklist /proc/filesystems | ||
23 | blacklist /proc/fs | ||
24 | blacklist /proc/i8k | ||
25 | blacklist /proc/interrupts | ||
26 | blacklist /proc/iomem | ||
27 | blacklist /proc/ioports | ||
28 | blacklist /proc/irq | ||
29 | blacklist /proc/kallsyms | ||
30 | blacklist /proc/kcore | ||
31 | blacklist /proc/keys | ||
32 | blacklist /proc/key-users | ||
33 | blacklist /proc/kmsg | ||
34 | blacklist /proc/kpagecgroup | ||
35 | blacklist /proc/kpagecount | ||
36 | blacklist /proc/kpageflags | ||
37 | blacklist /proc/latency_stats | ||
38 | #blacklist /proc/loadavg | ||
39 | blacklist /proc/locks | ||
40 | blacklist /proc/mdstat | ||
41 | #blacklist /proc/meminfo | ||
42 | blacklist /proc/misc | ||
43 | #blacklist /proc/modules | ||
44 | #blacklist /proc/mounts | ||
45 | blacklist /proc/mtrr | ||
46 | #blacklist /proc/net | ||
47 | blacklist /proc/partitions | ||
48 | blacklist /proc/pressure | ||
49 | blacklist /proc/sched_debug | ||
50 | blacklist /proc/schedstat | ||
51 | blacklist /proc/scsi | ||
52 | #blacklist /proc/self | ||
53 | blacklist /proc/slabinfo | ||
54 | blacklist /proc/softirqs | ||
55 | blacklist /proc/spl | ||
56 | #blacklist /proc/stat | ||
57 | blacklist /proc/swaps | ||
58 | #blacklist /proc/sys | ||
59 | blacklist /proc/sysrq-trigger | ||
60 | blacklist /proc/sysvipc | ||
61 | #blacklist /proc/thread-self | ||
62 | blacklist /proc/timer_list | ||
63 | blacklist /proc/tty | ||
64 | #blacklist /proc/uptime | ||
65 | #blacklist /proc/version | ||
66 | blacklist /proc/version_signature | ||
67 | blacklist /proc/vmallocinfo | ||
68 | #blacklist /proc/vmstat | ||
69 | #blacklist /proc/zoneinfo | ||
70 | |||
71 | blacklist /proc/sys/abi | ||
72 | blacklist /proc/sys/crypto | ||
73 | blacklist /proc/sys/debug | ||
74 | blacklist /proc/sys/dev | ||
75 | blacklist /proc/sys/fs | ||
76 | blacklist /proc/sys/net | ||
77 | blacklist /proc/sys/user | ||
78 | blacklist /proc/sys/vm | ||
79 | |||
80 | noblacklist /proc/sys/kernel/osrelease | ||
81 | noblacklist /proc/sys/kernel/yama | ||
82 | blacklist /proc/sys/*/* | ||
diff --git a/etc/inc/whitelist-run-common.inc b/etc/inc/whitelist-run-common.inc index 224d21064..0d87657a9 100644 --- a/etc/inc/whitelist-run-common.inc +++ b/etc/inc/whitelist-run-common.inc | |||
@@ -7,5 +7,6 @@ whitelist /run/cups/cups.sock | |||
7 | whitelist /run/dbus/system_bus_socket | 7 | whitelist /run/dbus/system_bus_socket |
8 | whitelist /run/media | 8 | whitelist /run/media |
9 | whitelist /run/resolvconf/resolv.conf | 9 | whitelist /run/resolvconf/resolv.conf |
10 | whitelist /run/shm | ||
10 | whitelist /run/systemd/resolve/resolv.conf | 11 | whitelist /run/systemd/resolve/resolv.conf |
11 | whitelist /run/systemd/resolve/stub-resolv.conf | 12 | whitelist /run/systemd/resolve/stub-resolv.conf |
diff --git a/etc/profile-a-l/Books.profile b/etc/profile-a-l/Books.profile index 76fd21d32..a256e942f 100644 --- a/etc/profile-a-l/Books.profile +++ b/etc/profile-a-l/Books.profile | |||
@@ -1,5 +1,10 @@ | |||
1 | # Firejail profile for gnome-books | 1 | # Firejail profile for gnome-books |
2 | # This file is overwritten after every install/update | 2 | # This file is overwritten after every install/update |
3 | # Persistent local customizations | ||
4 | include Books.local | ||
5 | # Persistent global definitions | ||
6 | # added by included profile | ||
7 | #include globals.local | ||
3 | 8 | ||
4 | 9 | ||
5 | # Temporary fix for https://github.com/netblue30/firejail/issues/2624 | 10 | # Temporary fix for https://github.com/netblue30/firejail/issues/2624 |
diff --git a/etc/profile-a-l/alienarena.profile b/etc/profile-a-l/alienarena.profile index 62857a3e2..68512e37b 100644 --- a/etc/profile-a-l/alienarena.profile +++ b/etc/profile-a-l/alienarena.profile | |||
@@ -29,7 +29,6 @@ caps.drop all | |||
29 | netfilter | 29 | netfilter |
30 | nodvd | 30 | nodvd |
31 | nogroups | 31 | nogroups |
32 | noinput | ||
33 | nonewprivs | 32 | nonewprivs |
34 | noroot | 33 | noroot |
35 | notv | 34 | notv |
diff --git a/etc/profile-a-l/amarok.profile b/etc/profile-a-l/amarok.profile index e7b78f7d0..7d8ec481d 100644 --- a/etc/profile-a-l/amarok.profile +++ b/etc/profile-a-l/amarok.profile | |||
@@ -39,7 +39,7 @@ dbus-user.own org.kde.amarok | |||
39 | dbus-user.own org.mpris.amarok | 39 | dbus-user.own org.mpris.amarok |
40 | dbus-user.own org.mpris.MediaPlayer2.amarok | 40 | dbus-user.own org.mpris.MediaPlayer2.amarok |
41 | dbus-user.talk org.freedesktop.Notifications | 41 | dbus-user.talk org.freedesktop.Notifications |
42 | dbus-user.talk org.kde.StatusNotifierWatcher | 42 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher |
43 | # If you're not on kde-plasma add the next lines to your amarok.local. | 43 | # If you're not on kde-plasma add the next lines to your amarok.local. |
44 | #dbus-user.own org.kde.kded | 44 | #dbus-user.own org.kde.kded |
45 | #dbus-user.own org.kde.klauncher | 45 | #dbus-user.own org.kde.klauncher |
diff --git a/etc/profile-a-l/blobwars.profile b/etc/profile-a-l/blobwars.profile index 683a7858b..66f38b358 100644 --- a/etc/profile-a-l/blobwars.profile +++ b/etc/profile-a-l/blobwars.profile | |||
@@ -19,6 +19,7 @@ include disable-xdg.inc | |||
19 | mkdir ${HOME}/.parallelrealities/blobwars | 19 | mkdir ${HOME}/.parallelrealities/blobwars |
20 | whitelist ${HOME}/.parallelrealities/blobwars | 20 | whitelist ${HOME}/.parallelrealities/blobwars |
21 | whitelist /usr/share/blobwars | 21 | whitelist /usr/share/blobwars |
22 | whitelist /usr/share/games/blobwars | ||
22 | include whitelist-common.inc | 23 | include whitelist-common.inc |
23 | include whitelist-usr-share-common.inc | 24 | include whitelist-usr-share-common.inc |
24 | include whitelist-var-common.inc | 25 | include whitelist-var-common.inc |
@@ -28,7 +29,6 @@ caps.drop all | |||
28 | net none | 29 | net none |
29 | nodvd | 30 | nodvd |
30 | nogroups | 31 | nogroups |
31 | noinput | ||
32 | nonewprivs | 32 | nonewprivs |
33 | noroot | 33 | noroot |
34 | notv | 34 | notv |
diff --git a/etc/profile-a-l/flameshot.profile b/etc/profile-a-l/flameshot.profile index 5c7bc03d8..862ef6ab6 100644 --- a/etc/profile-a-l/flameshot.profile +++ b/etc/profile-a-l/flameshot.profile | |||
@@ -63,6 +63,6 @@ dbus-user.talk org.freedesktop.Notifications | |||
63 | dbus-user.talk org.freedesktop.portal.Desktop | 63 | dbus-user.talk org.freedesktop.portal.Desktop |
64 | dbus-user.talk org.gnome.Shell | 64 | dbus-user.talk org.gnome.Shell |
65 | dbus-user.talk org.kde.KWin | 65 | dbus-user.talk org.kde.KWin |
66 | dbus-user.talk org.kde.StatusNotifierWatcher | 66 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher |
67 | dbus-user.own org.kde.* | 67 | ?ALLOW_TRAY: dbus-user.own org.kde.* |
68 | dbus-system none | 68 | dbus-system none |
diff --git a/etc/profile-a-l/frozen-bubble.profile b/etc/profile-a-l/frozen-bubble.profile index bb35c9447..88943760a 100644 --- a/etc/profile-a-l/frozen-bubble.profile +++ b/etc/profile-a-l/frozen-bubble.profile | |||
@@ -30,7 +30,6 @@ caps.drop all | |||
30 | net none | 30 | net none |
31 | nodvd | 31 | nodvd |
32 | nogroups | 32 | nogroups |
33 | noinput | ||
34 | nonewprivs | 33 | nonewprivs |
35 | noroot | 34 | noroot |
36 | notv | 35 | notv |
diff --git a/etc/profile-a-l/funnyboat.profile b/etc/profile-a-l/funnyboat.profile index 1009f345b..4a08fca9b 100644 --- a/etc/profile-a-l/funnyboat.profile +++ b/etc/profile-a-l/funnyboat.profile | |||
@@ -35,7 +35,6 @@ ipc-namespace | |||
35 | netfilter | 35 | netfilter |
36 | nodvd | 36 | nodvd |
37 | nogroups | 37 | nogroups |
38 | noinput | ||
39 | nonewprivs | 38 | nonewprivs |
40 | noroot | 39 | noroot |
41 | notv | 40 | notv |
diff --git a/etc/profile-a-l/gl-117.profile b/etc/profile-a-l/gl-117.profile index 35d969e6d..edb85048b 100644 --- a/etc/profile-a-l/gl-117.profile +++ b/etc/profile-a-l/gl-117.profile | |||
@@ -29,7 +29,6 @@ caps.drop all | |||
29 | net none | 29 | net none |
30 | nodvd | 30 | nodvd |
31 | nogroups | 31 | nogroups |
32 | noinput | ||
33 | nonewprivs | 32 | nonewprivs |
34 | noroot | 33 | noroot |
35 | notv | 34 | notv |
diff --git a/etc/profile-a-l/glaxium.profile b/etc/profile-a-l/glaxium.profile index dec0daef2..b5f98b411 100644 --- a/etc/profile-a-l/glaxium.profile +++ b/etc/profile-a-l/glaxium.profile | |||
@@ -29,7 +29,6 @@ caps.drop all | |||
29 | net none | 29 | net none |
30 | nodvd | 30 | nodvd |
31 | nogroups | 31 | nogroups |
32 | noinput | ||
33 | nonewprivs | 32 | nonewprivs |
34 | noroot | 33 | noroot |
35 | notv | 34 | notv |
diff --git a/etc/profile-a-l/jumpnbump-menu.profile b/etc/profile-a-l/jumpnbump-menu.profile index 8d391b90f..59d762f55 100644 --- a/etc/profile-a-l/jumpnbump-menu.profile +++ b/etc/profile-a-l/jumpnbump-menu.profile | |||
@@ -10,7 +10,7 @@ include jumpnbump-menu.local | |||
10 | # Allow python (blacklisted by disable-interpreters.inc) | 10 | # Allow python (blacklisted by disable-interpreters.inc) |
11 | include allow-python3.inc | 11 | include allow-python3.inc |
12 | 12 | ||
13 | private-bin jumpnbump-menu,python3* | 13 | private-bin env,jumpnbump-menu,python3* |
14 | 14 | ||
15 | # Redirect | 15 | # Redirect |
16 | include jumpnbump.profile | 16 | include jumpnbump.profile |
diff --git a/etc/profile-a-l/jumpnbump.profile b/etc/profile-a-l/jumpnbump.profile index b9bc8f219..9726ff6fe 100644 --- a/etc/profile-a-l/jumpnbump.profile +++ b/etc/profile-a-l/jumpnbump.profile | |||
@@ -27,7 +27,6 @@ caps.drop all | |||
27 | net none | 27 | net none |
28 | nodvd | 28 | nodvd |
29 | nogroups | 29 | nogroups |
30 | noinput | ||
31 | nonewprivs | 30 | nonewprivs |
32 | noroot | 31 | noroot |
33 | notv | 32 | notv |
diff --git a/etc/profile-a-l/keepassxc.profile b/etc/profile-a-l/keepassxc.profile index 0f3e6605b..45a707071 100644 --- a/etc/profile-a-l/keepassxc.profile +++ b/etc/profile-a-l/keepassxc.profile | |||
@@ -98,11 +98,10 @@ dbus-user.talk org.freedesktop.ScreenSaver | |||
98 | dbus-user.talk org.gnome.ScreenSaver | 98 | dbus-user.talk org.gnome.ScreenSaver |
99 | dbus-user.talk org.gnome.SessionManager | 99 | dbus-user.talk org.gnome.SessionManager |
100 | dbus-user.talk org.xfce.ScreenSaver | 100 | dbus-user.talk org.xfce.ScreenSaver |
101 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher | ||
102 | ?ALLOW_TRAY: dbus-user.own org.kde.* | ||
101 | # Add the next line to your keepassxc.local to allow notifications. | 103 | # Add the next line to your keepassxc.local to allow notifications. |
102 | #dbus-user.talk org.freedesktop.Notifications | 104 | #dbus-user.talk org.freedesktop.Notifications |
103 | # Add the next line to your keepassxc.local to allow the tray menu. | ||
104 | #dbus-user.talk org.kde.StatusNotifierWatcher | ||
105 | #dbus-user.own org.kde.* | ||
106 | dbus-system filter | 105 | dbus-system filter |
107 | dbus-system.talk org.freedesktop.login1 | 106 | dbus-system.talk org.freedesktop.login1 |
108 | 107 | ||
diff --git a/etc/profile-m-z/mrrescue.profile b/etc/profile-m-z/mrrescue.profile index 16dc97d0c..5b5902563 100644 --- a/etc/profile-m-z/mrrescue.profile +++ b/etc/profile-m-z/mrrescue.profile | |||
@@ -37,7 +37,6 @@ caps.drop all | |||
37 | net none | 37 | net none |
38 | nodvd | 38 | nodvd |
39 | nogroups | 39 | nogroups |
40 | noinput | ||
41 | nonewprivs | 40 | nonewprivs |
42 | noroot | 41 | noroot |
43 | notv | 42 | notv |
diff --git a/etc/profile-m-z/neochat.profile b/etc/profile-m-z/neochat.profile index 58cc716d9..0f55b674f 100644 --- a/etc/profile-m-z/neochat.profile +++ b/etc/profile-m-z/neochat.profile | |||
@@ -60,6 +60,6 @@ private-tmp | |||
60 | dbus-user filter | 60 | dbus-user filter |
61 | dbus-user.own org.kde.neochat | 61 | dbus-user.own org.kde.neochat |
62 | dbus-user.talk org.freedesktop.Notifications | 62 | dbus-user.talk org.freedesktop.Notifications |
63 | dbus-user.talk org.kde.StatusNotifierWatcher | 63 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher |
64 | dbus-user.talk org.kde.kwalletd5 | 64 | dbus-user.talk org.kde.kwalletd5 |
65 | dbus-system none | 65 | dbus-system none |
diff --git a/etc/profile-m-z/nextcloud.profile b/etc/profile-m-z/nextcloud.profile index d0eef9704..354d3351e 100644 --- a/etc/profile-m-z/nextcloud.profile +++ b/etc/profile-m-z/nextcloud.profile | |||
@@ -67,6 +67,5 @@ private-tmp | |||
67 | 67 | ||
68 | dbus-user filter | 68 | dbus-user filter |
69 | dbus-user.talk org.freedesktop.secrets | 69 | dbus-user.talk org.freedesktop.secrets |
70 | # Add the next line to your nextcloud.local for tray icon support | 70 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher |
71 | #dbus-user.talk org.kde.StatusNotifierWatcher | ||
72 | dbus-system none | 71 | dbus-system none |
diff --git a/etc/profile-m-z/nheko.profile b/etc/profile-m-z/nheko.profile index 2f305dae9..89a146a09 100644 --- a/etc/profile-m-z/nheko.profile +++ b/etc/profile-m-z/nheko.profile | |||
@@ -53,8 +53,7 @@ private-tmp | |||
53 | 53 | ||
54 | dbus-user filter | 54 | dbus-user filter |
55 | dbus-user.talk org.freedesktop.secrets | 55 | dbus-user.talk org.freedesktop.secrets |
56 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher | ||
56 | # Add the next line to your nheko.local to enable notification support. | 57 | # Add the next line to your nheko.local to enable notification support. |
57 | #dbus-user.talk org.freedesktop.Notifications | 58 | #dbus-user.talk org.freedesktop.Notifications |
58 | # Add the next line to your nheko.local to enable tray icon support. | ||
59 | #dbus-user.talk org.kde.StatusNotifierWatcher | ||
60 | dbus-system none | 59 | dbus-system none |
diff --git a/etc/profile-m-z/open-invaders.profile b/etc/profile-m-z/open-invaders.profile index 12c7ea3d0..c2c22f42d 100644 --- a/etc/profile-m-z/open-invaders.profile +++ b/etc/profile-m-z/open-invaders.profile | |||
@@ -25,7 +25,6 @@ caps.drop all | |||
25 | net none | 25 | net none |
26 | nodvd | 26 | nodvd |
27 | nogroups | 27 | nogroups |
28 | noinput | ||
29 | nonewprivs | 28 | nonewprivs |
30 | noroot | 29 | noroot |
31 | notv | 30 | notv |
diff --git a/etc/profile-m-z/openclonk.profile b/etc/profile-m-z/openclonk.profile index 253465991..68362cbc8 100644 --- a/etc/profile-m-z/openclonk.profile +++ b/etc/profile-m-z/openclonk.profile | |||
@@ -28,7 +28,6 @@ ipc-namespace | |||
28 | netfilter | 28 | netfilter |
29 | nodvd | 29 | nodvd |
30 | nogroups | 30 | nogroups |
31 | noinput | ||
32 | nonewprivs | 31 | nonewprivs |
33 | noroot | 32 | noroot |
34 | notv | 33 | notv |
diff --git a/etc/profile-m-z/spectral.profile b/etc/profile-m-z/spectral.profile index 5f17b73dc..3f7f68009 100644 --- a/etc/profile-m-z/spectral.profile +++ b/etc/profile-m-z/spectral.profile | |||
@@ -49,10 +49,8 @@ private-dev | |||
49 | private-etc alsa,alternatives,asound.conf,ca-certificates,crypto-policies,fonts,gtk-2.0,gtk-3.0,host.conf,hostname,hosts,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,mime.types,nsswitch.conf,pki,pulse,resolv.conf,selinux,ssl,X11,xdg | 49 | private-etc alsa,alternatives,asound.conf,ca-certificates,crypto-policies,fonts,gtk-2.0,gtk-3.0,host.conf,hostname,hosts,ld.so.cache,ld.so.conf,ld.so.conf.d,ld.so.preload,locale,locale.alias,locale.conf,mime.types,nsswitch.conf,pki,pulse,resolv.conf,selinux,ssl,X11,xdg |
50 | private-tmp | 50 | private-tmp |
51 | 51 | ||
52 | dbus-user none | 52 | dbus-user filter |
53 | # Add the next lines to your spectral.local to enable notification support. | 53 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher |
54 | #ignore dbus-user none | 54 | # Add the next line to your spectral.local to enable notification support. |
55 | #dbus-user filter | ||
56 | #dbus-user.talk org.freedesktop.Notifications | 55 | #dbus-user.talk org.freedesktop.Notifications |
57 | #dbus-user.talk org.kde.StatusNotifierWatcher | ||
58 | dbus-system none | 56 | dbus-system none |
diff --git a/etc/profile-m-z/supertux2.profile b/etc/profile-m-z/supertux2.profile index 323849e35..d48065c4b 100644 --- a/etc/profile-m-z/supertux2.profile +++ b/etc/profile-m-z/supertux2.profile | |||
@@ -30,7 +30,6 @@ caps.drop all | |||
30 | net none | 30 | net none |
31 | nodvd | 31 | nodvd |
32 | nogroups | 32 | nogroups |
33 | noinput | ||
34 | nonewprivs | 33 | nonewprivs |
35 | noroot | 34 | noroot |
36 | notv | 35 | notv |
diff --git a/etc/profile-m-z/teeworlds.profile b/etc/profile-m-z/teeworlds.profile index df54fb9ba..d0fb0d43e 100644 --- a/etc/profile-m-z/teeworlds.profile +++ b/etc/profile-m-z/teeworlds.profile | |||
@@ -26,7 +26,6 @@ ipc-namespace | |||
26 | netfilter | 26 | netfilter |
27 | nodvd | 27 | nodvd |
28 | nogroups | 28 | nogroups |
29 | noinput | ||
30 | nonewprivs | 29 | nonewprivs |
31 | noroot | 30 | noroot |
32 | notv | 31 | notv |
diff --git a/etc/profile-m-z/telegram.profile b/etc/profile-m-z/telegram.profile index fd4b82524..dc1f77664 100644 --- a/etc/profile-m-z/telegram.profile +++ b/etc/profile-m-z/telegram.profile | |||
@@ -50,7 +50,7 @@ private-tmp | |||
50 | dbus-user filter | 50 | dbus-user filter |
51 | dbus-user.own org.telegram.desktop.* | 51 | dbus-user.own org.telegram.desktop.* |
52 | dbus-user.talk org.freedesktop.Notifications | 52 | dbus-user.talk org.freedesktop.Notifications |
53 | dbus-user.talk org.kde.StatusNotifierWatcher | 53 | ?ALLOW_TRAY: dbus-user.talk org.kde.StatusNotifierWatcher |
54 | dbus-user.talk org.gnome.Mutter.IdleMonitor | 54 | dbus-user.talk org.gnome.Mutter.IdleMonitor |
55 | dbus-user.talk org.freedesktop.ScreenSaver | 55 | dbus-user.talk org.freedesktop.ScreenSaver |
56 | dbus-system none | 56 | dbus-system none |
diff --git a/etc/profile-m-z/torcs.profile b/etc/profile-m-z/torcs.profile index a7ebaf2af..19e586db4 100644 --- a/etc/profile-m-z/torcs.profile +++ b/etc/profile-m-z/torcs.profile | |||
@@ -28,7 +28,6 @@ ipc-namespace | |||
28 | net none | 28 | net none |
29 | nodvd | 29 | nodvd |
30 | nogroups | 30 | nogroups |
31 | noinput | ||
32 | nonewprivs | 31 | nonewprivs |
33 | noroot | 32 | noroot |
34 | notv | 33 | notv |
diff --git a/etc/profile-m-z/tremulous.profile b/etc/profile-m-z/tremulous.profile index 4e16df553..96541ae25 100644 --- a/etc/profile-m-z/tremulous.profile +++ b/etc/profile-m-z/tremulous.profile | |||
@@ -8,6 +8,9 @@ include globals.local | |||
8 | 8 | ||
9 | noblacklist ${HOME}/.tremulous | 9 | noblacklist ${HOME}/.tremulous |
10 | 10 | ||
11 | # Allow /bin/sh (blacklisted by disable-shell.inc) | ||
12 | include allow-bin-sh.inc | ||
13 | |||
11 | include disable-common.inc | 14 | include disable-common.inc |
12 | include disable-devel.inc | 15 | include disable-devel.inc |
13 | include disable-exec.inc | 16 | include disable-exec.inc |
@@ -41,7 +44,7 @@ shell none | |||
41 | tracelog | 44 | tracelog |
42 | 45 | ||
43 | disable-mnt | 46 | disable-mnt |
44 | private-bin tremded,tremulous,tremulous-wrapper | 47 | private-bin env,sh,tremded,tremulous,tremulous-wrapper |
45 | private-cache | 48 | private-cache |
46 | private-dev | 49 | private-dev |
47 | private-tmp | 50 | private-tmp |
diff --git a/etc/profile-m-z/warsow.profile b/etc/profile-m-z/warsow.profile index 5659ec69c..2f818b733 100644 --- a/etc/profile-m-z/warsow.profile +++ b/etc/profile-m-z/warsow.profile | |||
@@ -11,6 +11,9 @@ ignore noexec ${HOME} | |||
11 | noblacklist ${HOME}/.cache/warsow-2.1 | 11 | noblacklist ${HOME}/.cache/warsow-2.1 |
12 | noblacklist ${HOME}/.local/share/warsow-2.1 | 12 | noblacklist ${HOME}/.local/share/warsow-2.1 |
13 | 13 | ||
14 | # Allow /bin/sh (blacklisted by disable-shell.inc) | ||
15 | include allow-bin-sh.inc | ||
16 | |||
14 | include disable-common.inc | 17 | include disable-common.inc |
15 | include disable-devel.inc | 18 | include disable-devel.inc |
16 | include disable-exec.inc | 19 | include disable-exec.inc |
@@ -34,19 +37,18 @@ ipc-namespace | |||
34 | netfilter | 37 | netfilter |
35 | nodvd | 38 | nodvd |
36 | nogroups | 39 | nogroups |
37 | noinput | ||
38 | nonewprivs | 40 | nonewprivs |
39 | noroot | 41 | noroot |
40 | notv | 42 | notv |
41 | nou2f | 43 | nou2f |
42 | novideo | 44 | novideo |
43 | protocol unix,inet,inet6 | 45 | protocol unix,inet,inet6,netlink |
44 | seccomp | 46 | seccomp |
45 | shell none | 47 | shell none |
46 | tracelog | 48 | tracelog |
47 | 49 | ||
48 | disable-mnt | 50 | disable-mnt |
49 | private-bin warsow | 51 | private-bin basename,bash,dirname,sed,sh,uname,warsow |
50 | private-cache | 52 | private-cache |
51 | private-dev | 53 | private-dev |
52 | private-tmp | 54 | private-tmp |
diff --git a/etc/profile-m-z/xonotic.profile b/etc/profile-m-z/xonotic.profile index 6ffe9ece9..7c2b38d1d 100644 --- a/etc/profile-m-z/xonotic.profile +++ b/etc/profile-m-z/xonotic.profile | |||
@@ -32,7 +32,6 @@ caps.drop all | |||
32 | netfilter | 32 | netfilter |
33 | nodvd | 33 | nodvd |
34 | nogroups | 34 | nogroups |
35 | noinput | ||
36 | nonewprivs | 35 | nonewprivs |
37 | noroot | 36 | noroot |
38 | notv | 37 | notv |
diff --git a/etc/templates/profile.template b/etc/templates/profile.template index 7628313e0..44197b547 100644 --- a/etc/templates/profile.template +++ b/etc/templates/profile.template | |||
@@ -116,6 +116,7 @@ include globals.local | |||
116 | #include disable-devel.inc | 116 | #include disable-devel.inc |
117 | #include disable-exec.inc | 117 | #include disable-exec.inc |
118 | #include disable-interpreters.inc | 118 | #include disable-interpreters.inc |
119 | #include disable-proc.inc | ||
119 | #include disable-programs.inc | 120 | #include disable-programs.inc |
120 | #include disable-shell.inc | 121 | #include disable-shell.inc |
121 | #include disable-write-mnt.inc | 122 | #include disable-write-mnt.inc |
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c index 8700e0ba1..a1847284c 100644 --- a/src/fbuilder/build_fs.c +++ b/src/fbuilder/build_fs.c | |||
@@ -236,9 +236,6 @@ void build_share(const char *fname, FILE *fp) { | |||
236 | //******************************************* | 236 | //******************************************* |
237 | static FileDB *tmp_out = NULL; | 237 | static FileDB *tmp_out = NULL; |
238 | static void tmp_callback(char *ptr) { | 238 | static void tmp_callback(char *ptr) { |
239 | // skip strace file | ||
240 | if (strncmp(ptr, "/tmp/firejail-strace", 20) == 0) | ||
241 | return; | ||
242 | if (strncmp(ptr, "/tmp/runtime-", 13) == 0) | 239 | if (strncmp(ptr, "/tmp/runtime-", 13) == 0) |
243 | return; | 240 | return; |
244 | if (strcmp(ptr, "/tmp") == 0) | 241 | if (strcmp(ptr, "/tmp") == 0) |
diff --git a/src/firejail/cgroup.c b/src/firejail/cgroup.c index e7ffbca36..38b3c32d3 100644 --- a/src/firejail/cgroup.c +++ b/src/firejail/cgroup.c | |||
@@ -18,7 +18,8 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/stat.h> | 21 | #include <sys/wait.h> |
22 | #include <errno.h> | ||
22 | 23 | ||
23 | #define MAXBUF 4096 | 24 | #define MAXBUF 4096 |
24 | 25 | ||
@@ -68,52 +69,60 @@ errout: | |||
68 | fclose(fp); | 69 | fclose(fp); |
69 | } | 70 | } |
70 | 71 | ||
72 | static int is_cgroup_path(const char *fname) { | ||
73 | // path starts with /sys/fs/cgroup | ||
74 | if (strncmp(fname, "/sys/fs/cgroup", 14) != 0) | ||
75 | return 0; | ||
71 | 76 | ||
72 | void set_cgroup(const char *path) { | 77 | // no .. traversal |
73 | EUID_ASSERT(); | 78 | char *ptr = strstr(fname, ".."); |
79 | if (ptr) | ||
80 | return 0; | ||
74 | 81 | ||
75 | invalid_filename(path, 0); // no globbing | 82 | return 1; |
83 | } | ||
76 | 84 | ||
77 | // path starts with /sys/fs/cgroup | 85 | void check_cgroup_file(const char *fname) { |
78 | if (strncmp(path, "/sys/fs/cgroup", 14) != 0) | 86 | assert(fname); |
79 | goto errout; | 87 | invalid_filename(fname, 0); // no globbing |
80 | 88 | ||
81 | // path ends in tasks | 89 | if (!is_cgroup_path(fname)) |
82 | char *ptr = strstr(path, "tasks"); | ||
83 | if (!ptr) | ||
84 | goto errout; | ||
85 | if (*(ptr + 5) != '\0') | ||
86 | goto errout; | 90 | goto errout; |
87 | 91 | ||
88 | // no .. traversal | 92 | const char *base = gnu_basename(fname); |
89 | ptr = strstr(path, ".."); | 93 | if (strcmp(base, "tasks") != 0 && // cgroup v1 |
90 | if (ptr) | 94 | strcmp(base, "cgroup.procs") != 0) |
91 | goto errout; | 95 | goto errout; |
92 | 96 | ||
93 | // tasks file exists | 97 | if (access(fname, W_OK) == 0) |
94 | FILE *fp = fopen(path, "ae"); | 98 | return; |
95 | if (!fp) | ||
96 | goto errout; | ||
97 | // task file belongs to the user running the sandbox | ||
98 | int fd = fileno(fp); | ||
99 | if (fd == -1) | ||
100 | errExit("fileno"); | ||
101 | struct stat s; | ||
102 | if (fstat(fd, &s) == -1) | ||
103 | errExit("fstat"); | ||
104 | if (s.st_uid != getuid() && s.st_gid != getgid()) | ||
105 | goto errout2; | ||
106 | // add the task to cgroup | ||
107 | pid_t pid = getpid(); | ||
108 | int rv = fprintf(fp, "%d\n", pid); | ||
109 | (void) rv; | ||
110 | fclose(fp); | ||
111 | return; | ||
112 | 99 | ||
113 | errout: | 100 | errout: |
114 | fprintf(stderr, "Error: invalid cgroup\n"); | 101 | fprintf(stderr, "Error: invalid cgroup\n"); |
115 | exit(1); | 102 | exit(1); |
116 | errout2: | 103 | } |
117 | fprintf(stderr, "Error: you don't have permissions to use this control group\n"); | 104 | |
118 | exit(1); | 105 | static void do_set_cgroup(const char *fname, pid_t pid) { |
106 | FILE *fp = fopen(fname, "ae"); | ||
107 | if (!fp) { | ||
108 | fwarning("cannot open %s for writing: %s\n", fname, strerror(errno)); | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | int rv = fprintf(fp, "%d\n", pid); | ||
113 | (void) rv; | ||
114 | fclose(fp); | ||
115 | } | ||
116 | |||
117 | void set_cgroup(const char *fname, pid_t pid) { | ||
118 | pid_t child = fork(); | ||
119 | if (child < 0) | ||
120 | errExit("fork"); | ||
121 | if (child == 0) { | ||
122 | drop_privs(0); | ||
123 | |||
124 | do_set_cgroup(fname, pid); | ||
125 | _exit(0); | ||
126 | } | ||
127 | waitpid(child, NULL, 0); | ||
119 | } | 128 | } |
diff --git a/src/firejail/chroot.c b/src/firejail/chroot.c index 37ec22117..9425638ea 100644 --- a/src/firejail/chroot.c +++ b/src/firejail/chroot.c | |||
@@ -86,7 +86,7 @@ static void update_file(int parentfd, const char *relpath) { | |||
86 | if (arg_debug) | 86 | if (arg_debug) |
87 | printf("Updating chroot /%s\n", relpath); | 87 | printf("Updating chroot /%s\n", relpath); |
88 | unlinkat(parentfd, relpath, 0); | 88 | unlinkat(parentfd, relpath, 0); |
89 | int out = openat(parentfd, relpath, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 89 | int out = openat(parentfd, relpath, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
90 | if (out == -1) { | 90 | if (out == -1) { |
91 | close(in); | 91 | close(in); |
92 | goto errout; | 92 | goto errout; |
diff --git a/src/firejail/env.c b/src/firejail/env.c index ad16de037..4c0d729a1 100644 --- a/src/firejail/env.c +++ b/src/firejail/env.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <unistd.h> | 23 | #include <unistd.h> |
24 | #include <dirent.h> | 24 | #include <dirent.h> |
25 | #include <limits.h> | ||
25 | 26 | ||
26 | typedef struct env_t { | 27 | typedef struct env_t { |
27 | struct env_t *next; | 28 | struct env_t *next; |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 730c37aed..a6924b830 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "../include/common.h" | 22 | #include "../include/common.h" |
23 | #include "../include/euid_common.h" | 23 | #include "../include/euid_common.h" |
24 | #include "../include/rundefs.h" | 24 | #include "../include/rundefs.h" |
25 | #include <linux/limits.h> // Note: Plain limits.h may break ARG_MAX (see #4583) | ||
25 | #include <stdarg.h> | 26 | #include <stdarg.h> |
26 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
27 | 28 | ||
@@ -433,13 +434,15 @@ void fs_proc_sys_dev_boot(void); | |||
433 | void disable_config(void); | 434 | void disable_config(void); |
434 | // build a basic read-only filesystem | 435 | // build a basic read-only filesystem |
435 | void fs_basic_fs(void); | 436 | void fs_basic_fs(void); |
436 | // mount overlayfs on top of / directory | ||
437 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse); | ||
438 | void fs_overlayfs(void); | ||
439 | void fs_private_tmp(void); | 437 | void fs_private_tmp(void); |
440 | void fs_private_cache(void); | 438 | void fs_private_cache(void); |
441 | void fs_mnt(const int enforce); | 439 | void fs_mnt(const int enforce); |
442 | 440 | ||
441 | // fs_overlayfs.c | ||
442 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse); | ||
443 | void fs_overlayfs(void); | ||
444 | int remove_overlay_directory(void); | ||
445 | |||
443 | // chroot.c | 446 | // chroot.c |
444 | // chroot into an existing directory; mount existing /dev and update /etc/resolv.conf | 447 | // chroot into an existing directory; mount existing /dev and update /etc/resolv.conf |
445 | void fs_check_chroot_dir(void); | 448 | void fs_check_chroot_dir(void); |
@@ -516,6 +519,7 @@ void touch_file_as_user(const char *fname, mode_t mode); | |||
516 | int is_dir(const char *fname); | 519 | int is_dir(const char *fname); |
517 | int is_link(const char *fname); | 520 | int is_link(const char *fname); |
518 | char *realpath_as_user(const char *fname); | 521 | char *realpath_as_user(const char *fname); |
522 | ssize_t readlink_as_user(const char *fname, char *buf, size_t sz); | ||
519 | int stat_as_user(const char *fname, struct stat *s); | 523 | int stat_as_user(const char *fname, struct stat *s); |
520 | int lstat_as_user(const char *fname, struct stat *s); | 524 | int lstat_as_user(const char *fname, struct stat *s); |
521 | void trim_trailing_slash_or_dot(char *path); | 525 | void trim_trailing_slash_or_dot(char *path); |
@@ -529,8 +533,7 @@ void update_map(char *mapping, char *map_file); | |||
529 | void wait_for_other(int fd); | 533 | void wait_for_other(int fd); |
530 | void notify_other(int fd); | 534 | void notify_other(int fd); |
531 | uid_t pid_get_uid(pid_t pid); | 535 | uid_t pid_get_uid(pid_t pid); |
532 | uid_t get_group_id(const char *group); | 536 | gid_t get_group_id(const char *groupname); |
533 | int remove_overlay_directory(void); | ||
534 | void flush_stdin(void); | 537 | void flush_stdin(void); |
535 | int create_empty_dir_as_user(const char *dir, mode_t mode); | 538 | int create_empty_dir_as_user(const char *dir, mode_t mode); |
536 | void create_empty_dir_as_root(const char *dir, mode_t mode); | 539 | void create_empty_dir_as_root(const char *dir, mode_t mode); |
@@ -564,7 +567,7 @@ typedef struct { | |||
564 | // mountinfo.c | 567 | // mountinfo.c |
565 | MountData *get_last_mount(void); | 568 | MountData *get_last_mount(void); |
566 | int get_mount_id(int fd); | 569 | int get_mount_id(int fd); |
567 | char **build_mount_array(const int mount_id, const char *path); | 570 | char **build_mount_array(const int mountid, const char *path); |
568 | 571 | ||
569 | // fs_var.c | 572 | // fs_var.c |
570 | void fs_var_log(void); // mounting /var/log | 573 | void fs_var_log(void); // mounting /var/log |
@@ -645,7 +648,8 @@ void cpu_print_filter(pid_t pid) __attribute__((noreturn)); | |||
645 | // cgroup.c | 648 | // cgroup.c |
646 | void save_cgroup(void); | 649 | void save_cgroup(void); |
647 | void load_cgroup(const char *fname); | 650 | void load_cgroup(const char *fname); |
648 | void set_cgroup(const char *path); | 651 | void check_cgroup_file(const char *fname); |
652 | void set_cgroup(const char *fname, pid_t pid); | ||
649 | 653 | ||
650 | // output.c | 654 | // output.c |
651 | void check_output(int argc, char **argv); | 655 | void check_output(int argc, char **argv); |
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index 3144156a3..9c1b889ed 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -20,10 +20,7 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include "../include/gcov_wrapper.h" | 21 | #include "../include/gcov_wrapper.h" |
22 | #include <sys/mount.h> | 22 | #include <sys/mount.h> |
23 | #include <sys/stat.h> | ||
24 | #include <sys/statvfs.h> | 23 | #include <sys/statvfs.h> |
25 | #include <sys/wait.h> | ||
26 | #include <linux/limits.h> | ||
27 | #include <fnmatch.h> | 24 | #include <fnmatch.h> |
28 | #include <glob.h> | 25 | #include <glob.h> |
29 | #include <dirent.h> | 26 | #include <dirent.h> |
@@ -35,7 +32,7 @@ | |||
35 | #endif | 32 | #endif |
36 | 33 | ||
37 | #define MAX_BUF 4096 | 34 | #define MAX_BUF 4096 |
38 | #define EMPTY_STRING ("") | 35 | |
39 | // check noblacklist statements not matched by a proper blacklist in disable-*.inc files | 36 | // check noblacklist statements not matched by a proper blacklist in disable-*.inc files |
40 | //#define TEST_NO_BLACKLIST_MATCHING | 37 | //#define TEST_NO_BLACKLIST_MATCHING |
41 | 38 | ||
@@ -657,12 +654,13 @@ static void fs_remount_rec(const char *path, OPERATION op) { | |||
657 | 654 | ||
658 | // build array with all mount points that need to get remounted | 655 | // build array with all mount points that need to get remounted |
659 | char **arr = build_mount_array(mountid, path); | 656 | char **arr = build_mount_array(mountid, path); |
660 | assert(arr); | 657 | if (!arr) |
658 | return; | ||
661 | // remount | 659 | // remount |
662 | char **tmp = arr; | 660 | int i; |
663 | while (*tmp) { | 661 | for (i = 0; arr[i]; i++) { |
664 | fs_remount_simple(*tmp, op); | 662 | fs_remount_simple(arr[i], op); |
665 | free(*tmp++); | 663 | free(arr[i]); |
666 | } | 664 | } |
667 | free(arr); | 665 | free(arr); |
668 | } | 666 | } |
@@ -897,367 +895,6 @@ void fs_basic_fs(void) { | |||
897 | } | 895 | } |
898 | 896 | ||
899 | 897 | ||
900 | |||
901 | #ifdef HAVE_OVERLAYFS | ||
902 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | ||
903 | assert(subdirname); | ||
904 | EUID_ASSERT(); | ||
905 | struct stat s; | ||
906 | char *dirname; | ||
907 | |||
908 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) | ||
909 | errExit("asprintf"); | ||
910 | // check if ~/.firejail already exists | ||
911 | if (lstat(dirname, &s) == 0) { | ||
912 | if (!S_ISDIR(s.st_mode)) { | ||
913 | if (S_ISLNK(s.st_mode)) | ||
914 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
915 | else | ||
916 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
917 | exit(1); | ||
918 | } | ||
919 | if (s.st_uid != getuid()) { | ||
920 | fprintf(stderr, "Error: %s is not owned by the current user\n", dirname); | ||
921 | exit(1); | ||
922 | } | ||
923 | } | ||
924 | else { | ||
925 | // create ~/.firejail directory | ||
926 | create_empty_dir_as_user(dirname, 0700); | ||
927 | if (stat(dirname, &s) == -1) { | ||
928 | fprintf(stderr, "Error: cannot create directory %s\n", dirname); | ||
929 | exit(1); | ||
930 | } | ||
931 | } | ||
932 | free(dirname); | ||
933 | |||
934 | // check overlay directory | ||
935 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) | ||
936 | errExit("asprintf"); | ||
937 | if (lstat(dirname, &s) == 0) { | ||
938 | if (!S_ISDIR(s.st_mode)) { | ||
939 | if (S_ISLNK(s.st_mode)) | ||
940 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
941 | else | ||
942 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
943 | exit(1); | ||
944 | } | ||
945 | if (s.st_uid != 0) { | ||
946 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", dirname); | ||
947 | exit(1); | ||
948 | } | ||
949 | if (allow_reuse == 0) { | ||
950 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | ||
951 | exit(1); | ||
952 | } | ||
953 | } | ||
954 | |||
955 | return dirname; | ||
956 | } | ||
957 | |||
958 | |||
959 | |||
960 | // mount overlayfs on top of / directory | ||
961 | // mounting an overlay and chrooting into it: | ||
962 | // | ||
963 | // Old Ubuntu kernel | ||
964 | // # cd ~ | ||
965 | // # mkdir -p overlay/root | ||
966 | // # mkdir -p overlay/diff | ||
967 | // # mount -t overlayfs -o lowerdir=/,upperdir=/root/overlay/diff overlayfs /root/overlay/root | ||
968 | // # chroot /root/overlay/root | ||
969 | // to shutdown, first exit the chroot and then unmount the overlay | ||
970 | // # exit | ||
971 | // # umount /root/overlay/root | ||
972 | // | ||
973 | // Kernels 3.18+ | ||
974 | // # cd ~ | ||
975 | // # mkdir -p overlay/root | ||
976 | // # mkdir -p overlay/diff | ||
977 | // # mkdir -p overlay/work | ||
978 | // # mount -t overlay -o lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work overlay /root/overlay/root | ||
979 | // # cat /etc/mtab | grep overlay | ||
980 | // /root/overlay /root/overlay/root overlay rw,relatime,lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work 0 0 | ||
981 | // # chroot /root/overlay/root | ||
982 | // to shutdown, first exit the chroot and then unmount the overlay | ||
983 | // # exit | ||
984 | // # umount /root/overlay/root | ||
985 | |||
986 | |||
987 | // to do: fix the code below; also, it might work without /dev, but consider keeping /dev/shm; add locking mechanism for overlay-clean | ||
988 | #include <sys/utsname.h> | ||
989 | void fs_overlayfs(void) { | ||
990 | struct stat s; | ||
991 | |||
992 | // check kernel version | ||
993 | struct utsname u; | ||
994 | int rv = uname(&u); | ||
995 | if (rv != 0) | ||
996 | errExit("uname"); | ||
997 | int major; | ||
998 | int minor; | ||
999 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
1000 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
1001 | exit(1); | ||
1002 | } | ||
1003 | |||
1004 | if (arg_debug) | ||
1005 | printf("Linux kernel version %d.%d\n", major, minor); | ||
1006 | int oldkernel = 0; | ||
1007 | if (major < 3) { | ||
1008 | fprintf(stderr, "Error: minimum kernel version required 3.x\n"); | ||
1009 | exit(1); | ||
1010 | } | ||
1011 | if (major == 3 && minor < 18) | ||
1012 | oldkernel = 1; | ||
1013 | |||
1014 | // mounting an overlayfs on top of / seems to be broken for kernels > 4.19 | ||
1015 | // we disable overlayfs for now, pending fixing | ||
1016 | if (major >= 4 &&minor >= 19) { | ||
1017 | fprintf(stderr, "Error: OverlayFS disabled for Linux kernels 4.19 and newer, pending fixing.\n"); | ||
1018 | exit(1); | ||
1019 | } | ||
1020 | |||
1021 | char *oroot = RUN_OVERLAY_ROOT; | ||
1022 | mkdir_attr(oroot, 0755, 0, 0); | ||
1023 | |||
1024 | // set base for working and diff directories | ||
1025 | char *basedir = RUN_MNT_DIR; | ||
1026 | int basefd = -1; | ||
1027 | |||
1028 | if (arg_overlay_keep) { | ||
1029 | basedir = cfg.overlay_dir; | ||
1030 | assert(basedir); | ||
1031 | // get a file descriptor for ~/.firejail, fails if there is any symlink | ||
1032 | char *firejail; | ||
1033 | if (asprintf(&firejail, "%s/.firejail", cfg.homedir) == -1) | ||
1034 | errExit("asprintf"); | ||
1035 | int fd = safer_openat(-1, firejail, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1036 | if (fd == -1) | ||
1037 | errExit("safer_openat"); | ||
1038 | free(firejail); | ||
1039 | // create basedir if it doesn't exist | ||
1040 | // the new directory will be owned by root | ||
1041 | const char *dirname = gnu_basename(basedir); | ||
1042 | if (mkdirat(fd, dirname, 0755) == -1 && errno != EEXIST) { | ||
1043 | perror("mkdir"); | ||
1044 | fprintf(stderr, "Error: cannot create overlay directory %s\n", basedir); | ||
1045 | exit(1); | ||
1046 | } | ||
1047 | // open basedir | ||
1048 | basefd = openat(fd, dirname, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1049 | close(fd); | ||
1050 | } | ||
1051 | else { | ||
1052 | basefd = open(basedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
1053 | } | ||
1054 | if (basefd == -1) { | ||
1055 | perror("open"); | ||
1056 | fprintf(stderr, "Error: cannot open overlay directory %s\n", basedir); | ||
1057 | exit(1); | ||
1058 | } | ||
1059 | |||
1060 | // confirm once more base is owned by root | ||
1061 | if (fstat(basefd, &s) == -1) | ||
1062 | errExit("fstat"); | ||
1063 | if (s.st_uid != 0) { | ||
1064 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", basedir); | ||
1065 | exit(1); | ||
1066 | } | ||
1067 | // confirm permissions of base are 0755 | ||
1068 | if (((S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) & s.st_mode) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) { | ||
1069 | fprintf(stderr, "Error: invalid permissions on overlay directory %s\n", basedir); | ||
1070 | exit(1); | ||
1071 | } | ||
1072 | |||
1073 | // create diff and work directories inside base | ||
1074 | // no need to check arg_overlay_reuse | ||
1075 | char *odiff; | ||
1076 | if (asprintf(&odiff, "%s/odiff", basedir) == -1) | ||
1077 | errExit("asprintf"); | ||
1078 | // the new directory will be owned by root | ||
1079 | if (mkdirat(basefd, "odiff", 0755) == -1 && errno != EEXIST) { | ||
1080 | perror("mkdir"); | ||
1081 | fprintf(stderr, "Error: cannot create overlay directory %s\n", odiff); | ||
1082 | exit(1); | ||
1083 | } | ||
1084 | ASSERT_PERMS(odiff, 0, 0, 0755); | ||
1085 | |||
1086 | char *owork; | ||
1087 | if (asprintf(&owork, "%s/owork", basedir) == -1) | ||
1088 | errExit("asprintf"); | ||
1089 | // the new directory will be owned by root | ||
1090 | if (mkdirat(basefd, "owork", 0755) == -1 && errno != EEXIST) { | ||
1091 | perror("mkdir"); | ||
1092 | fprintf(stderr, "Error: cannot create overlay directory %s\n", owork); | ||
1093 | exit(1); | ||
1094 | } | ||
1095 | ASSERT_PERMS(owork, 0, 0, 0755); | ||
1096 | |||
1097 | // mount overlayfs | ||
1098 | if (arg_debug) | ||
1099 | printf("Mounting OverlayFS\n"); | ||
1100 | char *option; | ||
1101 | if (oldkernel) { // old Ubuntu/OpenSUSE kernels | ||
1102 | if (arg_overlay_keep) { | ||
1103 | fprintf(stderr, "Error: option --overlay= not available for kernels older than 3.18\n"); | ||
1104 | exit(1); | ||
1105 | } | ||
1106 | if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) | ||
1107 | errExit("asprintf"); | ||
1108 | if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) | ||
1109 | errExit("mounting overlayfs"); | ||
1110 | } | ||
1111 | else { // kernel 3.18 or newer | ||
1112 | if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) | ||
1113 | errExit("asprintf"); | ||
1114 | if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) { | ||
1115 | fprintf(stderr, "Debug: running on kernel version %d.%d\n", major, minor); | ||
1116 | errExit("mounting overlayfs"); | ||
1117 | } | ||
1118 | |||
1119 | //*************************** | ||
1120 | // issue #263 start code | ||
1121 | // My setup has a separate mount point for /home. When the overlay is mounted, | ||
1122 | // the overlay does not contain the original /home contents. | ||
1123 | // I added code to create a second overlay for /home if the overlay home dir is empty and this seems to work | ||
1124 | // @dshmgh, Jan 2016 | ||
1125 | { | ||
1126 | char *overlayhome; | ||
1127 | struct stat s; | ||
1128 | char *hroot; | ||
1129 | char *hdiff; | ||
1130 | char *hwork; | ||
1131 | |||
1132 | // dons add debug | ||
1133 | if (arg_debug) printf ("DEBUG: chroot dirs are oroot %s odiff %s owork %s\n",oroot,odiff,owork); | ||
1134 | |||
1135 | // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? | ||
1136 | // must create var for oroot/cfg.homedir | ||
1137 | if (asprintf(&overlayhome, "%s%s", oroot, cfg.homedir) == -1) | ||
1138 | errExit("asprintf"); | ||
1139 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n", overlayhome); | ||
1140 | |||
1141 | // if no homedir in overlay -- create another overlay for /home | ||
1142 | if (stat(cfg.homedir, &s) == 0 && stat(overlayhome, &s) == -1) { | ||
1143 | |||
1144 | // no need to check arg_overlay_reuse | ||
1145 | if (asprintf(&hdiff, "%s/hdiff", basedir) == -1) | ||
1146 | errExit("asprintf"); | ||
1147 | // the new directory will be owned by root | ||
1148 | if (mkdirat(basefd, "hdiff", 0755) == -1 && errno != EEXIST) { | ||
1149 | perror("mkdir"); | ||
1150 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hdiff); | ||
1151 | exit(1); | ||
1152 | } | ||
1153 | ASSERT_PERMS(hdiff, 0, 0, 0755); | ||
1154 | |||
1155 | // no need to check arg_overlay_reuse | ||
1156 | if (asprintf(&hwork, "%s/hwork", basedir) == -1) | ||
1157 | errExit("asprintf"); | ||
1158 | // the new directory will be owned by root | ||
1159 | if (mkdirat(basefd, "hwork", 0755) == -1 && errno != EEXIST) { | ||
1160 | perror("mkdir"); | ||
1161 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hwork); | ||
1162 | exit(1); | ||
1163 | } | ||
1164 | ASSERT_PERMS(hwork, 0, 0, 0755); | ||
1165 | |||
1166 | // no homedir in overlay so now mount another overlay for /home | ||
1167 | if (asprintf(&hroot, "%s/home", oroot) == -1) | ||
1168 | errExit("asprintf"); | ||
1169 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) | ||
1170 | errExit("asprintf"); | ||
1171 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) | ||
1172 | errExit("mounting overlayfs for mounted home directory"); | ||
1173 | |||
1174 | printf("OverlayFS for /home configured in %s directory\n", basedir); | ||
1175 | free(hroot); | ||
1176 | free(hdiff); | ||
1177 | free(hwork); | ||
1178 | |||
1179 | } // stat(overlayhome) | ||
1180 | free(overlayhome); | ||
1181 | } | ||
1182 | // issue #263 end code | ||
1183 | //*************************** | ||
1184 | } | ||
1185 | fmessage("OverlayFS configured in %s directory\n", basedir); | ||
1186 | close(basefd); | ||
1187 | |||
1188 | // /dev, /run and /tmp are not covered by the overlay | ||
1189 | // mount-bind dev directory | ||
1190 | if (arg_debug) | ||
1191 | printf("Mounting /dev\n"); | ||
1192 | char *dev; | ||
1193 | if (asprintf(&dev, "%s/dev", oroot) == -1) | ||
1194 | errExit("asprintf"); | ||
1195 | if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1196 | errExit("mounting /dev"); | ||
1197 | fs_logger("whitelist /dev"); | ||
1198 | |||
1199 | // mount-bind run directory | ||
1200 | if (arg_debug) | ||
1201 | printf("Mounting /run\n"); | ||
1202 | char *run; | ||
1203 | if (asprintf(&run, "%s/run", oroot) == -1) | ||
1204 | errExit("asprintf"); | ||
1205 | if (mount("/run", run, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1206 | errExit("mounting /run"); | ||
1207 | fs_logger("whitelist /run"); | ||
1208 | |||
1209 | // mount-bind tmp directory | ||
1210 | if (arg_debug) | ||
1211 | printf("Mounting /tmp\n"); | ||
1212 | char *tmp; | ||
1213 | if (asprintf(&tmp, "%s/tmp", oroot) == -1) | ||
1214 | errExit("asprintf"); | ||
1215 | if (mount("/tmp", tmp, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
1216 | errExit("mounting /tmp"); | ||
1217 | fs_logger("whitelist /tmp"); | ||
1218 | |||
1219 | // chroot in the new filesystem | ||
1220 | __gcov_flush(); | ||
1221 | |||
1222 | if (chroot(oroot) == -1) | ||
1223 | errExit("chroot"); | ||
1224 | |||
1225 | // mount a new proc filesystem | ||
1226 | if (arg_debug) | ||
1227 | printf("Mounting /proc filesystem representing the PID namespace\n"); | ||
1228 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | ||
1229 | errExit("mounting /proc"); | ||
1230 | |||
1231 | // update /var directory in order to support multiple sandboxes running on the same root directory | ||
1232 | // if (!arg_private_dev) | ||
1233 | // fs_dev_shm(); | ||
1234 | fs_var_lock(); | ||
1235 | if (!arg_keep_var_tmp) | ||
1236 | fs_var_tmp(); | ||
1237 | if (!arg_writable_var_log) | ||
1238 | fs_var_log(); | ||
1239 | fs_var_lib(); | ||
1240 | fs_var_cache(); | ||
1241 | fs_var_utmp(); | ||
1242 | fs_machineid(); | ||
1243 | |||
1244 | // don't leak user information | ||
1245 | restrict_users(); | ||
1246 | |||
1247 | // when starting as root, firejail config is not disabled; | ||
1248 | if (getuid() != 0) | ||
1249 | disable_config(); | ||
1250 | |||
1251 | // cleanup and exit | ||
1252 | free(option); | ||
1253 | free(odiff); | ||
1254 | free(owork); | ||
1255 | free(dev); | ||
1256 | free(run); | ||
1257 | free(tmp); | ||
1258 | } | ||
1259 | #endif | ||
1260 | |||
1261 | // this function is called from sandbox.c before blacklist/whitelist functions | 898 | // this function is called from sandbox.c before blacklist/whitelist functions |
1262 | void fs_private_tmp(void) { | 899 | void fs_private_tmp(void) { |
1263 | EUID_ASSERT(); | 900 | EUID_ASSERT(); |
@@ -1281,7 +918,6 @@ void fs_private_tmp(void) { | |||
1281 | 918 | ||
1282 | // whitelist x11 directory | 919 | // whitelist x11 directory |
1283 | profile_add("whitelist /tmp/.X11-unix"); | 920 | profile_add("whitelist /tmp/.X11-unix"); |
1284 | // read-only x11 directory | ||
1285 | profile_add("read-only /tmp/.X11-unix"); | 921 | profile_add("read-only /tmp/.X11-unix"); |
1286 | 922 | ||
1287 | // whitelist sndio directory | 923 | // whitelist sndio directory |
diff --git a/src/firejail/fs_dev.c b/src/firejail/fs_dev.c index a43b18344..694d0a379 100644 --- a/src/firejail/fs_dev.c +++ b/src/firejail/fs_dev.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index 590337da1..8d8530d81 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -19,7 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <linux/limits.h> | ||
23 | #include <dirent.h> | 22 | #include <dirent.h> |
24 | #include <errno.h> | 23 | #include <errno.h> |
25 | #include <sys/stat.h> | 24 | #include <sys/stat.h> |
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c index 7d320e90b..8b7e94f51 100644 --- a/src/firejail/fs_hostname.c +++ b/src/firejail/fs_hostname.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
@@ -33,7 +32,7 @@ void fs_hostname(const char *hostname) { | |||
33 | if (arg_debug) | 32 | if (arg_debug) |
34 | printf("Creating a new /etc/hostname file\n"); | 33 | printf("Creating a new /etc/hostname file\n"); |
35 | 34 | ||
36 | create_empty_file_as_root(RUN_HOSTNAME_FILE, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 35 | create_empty_file_as_root(RUN_HOSTNAME_FILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
37 | 36 | ||
38 | // bind-mount the file on top of /etc/hostname | 37 | // bind-mount the file on top of /etc/hostname |
39 | if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) | 38 | if (mount(RUN_HOSTNAME_FILE, "/etc/hostname", NULL, MS_BIND|MS_REC, NULL) < 0) |
@@ -75,7 +74,7 @@ void fs_hostname(const char *hostname) { | |||
75 | } | 74 | } |
76 | fclose(fp1); | 75 | fclose(fp1); |
77 | // mode and owner | 76 | // mode and owner |
78 | SET_PERMS_STREAM(fp2, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 77 | SET_PERMS_STREAM(fp2, 0, 0, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
79 | fclose(fp2); | 78 | fclose(fp2); |
80 | 79 | ||
81 | // bind-mount the file on top of /etc/hostname | 80 | // bind-mount the file on top of /etc/hostname |
diff --git a/src/firejail/fs_overlayfs.c b/src/firejail/fs_overlayfs.c new file mode 100644 index 000000000..fe3761cb6 --- /dev/null +++ b/src/firejail/fs_overlayfs.c | |||
@@ -0,0 +1,470 @@ | |||
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 | |||
21 | #ifdef HAVE_OVERLAYFS | ||
22 | #include "firejail.h" | ||
23 | #include "../include/gcov_wrapper.h" | ||
24 | #include <sys/mount.h> | ||
25 | #include <sys/wait.h> | ||
26 | #include <ftw.h> | ||
27 | #include <errno.h> | ||
28 | |||
29 | #include <fcntl.h> | ||
30 | #ifndef O_PATH | ||
31 | #define O_PATH 010000000 | ||
32 | #endif | ||
33 | |||
34 | |||
35 | char *fs_check_overlay_dir(const char *subdirname, int allow_reuse) { | ||
36 | assert(subdirname); | ||
37 | EUID_ASSERT(); | ||
38 | struct stat s; | ||
39 | char *dirname; | ||
40 | |||
41 | if (asprintf(&dirname, "%s/.firejail", cfg.homedir) == -1) | ||
42 | errExit("asprintf"); | ||
43 | // check if ~/.firejail already exists | ||
44 | if (lstat(dirname, &s) == 0) { | ||
45 | if (!S_ISDIR(s.st_mode)) { | ||
46 | if (S_ISLNK(s.st_mode)) | ||
47 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
48 | else | ||
49 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
50 | exit(1); | ||
51 | } | ||
52 | if (s.st_uid != getuid()) { | ||
53 | fprintf(stderr, "Error: %s is not owned by the current user\n", dirname); | ||
54 | exit(1); | ||
55 | } | ||
56 | } | ||
57 | else { | ||
58 | // create ~/.firejail directory | ||
59 | create_empty_dir_as_user(dirname, 0700); | ||
60 | if (stat(dirname, &s) == -1) { | ||
61 | fprintf(stderr, "Error: cannot create directory %s\n", dirname); | ||
62 | exit(1); | ||
63 | } | ||
64 | } | ||
65 | free(dirname); | ||
66 | |||
67 | // check overlay directory | ||
68 | if (asprintf(&dirname, "%s/.firejail/%s", cfg.homedir, subdirname) == -1) | ||
69 | errExit("asprintf"); | ||
70 | if (lstat(dirname, &s) == 0) { | ||
71 | if (!S_ISDIR(s.st_mode)) { | ||
72 | if (S_ISLNK(s.st_mode)) | ||
73 | fprintf(stderr, "Error: %s is a symbolic link\n", dirname); | ||
74 | else | ||
75 | fprintf(stderr, "Error: %s is not a directory\n", dirname); | ||
76 | exit(1); | ||
77 | } | ||
78 | if (s.st_uid != 0) { | ||
79 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", dirname); | ||
80 | exit(1); | ||
81 | } | ||
82 | if (allow_reuse == 0) { | ||
83 | fprintf(stderr, "Error: overlay directory exists, but reuse is not allowed\n"); | ||
84 | exit(1); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | return dirname; | ||
89 | } | ||
90 | |||
91 | |||
92 | // mount overlayfs on top of / directory | ||
93 | // mounting an overlay and chrooting into it: | ||
94 | // | ||
95 | // Old Ubuntu kernel | ||
96 | // # cd ~ | ||
97 | // # mkdir -p overlay/root | ||
98 | // # mkdir -p overlay/diff | ||
99 | // # mount -t overlayfs -o lowerdir=/,upperdir=/root/overlay/diff overlayfs /root/overlay/root | ||
100 | // # chroot /root/overlay/root | ||
101 | // to shutdown, first exit the chroot and then unmount the overlay | ||
102 | // # exit | ||
103 | // # umount /root/overlay/root | ||
104 | // | ||
105 | // Kernels 3.18+ | ||
106 | // # cd ~ | ||
107 | // # mkdir -p overlay/root | ||
108 | // # mkdir -p overlay/diff | ||
109 | // # mkdir -p overlay/work | ||
110 | // # mount -t overlay -o lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work overlay /root/overlay/root | ||
111 | // # cat /etc/mtab | grep overlay | ||
112 | // /root/overlay /root/overlay/root overlay rw,relatime,lowerdir=/,upperdir=/root/overlay/diff,workdir=/root/overlay/work 0 0 | ||
113 | // # chroot /root/overlay/root | ||
114 | // to shutdown, first exit the chroot and then unmount the overlay | ||
115 | // # exit | ||
116 | // # umount /root/overlay/root | ||
117 | |||
118 | // to do: fix the code below | ||
119 | #include <sys/utsname.h> | ||
120 | void fs_overlayfs(void) { | ||
121 | struct stat s; | ||
122 | |||
123 | // check kernel version | ||
124 | struct utsname u; | ||
125 | int rv = uname(&u); | ||
126 | if (rv != 0) | ||
127 | errExit("uname"); | ||
128 | int major; | ||
129 | int minor; | ||
130 | if (2 != sscanf(u.release, "%d.%d", &major, &minor)) { | ||
131 | fprintf(stderr, "Error: cannot extract Linux kernel version: %s\n", u.version); | ||
132 | exit(1); | ||
133 | } | ||
134 | |||
135 | if (arg_debug) | ||
136 | printf("Linux kernel version %d.%d\n", major, minor); | ||
137 | int oldkernel = 0; | ||
138 | if (major < 3) { | ||
139 | fprintf(stderr, "Error: minimum kernel version required 3.x\n"); | ||
140 | exit(1); | ||
141 | } | ||
142 | if (major == 3 && minor < 18) | ||
143 | oldkernel = 1; | ||
144 | |||
145 | // mounting an overlayfs on top of / seems to be broken for kernels > 4.19 | ||
146 | // we disable overlayfs for now, pending fixing | ||
147 | if (major >= 4 &&minor >= 19) { | ||
148 | fprintf(stderr, "Error: OverlayFS disabled for Linux kernels 4.19 and newer, pending fixing.\n"); | ||
149 | exit(1); | ||
150 | } | ||
151 | |||
152 | char *oroot = RUN_OVERLAY_ROOT; | ||
153 | mkdir_attr(oroot, 0755, 0, 0); | ||
154 | |||
155 | // set base for working and diff directories | ||
156 | char *basedir = RUN_MNT_DIR; | ||
157 | int basefd = -1; | ||
158 | |||
159 | if (arg_overlay_keep) { | ||
160 | basedir = cfg.overlay_dir; | ||
161 | assert(basedir); | ||
162 | // get a file descriptor for ~/.firejail, fails if there is any symlink | ||
163 | char *firejail; | ||
164 | if (asprintf(&firejail, "%s/.firejail", cfg.homedir) == -1) | ||
165 | errExit("asprintf"); | ||
166 | int fd = safer_openat(-1, firejail, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
167 | if (fd == -1) | ||
168 | errExit("safer_openat"); | ||
169 | free(firejail); | ||
170 | // create basedir if it doesn't exist | ||
171 | // the new directory will be owned by root | ||
172 | const char *dirname = gnu_basename(basedir); | ||
173 | if (mkdirat(fd, dirname, 0755) == -1 && errno != EEXIST) { | ||
174 | perror("mkdir"); | ||
175 | fprintf(stderr, "Error: cannot create overlay directory %s\n", basedir); | ||
176 | exit(1); | ||
177 | } | ||
178 | // open basedir | ||
179 | basefd = openat(fd, dirname, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
180 | close(fd); | ||
181 | } | ||
182 | else { | ||
183 | basefd = open(basedir, O_PATH|O_DIRECTORY|O_NOFOLLOW|O_CLOEXEC); | ||
184 | } | ||
185 | if (basefd == -1) { | ||
186 | perror("open"); | ||
187 | fprintf(stderr, "Error: cannot open overlay directory %s\n", basedir); | ||
188 | exit(1); | ||
189 | } | ||
190 | |||
191 | // confirm once more base is owned by root | ||
192 | if (fstat(basefd, &s) == -1) | ||
193 | errExit("fstat"); | ||
194 | if (s.st_uid != 0) { | ||
195 | fprintf(stderr, "Error: overlay directory %s is not owned by the root user\n", basedir); | ||
196 | exit(1); | ||
197 | } | ||
198 | // confirm permissions of base are 0755 | ||
199 | if (((S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) & s.st_mode) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) { | ||
200 | fprintf(stderr, "Error: invalid permissions on overlay directory %s\n", basedir); | ||
201 | exit(1); | ||
202 | } | ||
203 | |||
204 | // create diff and work directories inside base | ||
205 | // no need to check arg_overlay_reuse | ||
206 | char *odiff; | ||
207 | if (asprintf(&odiff, "%s/odiff", basedir) == -1) | ||
208 | errExit("asprintf"); | ||
209 | // the new directory will be owned by root | ||
210 | if (mkdirat(basefd, "odiff", 0755) == -1 && errno != EEXIST) { | ||
211 | perror("mkdir"); | ||
212 | fprintf(stderr, "Error: cannot create overlay directory %s\n", odiff); | ||
213 | exit(1); | ||
214 | } | ||
215 | ASSERT_PERMS(odiff, 0, 0, 0755); | ||
216 | |||
217 | char *owork; | ||
218 | if (asprintf(&owork, "%s/owork", basedir) == -1) | ||
219 | errExit("asprintf"); | ||
220 | // the new directory will be owned by root | ||
221 | if (mkdirat(basefd, "owork", 0755) == -1 && errno != EEXIST) { | ||
222 | perror("mkdir"); | ||
223 | fprintf(stderr, "Error: cannot create overlay directory %s\n", owork); | ||
224 | exit(1); | ||
225 | } | ||
226 | ASSERT_PERMS(owork, 0, 0, 0755); | ||
227 | |||
228 | // mount overlayfs | ||
229 | if (arg_debug) | ||
230 | printf("Mounting OverlayFS\n"); | ||
231 | char *option; | ||
232 | if (oldkernel) { // old Ubuntu/OpenSUSE kernels | ||
233 | if (arg_overlay_keep) { | ||
234 | fprintf(stderr, "Error: option --overlay= not available for kernels older than 3.18\n"); | ||
235 | exit(1); | ||
236 | } | ||
237 | if (asprintf(&option, "lowerdir=/,upperdir=%s", odiff) == -1) | ||
238 | errExit("asprintf"); | ||
239 | if (mount("overlayfs", oroot, "overlayfs", MS_MGC_VAL, option) < 0) | ||
240 | errExit("mounting overlayfs"); | ||
241 | } | ||
242 | else { // kernel 3.18 or newer | ||
243 | if (asprintf(&option, "lowerdir=/,upperdir=%s,workdir=%s", odiff, owork) == -1) | ||
244 | errExit("asprintf"); | ||
245 | if (mount("overlay", oroot, "overlay", MS_MGC_VAL, option) < 0) { | ||
246 | fprintf(stderr, "Debug: running on kernel version %d.%d\n", major, minor); | ||
247 | errExit("mounting overlayfs"); | ||
248 | } | ||
249 | |||
250 | //*************************** | ||
251 | // issue #263 start code | ||
252 | // My setup has a separate mount point for /home. When the overlay is mounted, | ||
253 | // the overlay does not contain the original /home contents. | ||
254 | // I added code to create a second overlay for /home if the overlay home dir is empty and this seems to work | ||
255 | // @dshmgh, Jan 2016 | ||
256 | { | ||
257 | char *overlayhome; | ||
258 | struct stat s; | ||
259 | char *hroot; | ||
260 | char *hdiff; | ||
261 | char *hwork; | ||
262 | |||
263 | // dons add debug | ||
264 | if (arg_debug) printf ("DEBUG: chroot dirs are oroot %s odiff %s owork %s\n",oroot,odiff,owork); | ||
265 | |||
266 | // BEFORE NEXT, WE NEED TO TEST IF /home has any contents or do we need to mount it? | ||
267 | // must create var for oroot/cfg.homedir | ||
268 | if (asprintf(&overlayhome, "%s%s", oroot, cfg.homedir) == -1) | ||
269 | errExit("asprintf"); | ||
270 | if (arg_debug) printf ("DEBUG: overlayhome var holds ##%s##\n", overlayhome); | ||
271 | |||
272 | // if no homedir in overlay -- create another overlay for /home | ||
273 | if (stat(cfg.homedir, &s) == 0 && stat(overlayhome, &s) == -1) { | ||
274 | |||
275 | // no need to check arg_overlay_reuse | ||
276 | if (asprintf(&hdiff, "%s/hdiff", basedir) == -1) | ||
277 | errExit("asprintf"); | ||
278 | // the new directory will be owned by root | ||
279 | if (mkdirat(basefd, "hdiff", 0755) == -1 && errno != EEXIST) { | ||
280 | perror("mkdir"); | ||
281 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hdiff); | ||
282 | exit(1); | ||
283 | } | ||
284 | ASSERT_PERMS(hdiff, 0, 0, 0755); | ||
285 | |||
286 | // no need to check arg_overlay_reuse | ||
287 | if (asprintf(&hwork, "%s/hwork", basedir) == -1) | ||
288 | errExit("asprintf"); | ||
289 | // the new directory will be owned by root | ||
290 | if (mkdirat(basefd, "hwork", 0755) == -1 && errno != EEXIST) { | ||
291 | perror("mkdir"); | ||
292 | fprintf(stderr, "Error: cannot create overlay directory %s\n", hwork); | ||
293 | exit(1); | ||
294 | } | ||
295 | ASSERT_PERMS(hwork, 0, 0, 0755); | ||
296 | |||
297 | // no homedir in overlay so now mount another overlay for /home | ||
298 | if (asprintf(&hroot, "%s/home", oroot) == -1) | ||
299 | errExit("asprintf"); | ||
300 | if (asprintf(&option, "lowerdir=/home,upperdir=%s,workdir=%s", hdiff, hwork) == -1) | ||
301 | errExit("asprintf"); | ||
302 | if (mount("overlay", hroot, "overlay", MS_MGC_VAL, option) < 0) | ||
303 | errExit("mounting overlayfs for mounted home directory"); | ||
304 | |||
305 | printf("OverlayFS for /home configured in %s directory\n", basedir); | ||
306 | free(hroot); | ||
307 | free(hdiff); | ||
308 | free(hwork); | ||
309 | |||
310 | } // stat(overlayhome) | ||
311 | free(overlayhome); | ||
312 | } | ||
313 | // issue #263 end code | ||
314 | //*************************** | ||
315 | } | ||
316 | fmessage("OverlayFS configured in %s directory\n", basedir); | ||
317 | close(basefd); | ||
318 | |||
319 | // /dev, /run and /tmp are not covered by the overlay | ||
320 | // mount-bind dev directory | ||
321 | if (arg_debug) | ||
322 | printf("Mounting /dev\n"); | ||
323 | char *dev; | ||
324 | if (asprintf(&dev, "%s/dev", oroot) == -1) | ||
325 | errExit("asprintf"); | ||
326 | if (mount("/dev", dev, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
327 | errExit("mounting /dev"); | ||
328 | fs_logger("whitelist /dev"); | ||
329 | |||
330 | // mount-bind run directory | ||
331 | if (arg_debug) | ||
332 | printf("Mounting /run\n"); | ||
333 | char *run; | ||
334 | if (asprintf(&run, "%s/run", oroot) == -1) | ||
335 | errExit("asprintf"); | ||
336 | if (mount("/run", run, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
337 | errExit("mounting /run"); | ||
338 | fs_logger("whitelist /run"); | ||
339 | |||
340 | // mount-bind tmp directory | ||
341 | if (arg_debug) | ||
342 | printf("Mounting /tmp\n"); | ||
343 | char *tmp; | ||
344 | if (asprintf(&tmp, "%s/tmp", oroot) == -1) | ||
345 | errExit("asprintf"); | ||
346 | if (mount("/tmp", tmp, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
347 | errExit("mounting /tmp"); | ||
348 | fs_logger("whitelist /tmp"); | ||
349 | |||
350 | // chroot in the new filesystem | ||
351 | __gcov_flush(); | ||
352 | |||
353 | if (chroot(oroot) == -1) | ||
354 | errExit("chroot"); | ||
355 | |||
356 | // mount a new proc filesystem | ||
357 | if (arg_debug) | ||
358 | printf("Mounting /proc filesystem representing the PID namespace\n"); | ||
359 | if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_REC, NULL) < 0) | ||
360 | errExit("mounting /proc"); | ||
361 | |||
362 | // update /var directory in order to support multiple sandboxes running on the same root directory | ||
363 | // if (!arg_private_dev) | ||
364 | // fs_dev_shm(); | ||
365 | fs_var_lock(); | ||
366 | if (!arg_keep_var_tmp) | ||
367 | fs_var_tmp(); | ||
368 | if (!arg_writable_var_log) | ||
369 | fs_var_log(); | ||
370 | fs_var_lib(); | ||
371 | fs_var_cache(); | ||
372 | fs_var_utmp(); | ||
373 | fs_machineid(); | ||
374 | |||
375 | // don't leak user information | ||
376 | restrict_users(); | ||
377 | |||
378 | // when starting as root, firejail config is not disabled; | ||
379 | if (getuid() != 0) | ||
380 | disable_config(); | ||
381 | |||
382 | // cleanup and exit | ||
383 | free(option); | ||
384 | free(odiff); | ||
385 | free(owork); | ||
386 | free(dev); | ||
387 | free(run); | ||
388 | free(tmp); | ||
389 | } | ||
390 | |||
391 | |||
392 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { | ||
393 | (void) sb; | ||
394 | (void) typeflag; | ||
395 | (void) ftwbuf; | ||
396 | assert(fpath); | ||
397 | |||
398 | if (strcmp(fpath, ".") == 0) // rmdir would fail with EINVAL | ||
399 | return 0; | ||
400 | |||
401 | if (remove(fpath)) { // removes the link not the actual file | ||
402 | fprintf(stderr, "Error: cannot remove file: %s\n", strerror(errno)); | ||
403 | exit(1); | ||
404 | } | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | int remove_overlay_directory(void) { | ||
410 | EUID_ASSERT(); | ||
411 | sleep(1); | ||
412 | |||
413 | char *path; | ||
414 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | ||
415 | errExit("asprintf"); | ||
416 | |||
417 | if (access(path, F_OK) == 0) { | ||
418 | pid_t child = fork(); | ||
419 | if (child < 0) | ||
420 | errExit("fork"); | ||
421 | if (child == 0) { | ||
422 | // open ~/.firejail | ||
423 | int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | ||
424 | if (fd == -1) { | ||
425 | fprintf(stderr, "Error: cannot open %s\n", path); | ||
426 | exit(1); | ||
427 | } | ||
428 | struct stat s; | ||
429 | if (fstat(fd, &s) == -1) | ||
430 | errExit("fstat"); | ||
431 | if (!S_ISDIR(s.st_mode)) { | ||
432 | if (S_ISLNK(s.st_mode)) | ||
433 | fprintf(stderr, "Error: %s is a symbolic link\n", path); | ||
434 | else | ||
435 | fprintf(stderr, "Error: %s is not a directory\n", path); | ||
436 | exit(1); | ||
437 | } | ||
438 | if (s.st_uid != getuid()) { | ||
439 | fprintf(stderr, "Error: %s is not owned by the current user\n", path); | ||
440 | exit(1); | ||
441 | } | ||
442 | // chdir to ~/.firejail | ||
443 | if (fchdir(fd) == -1) | ||
444 | errExit("fchdir"); | ||
445 | close(fd); | ||
446 | |||
447 | EUID_ROOT(); | ||
448 | // FTW_PHYS - do not follow symbolic links | ||
449 | if (nftw(".", remove_callback, 64, FTW_DEPTH | FTW_PHYS) == -1) | ||
450 | errExit("nftw"); | ||
451 | |||
452 | EUID_USER(); | ||
453 | // remove ~/.firejail | ||
454 | if (rmdir(path) == -1) | ||
455 | errExit("rmdir"); | ||
456 | |||
457 | __gcov_flush(); | ||
458 | |||
459 | _exit(0); | ||
460 | } | ||
461 | // wait for the child to finish | ||
462 | waitpid(child, NULL, 0); | ||
463 | // check if ~/.firejail was deleted | ||
464 | if (access(path, F_OK) == 0) | ||
465 | return 1; | ||
466 | } | ||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | #endif // HAVE_OVERLAYFS | ||
diff --git a/src/firejail/fs_trace.c b/src/firejail/fs_trace.c index 718786cdc..17a7b3d23 100644 --- a/src/firejail/fs_trace.c +++ b/src/firejail/fs_trace.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
@@ -54,7 +53,7 @@ void fs_tracefile(void) { | |||
54 | if (arg_debug) | 53 | if (arg_debug) |
55 | printf("Creating an empty trace log file: %s\n", arg_tracefile); | 54 | printf("Creating an empty trace log file: %s\n", arg_tracefile); |
56 | EUID_USER(); | 55 | EUID_USER(); |
57 | int fd = open(arg_tracefile, O_CREAT|O_WRONLY|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 56 | int fd = open(arg_tracefile, O_CREAT|O_WRONLY|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
58 | if (fd == -1) { | 57 | if (fd == -1) { |
59 | perror("open"); | 58 | perror("open"); |
60 | fprintf(stderr, "Error: cannot open trace log file %s for writing\n", arg_tracefile); | 59 | fprintf(stderr, "Error: cannot open trace log file %s for writing\n", arg_tracefile); |
@@ -107,7 +106,7 @@ void fs_trace(void) { | |||
107 | fmessage("Post-exec seccomp protector enabled\n"); | 106 | fmessage("Post-exec seccomp protector enabled\n"); |
108 | } | 107 | } |
109 | 108 | ||
110 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 109 | SET_PERMS_STREAM(fp, 0, 0, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
111 | fclose(fp); | 110 | fclose(fp); |
112 | 111 | ||
113 | // mount the new preload file | 112 | // mount the new preload file |
diff --git a/src/firejail/fs_var.c b/src/firejail/fs_var.c index 20e262d80..e19d0df96 100644 --- a/src/firejail/fs_var.c +++ b/src/firejail/fs_var.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <linux/limits.h> | ||
24 | #include <glob.h> | 23 | #include <glob.h> |
25 | #include <dirent.h> | 24 | #include <dirent.h> |
26 | #include <fcntl.h> | 25 | #include <fcntl.h> |
@@ -129,7 +128,7 @@ void fs_var_log(void) { | |||
129 | /* coverity[toctou] */ | 128 | /* coverity[toctou] */ |
130 | FILE *fp = fopen("/var/log/wtmp", "wxe"); | 129 | FILE *fp = fopen("/var/log/wtmp", "wxe"); |
131 | if (fp) { | 130 | if (fp) { |
132 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH); | 131 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); |
133 | fclose(fp); | 132 | fclose(fp); |
134 | } | 133 | } |
135 | fs_logger("touch /var/log/wtmp"); | 134 | fs_logger("touch /var/log/wtmp"); |
@@ -137,7 +136,7 @@ void fs_var_log(void) { | |||
137 | // create an empty /var/log/btmp file | 136 | // create an empty /var/log/btmp file |
138 | fp = fopen("/var/log/btmp", "wxe"); | 137 | fp = fopen("/var/log/btmp", "wxe"); |
139 | if (fp) { | 138 | if (fp) { |
140 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP); | 139 | SET_PERMS_STREAM(fp, 0, wtmp_group, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); |
141 | fclose(fp); | 140 | fclose(fp); |
142 | } | 141 | } |
143 | fs_logger("touch /var/log/btmp"); | 142 | fs_logger("touch /var/log/btmp"); |
@@ -314,7 +313,7 @@ void fs_var_utmp(void) { | |||
314 | // save new utmp file | 313 | // save new utmp file |
315 | int rv = fwrite(&u_boot, sizeof(u_boot), 1, fp); | 314 | int rv = fwrite(&u_boot, sizeof(u_boot), 1, fp); |
316 | (void) rv; | 315 | (void) rv; |
317 | SET_PERMS_STREAM(fp, 0, utmp_group, S_IRUSR | S_IWRITE | S_IRGRP | S_IWGRP | S_IROTH); | 316 | SET_PERMS_STREAM(fp, 0, utmp_group, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); |
318 | fclose(fp); | 317 | fclose(fp); |
319 | 318 | ||
320 | // mount the new utmp file | 319 | // mount the new utmp file |
diff --git a/src/firejail/join.c b/src/firejail/join.c index a869f6b64..0e76fd944 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -431,7 +431,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
431 | 431 | ||
432 | // set cgroup | 432 | // set cgroup |
433 | if (cfg.cgroup) // not available for uid 0 | 433 | if (cfg.cgroup) // not available for uid 0 |
434 | set_cgroup(cfg.cgroup); | 434 | set_cgroup(cfg.cgroup, getpid()); |
435 | 435 | ||
436 | // join namespaces | 436 | // join namespaces |
437 | if (arg_join_network) { | 437 | if (arg_join_network) { |
diff --git a/src/firejail/ls.c b/src/firejail/ls.c index 70985ba9e..53e918dde 100644 --- a/src/firejail/ls.c +++ b/src/firejail/ls.c | |||
@@ -305,7 +305,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
305 | } | 305 | } |
306 | // create destination file if necessary | 306 | // create destination file if necessary |
307 | EUID_ASSERT(); | 307 | EUID_ASSERT(); |
308 | int fd = open(dest_fname, O_WRONLY|O_CREAT|O_CLOEXEC, S_IRUSR | S_IWRITE); | 308 | int fd = open(dest_fname, O_WRONLY|O_CREAT|O_CLOEXEC, S_IRUSR | S_IWUSR); |
309 | if (fd == -1) { | 309 | if (fd == -1) { |
310 | fprintf(stderr, "Error: cannot open %s for writing\n", dest_fname); | 310 | fprintf(stderr, "Error: cannot open %s for writing\n", dest_fname); |
311 | exit(1); | 311 | exit(1); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 81d148257..1ba70b0bd 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -32,7 +32,8 @@ | |||
32 | #include <dirent.h> | 32 | #include <dirent.h> |
33 | #include <pwd.h> | 33 | #include <pwd.h> |
34 | #include <errno.h> | 34 | #include <errno.h> |
35 | //#include <limits.h> | 35 | |
36 | #include <limits.h> | ||
36 | #include <sys/file.h> | 37 | #include <sys/file.h> |
37 | #include <sys/prctl.h> | 38 | #include <sys/prctl.h> |
38 | #include <signal.h> | 39 | #include <signal.h> |
@@ -1528,15 +1529,16 @@ int main(int argc, char **argv, char **envp) { | |||
1528 | else if (strncmp(argv[i], "--cgroup=", 9) == 0) { | 1529 | else if (strncmp(argv[i], "--cgroup=", 9) == 0) { |
1529 | if (checkcfg(CFG_CGROUP)) { | 1530 | if (checkcfg(CFG_CGROUP)) { |
1530 | if (option_cgroup) { | 1531 | if (option_cgroup) { |
1531 | fprintf(stderr, "Error: only a cgroup can be defined\n"); | 1532 | fprintf(stderr, "Error: only one cgroup can be defined\n"); |
1532 | exit(1); | 1533 | exit(1); |
1533 | } | 1534 | } |
1534 | |||
1535 | option_cgroup = 1; | ||
1536 | cfg.cgroup = strdup(argv[i] + 9); | 1535 | cfg.cgroup = strdup(argv[i] + 9); |
1537 | if (!cfg.cgroup) | 1536 | if (!cfg.cgroup) |
1538 | errExit("strdup"); | 1537 | errExit("strdup"); |
1539 | set_cgroup(cfg.cgroup); | 1538 | |
1539 | check_cgroup_file(cfg.cgroup); | ||
1540 | set_cgroup(cfg.cgroup, getpid()); | ||
1541 | option_cgroup = 1; | ||
1540 | } | 1542 | } |
1541 | else | 1543 | else |
1542 | exit_err_feature("cgroup"); | 1544 | exit_err_feature("cgroup"); |
@@ -2154,6 +2156,10 @@ int main(int argc, char **argv, char **envp) { | |||
2154 | arg_novideo = 1; | 2156 | arg_novideo = 1; |
2155 | else if (strcmp(argv[i], "--no3d") == 0) | 2157 | else if (strcmp(argv[i], "--no3d") == 0) |
2156 | arg_no3d = 1; | 2158 | arg_no3d = 1; |
2159 | else if (strcmp(argv[i], "--noprinters") == 0) { | ||
2160 | profile_add("blacklist /dev/lp*"); | ||
2161 | profile_add("blacklist /run/cups/cups.sock"); | ||
2162 | } | ||
2157 | else if (strcmp(argv[i], "--notv") == 0) | 2163 | else if (strcmp(argv[i], "--notv") == 0) |
2158 | arg_notv = 1; | 2164 | arg_notv = 1; |
2159 | else if (strcmp(argv[i], "--nodvd") == 0) | 2165 | else if (strcmp(argv[i], "--nodvd") == 0) |
diff --git a/src/firejail/mountinfo.c b/src/firejail/mountinfo.c index 304f80eee..ee437e10b 100644 --- a/src/firejail/mountinfo.c +++ b/src/firejail/mountinfo.c | |||
@@ -33,43 +33,38 @@ static MountData mdata; | |||
33 | 33 | ||
34 | 34 | ||
35 | // Convert octal escape sequence to decimal value | 35 | // Convert octal escape sequence to decimal value |
36 | static int read_oct(const char *path) { | 36 | static unsigned read_oct(char *s) { |
37 | int dec = 0; | 37 | assert(s[0] == '\\'); |
38 | int digit, i; | 38 | s++; |
39 | // there are always exactly three octal digits | 39 | |
40 | for (i = 1; i < 4; i++) { | 40 | int i; |
41 | digit = *(path + i); | 41 | for (i = 0; i < 3; i++) |
42 | if (digit < '0' || digit > '7') { | 42 | assert(s[i] >= '0' && s[i] <= '7'); |
43 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 43 | |
44 | exit(1); | 44 | return ((s[0] - '0') << 6 | |
45 | } | 45 | (s[1] - '0') << 3 | |
46 | dec = (dec << 3) + (digit - '0'); | 46 | (s[2] - '0') << 0); |
47 | } | ||
48 | return dec; | ||
49 | } | 47 | } |
50 | 48 | ||
51 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo | 49 | // Restore empty spaces in pathnames extracted from /proc/self/mountinfo |
52 | static void unmangle_path(char *path) { | 50 | static void unmangle_path(char *path) { |
53 | char *p = strchr(path, '\\'); | 51 | char *r = strchr(path, '\\'); |
54 | if (p && read_oct(p) == ' ') { | 52 | if (!r) |
55 | *p = ' '; | 53 | return; |
56 | int i = 3; | 54 | |
57 | do { | 55 | char *w = r; |
58 | p++; | 56 | do { |
59 | if (*(p + i) == '\\' && read_oct(p + i) == ' ') { | 57 | while (*r == '\\') { |
60 | *p = ' '; | 58 | *w++ = read_oct(r); |
61 | i += 3; | 59 | r += 4; |
62 | } | 60 | } |
63 | else | 61 | *w++ = *r; |
64 | *p = *(p + i); | 62 | } while (*r++); |
65 | } while (*p); | ||
66 | } | ||
67 | } | 63 | } |
68 | 64 | ||
69 | // Parse a line from /proc/self/mountinfo, | 65 | // Parse a line from /proc/self/mountinfo, |
70 | // the function does an exit(1) if anything goes wrong. | 66 | // the function does an exit(1) if anything goes wrong. |
71 | static void parse_line(char *line, MountData *output) { | 67 | static void parse_line(char *line, MountData *output) { |
72 | assert(line && output); | ||
73 | memset(output, 0, sizeof(*output)); | 68 | memset(output, 0, sizeof(*output)); |
74 | // extract mount id, filesystem name, directory and filesystem types | 69 | // extract mount id, filesystem name, directory and filesystem types |
75 | // examples: | 70 | // examples: |
@@ -87,8 +82,6 @@ static void parse_line(char *line, MountData *output) { | |||
87 | char *ptr = strtok(line, " "); | 82 | char *ptr = strtok(line, " "); |
88 | if (!ptr) | 83 | if (!ptr) |
89 | goto errexit; | 84 | goto errexit; |
90 | if (ptr != line) | ||
91 | goto errexit; | ||
92 | output->mountid = atoi(ptr); | 85 | output->mountid = atoi(ptr); |
93 | int cnt = 1; | 86 | int cnt = 1; |
94 | 87 | ||
@@ -109,10 +102,9 @@ static void parse_line(char *line, MountData *output) { | |||
109 | ptr = strtok(NULL, " "); | 102 | ptr = strtok(NULL, " "); |
110 | if (!ptr) | 103 | if (!ptr) |
111 | goto errexit; | 104 | goto errexit; |
112 | output->fstype = ptr++; | 105 | output->fstype = ptr; |
113 | 106 | ||
114 | 107 | if (output->mountid < 0 || | |
115 | if (output->mountid == 0 || | ||
116 | output->fsname == NULL || | 108 | output->fsname == NULL || |
117 | output->dir == NULL || | 109 | output->dir == NULL || |
118 | output->fstype == NULL) | 110 | output->fstype == NULL) |
@@ -195,9 +187,9 @@ static int get_mount_id_from_fdinfo(int fd) { | |||
195 | char buf[MAX_BUF]; | 187 | char buf[MAX_BUF]; |
196 | while (fgets(buf, MAX_BUF, fp)) { | 188 | while (fgets(buf, MAX_BUF, fp)) { |
197 | if (strncmp(buf, "mnt_id:", 7) == 0) { | 189 | if (strncmp(buf, "mnt_id:", 7) == 0) { |
198 | if (sscanf(buf + 7, "%d", &rv) != 1) | 190 | if (sscanf(buf + 7, "%d", &rv) == 1) |
199 | goto errexit; | 191 | break; |
200 | break; | 192 | goto errexit; |
201 | } | 193 | } |
202 | } | 194 | } |
203 | 195 | ||
@@ -219,62 +211,50 @@ int get_mount_id(int fd) { | |||
219 | 211 | ||
220 | // Check /proc/self/mountinfo if path contains any mounts points. | 212 | // Check /proc/self/mountinfo if path contains any mounts points. |
221 | // Returns an array that can be iterated over for recursive remounting. | 213 | // Returns an array that can be iterated over for recursive remounting. |
222 | char **build_mount_array(const int mount_id, const char *path) { | 214 | char **build_mount_array(const int mountid, const char *path) { |
223 | assert(path); | 215 | assert(path); |
224 | 216 | ||
225 | // open /proc/self/mountinfo | ||
226 | FILE *fp = fopen("/proc/self/mountinfo", "re"); | 217 | FILE *fp = fopen("/proc/self/mountinfo", "re"); |
227 | if (!fp) { | 218 | if (!fp) { |
228 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 219 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); |
229 | exit(1); | 220 | exit(1); |
230 | } | 221 | } |
231 | 222 | ||
232 | // array to be returned | 223 | // try to find line with mount id |
233 | size_t cnt = 0; | 224 | int found = 0; |
225 | MountData mntp; | ||
226 | char line[MAX_BUF]; | ||
227 | while (fgets(line, MAX_BUF, fp)) { | ||
228 | parse_line(line, &mntp); | ||
229 | if (mntp.mountid == mountid) { | ||
230 | found = 1; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | if (!found) { | ||
236 | fclose(fp); | ||
237 | return NULL; | ||
238 | } | ||
239 | |||
240 | // allocate array | ||
234 | size_t size = 32; | 241 | size_t size = 32; |
235 | char **rv = malloc(size * sizeof(*rv)); | 242 | char **rv = malloc(size * sizeof(*rv)); |
236 | if (!rv) | 243 | if (!rv) |
237 | errExit("malloc"); | 244 | errExit("malloc"); |
238 | 245 | ||
239 | // read /proc/self/mountinfo | 246 | // add directory itself |
240 | size_t pathlen = strlen(path); | 247 | size_t cnt = 0; |
241 | char buf[MAX_BUF]; | 248 | rv[cnt] = strdup(path); |
242 | MountData mntp; | 249 | if (rv[cnt] == NULL) |
243 | int found = 0; | 250 | errExit("strdup"); |
244 | 251 | ||
245 | if (fgets(buf, MAX_BUF, fp) == NULL) { | 252 | // and add all following mountpoints contained in this directory |
246 | fprintf(stderr, "Error: cannot read /proc/self/mountinfo\n"); | 253 | size_t pathlen = strlen(path); |
247 | exit(1); | 254 | while (fgets(line, MAX_BUF, fp)) { |
248 | } | 255 | parse_line(line, &mntp); |
249 | do { | 256 | if (strncmp(mntp.dir, path, pathlen) == 0 && mntp.dir[pathlen] == '/') { |
250 | parse_line(buf, &mntp); | 257 | if (++cnt == size) { |
251 | // find mount point with mount id | ||
252 | if (!found) { | ||
253 | if (mntp.mountid == mount_id) { | ||
254 | // give up if mount id has been reassigned, | ||
255 | // don't remount blacklisted path | ||
256 | if (strncmp(mntp.dir, path, strlen(mntp.dir)) || | ||
257 | strstr(mntp.fsname, "firejail.ro.dir") || | ||
258 | strstr(mntp.fsname, "firejail.ro.file")) | ||
259 | break; | ||
260 | |||
261 | rv[cnt] = strdup(path); | ||
262 | if (rv[cnt] == NULL) | ||
263 | errExit("strdup"); | ||
264 | cnt++; | ||
265 | found = 1; | ||
266 | continue; | ||
267 | } | ||
268 | continue; | ||
269 | } | ||
270 | // from here on add all mount points below path, | ||
271 | // don't remount blacklisted paths | ||
272 | if (strncmp(mntp.dir, path, pathlen) == 0 && | ||
273 | mntp.dir[pathlen] == '/' && | ||
274 | strstr(mntp.fsname, "firejail.ro.dir") == NULL && | ||
275 | strstr(mntp.fsname, "firejail.ro.file") == NULL) { | ||
276 | |||
277 | if (cnt == size) { | ||
278 | size *= 2; | 258 | size *= 2; |
279 | rv = realloc(rv, size * sizeof(*rv)); | 259 | rv = realloc(rv, size * sizeof(*rv)); |
280 | if (!rv) | 260 | if (!rv) |
@@ -283,18 +263,17 @@ char **build_mount_array(const int mount_id, const char *path) { | |||
283 | rv[cnt] = strdup(mntp.dir); | 263 | rv[cnt] = strdup(mntp.dir); |
284 | if (rv[cnt] == NULL) | 264 | if (rv[cnt] == NULL) |
285 | errExit("strdup"); | 265 | errExit("strdup"); |
286 | cnt++; | ||
287 | } | 266 | } |
288 | } while (fgets(buf, MAX_BUF, fp)); | 267 | } |
268 | fclose(fp); | ||
289 | 269 | ||
290 | if (cnt == size) { | 270 | // end of array |
291 | size++; | 271 | if (++cnt == size) { |
272 | ++size; | ||
292 | rv = realloc(rv, size * sizeof(*rv)); | 273 | rv = realloc(rv, size * sizeof(*rv)); |
293 | if (!rv) | 274 | if (!rv) |
294 | errExit("realloc"); | 275 | errExit("realloc"); |
295 | } | 276 | } |
296 | rv[cnt] = NULL; // end of the array | 277 | rv[cnt] = NULL; |
297 | |||
298 | fclose(fp); | ||
299 | return rv; | 278 | return rv; |
300 | } | 279 | } |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 5390249ea..babc3941e 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -449,6 +449,11 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
449 | arg_no3d = 1; | 449 | arg_no3d = 1; |
450 | return 0; | 450 | return 0; |
451 | } | 451 | } |
452 | else if (strcmp(ptr, "noprinters") == 0) { | ||
453 | profile_add("blacklist /dev/lp*"); | ||
454 | profile_add("blacklist /run/cups/cups.sock"); | ||
455 | return 0; | ||
456 | } | ||
452 | else if (strcmp(ptr, "noinput") == 0) { | 457 | else if (strcmp(ptr, "noinput") == 0) { |
453 | arg_noinput = 1; | 458 | arg_noinput = 1; |
454 | return 0; | 459 | return 0; |
@@ -1129,8 +1134,14 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1129 | 1134 | ||
1130 | // cgroup | 1135 | // cgroup |
1131 | if (strncmp(ptr, "cgroup ", 7) == 0) { | 1136 | if (strncmp(ptr, "cgroup ", 7) == 0) { |
1132 | if (checkcfg(CFG_CGROUP)) | 1137 | if (checkcfg(CFG_CGROUP)) { |
1133 | set_cgroup(ptr + 7); | 1138 | cfg.cgroup = strdup(ptr + 7); |
1139 | if (!cfg.cgroup) | ||
1140 | errExit("strdup"); | ||
1141 | |||
1142 | check_cgroup_file(cfg.cgroup); | ||
1143 | set_cgroup(cfg.cgroup, getpid()); | ||
1144 | } | ||
1134 | else | 1145 | else |
1135 | warning_feature_disabled("cgroup"); | 1146 | warning_feature_disabled("cgroup"); |
1136 | return 0; | 1147 | return 0; |
diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c index 6f17231a4..59077dada 100644 --- a/src/firejail/restrict_users.c +++ b/src/firejail/restrict_users.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include "../include/firejail_user.h" | 21 | #include "../include/firejail_user.h" |
22 | #include <sys/mount.h> | 22 | #include <sys/mount.h> |
23 | #include <sys/stat.h> | 23 | #include <sys/stat.h> |
24 | #include <linux/limits.h> | ||
25 | #include <fnmatch.h> | 24 | #include <fnmatch.h> |
26 | #include <glob.h> | 25 | #include <glob.h> |
27 | #include <dirent.h> | 26 | #include <dirent.h> |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index b776a0cc5..d66b6c573 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -204,7 +204,7 @@ static void save_umask(void) { | |||
204 | } | 204 | } |
205 | 205 | ||
206 | static char *create_join_file(void) { | 206 | static char *create_join_file(void) { |
207 | int fd = open(RUN_JOIN_FILE, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWRITE | S_IRGRP | S_IROTH); | 207 | int fd = open(RUN_JOIN_FILE, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); |
208 | if (fd == -1) | 208 | if (fd == -1) |
209 | errExit("open"); | 209 | errExit("open"); |
210 | if (ftruncate(fd, 1) == -1) | 210 | if (ftruncate(fd, 1) == -1) |
diff --git a/src/firejail/util.c b/src/firejail/util.c index f0df45eb2..55dcdc246 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -20,8 +20,6 @@ | |||
20 | #define _XOPEN_SOURCE 500 | 20 | #define _XOPEN_SOURCE 500 |
21 | #include "firejail.h" | 21 | #include "firejail.h" |
22 | #include "../include/gcov_wrapper.h" | 22 | #include "../include/gcov_wrapper.h" |
23 | #include <ftw.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <sys/mount.h> | 23 | #include <sys/mount.h> |
26 | #include <syslog.h> | 24 | #include <syslog.h> |
27 | #include <errno.h> | 25 | #include <errno.h> |
@@ -32,9 +30,6 @@ | |||
32 | #include <sys/wait.h> | 30 | #include <sys/wait.h> |
33 | #include <limits.h> | 31 | #include <limits.h> |
34 | 32 | ||
35 | #include <string.h> | ||
36 | #include <ctype.h> | ||
37 | |||
38 | #include <fcntl.h> | 33 | #include <fcntl.h> |
39 | #ifndef O_PATH | 34 | #ifndef O_PATH |
40 | #define O_PATH 010000000 | 35 | #define O_PATH 010000000 |
@@ -489,13 +484,6 @@ int is_link(const char *fname) { | |||
489 | if (*fname == '\0') | 484 | if (*fname == '\0') |
490 | return 0; | 485 | return 0; |
491 | 486 | ||
492 | int called_as_root = 0; | ||
493 | if (geteuid() == 0) | ||
494 | called_as_root = 1; | ||
495 | |||
496 | if (called_as_root) | ||
497 | EUID_USER(); | ||
498 | |||
499 | // remove trailing '/' if any | 487 | // remove trailing '/' if any |
500 | char *tmp = strdup(fname); | 488 | char *tmp = strdup(fname); |
501 | if (!tmp) | 489 | if (!tmp) |
@@ -503,12 +491,9 @@ int is_link(const char *fname) { | |||
503 | trim_trailing_slash_or_dot(tmp); | 491 | trim_trailing_slash_or_dot(tmp); |
504 | 492 | ||
505 | char c; | 493 | char c; |
506 | ssize_t rv = readlink(tmp, &c, 1); | 494 | ssize_t rv = readlink_as_user(tmp, &c, 1); |
507 | free(tmp); | 495 | free(tmp); |
508 | 496 | ||
509 | if (called_as_root) | ||
510 | EUID_ROOT(); | ||
511 | |||
512 | return (rv != -1); | 497 | return (rv != -1); |
513 | } | 498 | } |
514 | 499 | ||
@@ -530,6 +515,24 @@ char *realpath_as_user(const char *fname) { | |||
530 | return rv; | 515 | return rv; |
531 | } | 516 | } |
532 | 517 | ||
518 | ssize_t readlink_as_user(const char *fname, char *buf, size_t sz) { | ||
519 | assert(fname && buf && sz); | ||
520 | |||
521 | int called_as_root = 0; | ||
522 | if (geteuid() == 0) | ||
523 | called_as_root = 1; | ||
524 | |||
525 | if (called_as_root) | ||
526 | EUID_USER(); | ||
527 | |||
528 | ssize_t rv = readlink(fname, buf, sz); | ||
529 | |||
530 | if (called_as_root) | ||
531 | EUID_ROOT(); | ||
532 | |||
533 | return rv; | ||
534 | } | ||
535 | |||
533 | int stat_as_user(const char *fname, struct stat *s) { | 536 | int stat_as_user(const char *fname, struct stat *s) { |
534 | assert(fname); | 537 | assert(fname); |
535 | 538 | ||
@@ -964,12 +967,9 @@ uid_t pid_get_uid(pid_t pid) { | |||
964 | } | 967 | } |
965 | 968 | ||
966 | 969 | ||
967 | 970 | gid_t get_group_id(const char *groupname) { | |
968 | |||
969 | uid_t get_group_id(const char *group) { | ||
970 | // find tty group id | ||
971 | gid_t gid = 0; | 971 | gid_t gid = 0; |
972 | struct group *g = getgrnam(group); | 972 | struct group *g = getgrnam(groupname); |
973 | if (g) | 973 | if (g) |
974 | gid = g->gr_gid; | 974 | gid = g->gr_gid; |
975 | 975 | ||
@@ -977,86 +977,6 @@ uid_t get_group_id(const char *group) { | |||
977 | } | 977 | } |
978 | 978 | ||
979 | 979 | ||
980 | static int remove_callback(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { | ||
981 | (void) sb; | ||
982 | (void) typeflag; | ||
983 | (void) ftwbuf; | ||
984 | assert(fpath); | ||
985 | |||
986 | if (strcmp(fpath, ".") == 0) | ||
987 | return 0; | ||
988 | |||
989 | if (remove(fpath)) { // removes the link not the actual file | ||
990 | perror("remove"); | ||
991 | fprintf(stderr, "Error: cannot remove file from user .firejail directory: %s\n", fpath); | ||
992 | exit(1); | ||
993 | } | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | |||
999 | int remove_overlay_directory(void) { | ||
1000 | EUID_ASSERT(); | ||
1001 | sleep(1); | ||
1002 | |||
1003 | char *path; | ||
1004 | if (asprintf(&path, "%s/.firejail", cfg.homedir) == -1) | ||
1005 | errExit("asprintf"); | ||
1006 | |||
1007 | if (access(path, F_OK) == 0) { | ||
1008 | pid_t child = fork(); | ||
1009 | if (child < 0) | ||
1010 | errExit("fork"); | ||
1011 | if (child == 0) { | ||
1012 | // open ~/.firejail | ||
1013 | int fd = safer_openat(-1, path, O_PATH|O_NOFOLLOW|O_CLOEXEC); | ||
1014 | if (fd == -1) { | ||
1015 | fprintf(stderr, "Error: cannot open %s\n", path); | ||
1016 | exit(1); | ||
1017 | } | ||
1018 | struct stat s; | ||
1019 | if (fstat(fd, &s) == -1) | ||
1020 | errExit("fstat"); | ||
1021 | if (!S_ISDIR(s.st_mode)) { | ||
1022 | if (S_ISLNK(s.st_mode)) | ||
1023 | fprintf(stderr, "Error: %s is a symbolic link\n", path); | ||
1024 | else | ||
1025 | fprintf(stderr, "Error: %s is not a directory\n", path); | ||
1026 | exit(1); | ||
1027 | } | ||
1028 | if (s.st_uid != getuid()) { | ||
1029 | fprintf(stderr, "Error: %s is not owned by the current user\n", path); | ||
1030 | exit(1); | ||
1031 | } | ||
1032 | // chdir to ~/.firejail | ||
1033 | if (fchdir(fd) == -1) | ||
1034 | errExit("fchdir"); | ||
1035 | close(fd); | ||
1036 | |||
1037 | EUID_ROOT(); | ||
1038 | // FTW_PHYS - do not follow symbolic links | ||
1039 | if (nftw(".", remove_callback, 64, FTW_DEPTH | FTW_PHYS) == -1) | ||
1040 | errExit("nftw"); | ||
1041 | |||
1042 | EUID_USER(); | ||
1043 | // remove ~/.firejail | ||
1044 | if (rmdir(path) == -1) | ||
1045 | errExit("rmdir"); | ||
1046 | |||
1047 | __gcov_flush(); | ||
1048 | |||
1049 | _exit(0); | ||
1050 | } | ||
1051 | // wait for the child to finish | ||
1052 | waitpid(child, NULL, 0); | ||
1053 | // check if ~/.firejail was deleted | ||
1054 | if (access(path, F_OK) == 0) | ||
1055 | return 1; | ||
1056 | } | ||
1057 | return 0; | ||
1058 | } | ||
1059 | |||
1060 | // flush stdin if it is connected to a tty and has input | 980 | // flush stdin if it is connected to a tty and has input |
1061 | void flush_stdin(void) { | 981 | void flush_stdin(void) { |
1062 | if (!isatty(STDIN_FILENO)) | 982 | if (!isatty(STDIN_FILENO)) |
@@ -1085,31 +1005,33 @@ int create_empty_dir_as_user(const char *dir, mode_t mode) { | |||
1085 | assert(dir); | 1005 | assert(dir); |
1086 | mode &= 07777; | 1006 | mode &= 07777; |
1087 | 1007 | ||
1088 | if (access(dir, F_OK) != 0) { | 1008 | if (access(dir, F_OK) == 0) |
1009 | return 0; | ||
1010 | |||
1011 | pid_t child = fork(); | ||
1012 | if (child < 0) | ||
1013 | errExit("fork"); | ||
1014 | if (child == 0) { | ||
1015 | // drop privileges | ||
1016 | drop_privs(0); | ||
1017 | |||
1089 | if (arg_debug) | 1018 | if (arg_debug) |
1090 | printf("Creating empty %s directory\n", dir); | 1019 | printf("Creating empty %s directory\n", dir); |
1091 | pid_t child = fork(); | 1020 | if (mkdir(dir, mode) == 0) { |
1092 | if (child < 0) | 1021 | int err = chmod(dir, mode); |
1093 | errExit("fork"); | 1022 | (void) err; |
1094 | if (child == 0) { | 1023 | } |
1095 | // drop privileges | 1024 | else if (arg_debug) |
1096 | drop_privs(0); | 1025 | printf("Directory %s not created: %s\n", dir, strerror(errno)); |
1097 | |||
1098 | if (mkdir(dir, mode) == 0) { | ||
1099 | int err = chmod(dir, mode); | ||
1100 | (void) err; | ||
1101 | } | ||
1102 | else if (arg_debug) | ||
1103 | printf("Directory %s not created: %s\n", dir, strerror(errno)); | ||
1104 | 1026 | ||
1105 | __gcov_flush(); | 1027 | __gcov_flush(); |
1106 | 1028 | ||
1107 | _exit(0); | 1029 | _exit(0); |
1108 | } | ||
1109 | waitpid(child, NULL, 0); | ||
1110 | if (access(dir, F_OK) == 0) | ||
1111 | return 1; | ||
1112 | } | 1030 | } |
1031 | waitpid(child, NULL, 0); | ||
1032 | |||
1033 | if (access(dir, F_OK) == 0) | ||
1034 | return 1; | ||
1113 | return 0; | 1035 | return 0; |
1114 | } | 1036 | } |
1115 | 1037 | ||
@@ -1499,7 +1421,7 @@ static int has_link(const char *dir) { | |||
1499 | void check_homedir(const char *dir) { | 1421 | void check_homedir(const char *dir) { |
1500 | assert(dir); | 1422 | assert(dir); |
1501 | if (dir[0] != '/') { | 1423 | if (dir[0] != '/') { |
1502 | fprintf(stderr, "Error: invalid user directory \"%s\"\n", cfg.homedir); | 1424 | fprintf(stderr, "Error: invalid user directory \"%s\"\n", dir); |
1503 | exit(1); | 1425 | exit(1); |
1504 | } | 1426 | } |
1505 | // symlinks are rejected in many places | 1427 | // symlinks are rejected in many places |
diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c index d88512b0a..319902ff7 100644 --- a/src/libtrace/libtrace.c +++ b/src/libtrace/libtrace.c | |||
@@ -18,12 +18,12 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #define _GNU_SOURCE | 20 | #define _GNU_SOURCE |
21 | #include <errno.h> | ||
21 | #include <stdio.h> | 22 | #include <stdio.h> |
22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
23 | #include <string.h> | 24 | #include <string.h> |
24 | #include <dlfcn.h> | 25 | #include <dlfcn.h> |
25 | #include <sys/types.h> | 26 | #include <sys/types.h> |
26 | #include <limits.h> | ||
27 | #include <unistd.h> | 27 | #include <unistd.h> |
28 | #include <sys/socket.h> | 28 | #include <sys/socket.h> |
29 | #include <netinet/in.h> | 29 | #include <netinet/in.h> |
@@ -706,10 +706,14 @@ __attribute__((constructor)) | |||
706 | static void log_exec(int argc, char** argv) { | 706 | static void log_exec(int argc, char** argv) { |
707 | (void) argc; | 707 | (void) argc; |
708 | (void) argv; | 708 | (void) argv; |
709 | static char buf[PATH_MAX + 1]; | 709 | char *buf = realpath("/proc/self/exe", NULL); |
710 | int rv = readlink("/proc/self/exe", buf, PATH_MAX); | 710 | if (buf == NULL) { |
711 | if (rv != -1) { | 711 | if (errno == ENOMEM) { |
712 | buf[rv] = '\0'; // readlink does not add a '\0' at the end | 712 | tprintf(ftty, "realpath: %s\n", strerror(errno)); |
713 | exit(1); | ||
714 | } | ||
715 | } else { | ||
713 | tprintf(ftty, "%u:%s:exec %s:0\n", mypid, myname, buf); | 716 | tprintf(ftty, "%u:%s:exec %s:0\n", mypid, myname, buf); |
717 | free(buf); | ||
714 | } | 718 | } |
715 | } | 719 | } |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 2883ab257..e724e4bb9 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -290,8 +290,8 @@ $ firejail \-\-caps.print=3272 | |||
290 | Print content of file from sandbox container, see FILE TRANSFER section for more details. | 290 | Print content of file from sandbox container, see FILE TRANSFER section for more details. |
291 | #endif | 291 | #endif |
292 | .TP | 292 | .TP |
293 | \fB\-\-cgroup=tasks-file | 293 | \fB\-\-cgroup=file |
294 | Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. | 294 | Place the sandbox in the specified control group. file is the full path of a tasks or cgroup.procs file. |
295 | .br | 295 | .br |
296 | 296 | ||
297 | .br | 297 | .br |
@@ -310,6 +310,11 @@ regular user, nonewprivs and a default capabilities filter are enabled. | |||
310 | Example: | 310 | Example: |
311 | .br | 311 | .br |
312 | $ firejail \-\-chroot=/media/ubuntu warzone2100 | 312 | $ firejail \-\-chroot=/media/ubuntu warzone2100 |
313 | .br | ||
314 | |||
315 | .br | ||
316 | For automatic mounting of X11 and PulseAudio sockets set environment variables | ||
317 | FIREJAIL_CHROOT_X11 and FIREJAIL_CHROOT_PULSE. | ||
313 | #endif | 318 | #endif |
314 | .TP | 319 | .TP |
315 | \fB\-\-cpu=cpu-number,cpu-number,cpu-number | 320 | \fB\-\-cpu=cpu-number,cpu-number,cpu-number |
@@ -2192,6 +2197,11 @@ More information about groups can be found in /usr/share/doc/firejail/syscalls.t | |||
2192 | .br | 2197 | .br |
2193 | 2198 | ||
2194 | .br | 2199 | .br |
2200 | The default list can be customized, see \-\-seccomp= for a description. | ||
2201 | It can be customized also globally in /etc/firejail/firejail.config file. | ||
2202 | .br | ||
2203 | |||
2204 | .br | ||
2195 | System architecture is strictly imposed only if flag | 2205 | System architecture is strictly imposed only if flag |
2196 | \-\-seccomp.block-secondary is used. The filter is applied at run time | 2206 | \-\-seccomp.block-secondary is used. The filter is applied at run time |
2197 | only if the correct architecture was detected. For the case of I386 | 2207 | only if the correct architecture was detected. For the case of I386 |
@@ -2206,11 +2216,7 @@ Firejail will print seccomp violations to the audit log if the kernel was compil | |||
2206 | Example: | 2216 | Example: |
2207 | .br | 2217 | .br |
2208 | $ firejail \-\-seccomp | 2218 | $ firejail \-\-seccomp |
2209 | .br | ||
2210 | 2219 | ||
2211 | .br | ||
2212 | The default list can be customized, see \-\-seccomp= for a description. It can be customized | ||
2213 | also globally in /etc/firejail/firejail.config file. | ||
2214 | 2220 | ||
2215 | .TP | 2221 | .TP |
2216 | \fB\-\-seccomp=syscall,@group,!syscall2 | 2222 | \fB\-\-seccomp=syscall,@group,!syscall2 |