diff --git a/.gitignore b/.gitignore index 0d5979c8b..db523da59 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,6 @@ src/firecfg/firecfg src/ftee/ftee src/tags src/faudit/faudit +src/fnet/fnet +src/fseccomp/fseccomp uids.h diff --git a/Makefile.in b/Makefile.in index 3f08c5952..86acc206c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,6 +1,6 @@ all: apps man MYLIBS = src/lib -APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect +APPS = src/firejail src/firemon src/firecfg src/libtrace src/libtracelog src/ftee src/faudit src/libconnect src/fnet src/fseccomp MANPAGES = firejail.1 firemon.1 firecfg.1 firejail-profile.5 firejail-login.5 prefix=@prefix@ @@ -76,6 +76,8 @@ realinstall: install -c -m 0755 src/fshaper/fshaper.sh $(DESTDIR)/$(libdir)/firejail/. install -c -m 0644 src/firecfg/firecfg.config $(DESTDIR)/$(libdir)/firejail/. install -c -m 0755 src/faudit/faudit $(DESTDIR)/$(libdir)/firejail/. + install -c -m 0755 src/fnet/fnet $(DESTDIR)/$(libdir)/firejail/. + install -c -m 0755 src/fseccomp/fseccomp $(DESTDIR)/$(libdir)/firejail/. # documents install -m 0755 -d $(DESTDIR)/$(DOCDIR) install -c -m 0644 COPYING $(DESTDIR)/$(DOCDIR)/. @@ -124,6 +126,8 @@ install-strip: all strip src/libconnect/libconnect.so strip src/ftee/ftee strip src/faudit/faudit + strip src/fnet/fnet + strip src/fseccomp/fseccomp $(MAKE) realinstall uninstall: @@ -141,7 +145,7 @@ uninstall: rm -f $(DESTDIR)/$(datarootdir)/bash-completion/completions/firecfg DISTFILES = "src etc platform configure configure.ac Makefile.in install.sh mkman.sh mketc.sh mkdeb.sh mkuid.sh COPYING README RELNOTES" -DISTFILES_TEST = "test/apps test/apps-x11 test/environment test/profiles test/utils test/compile test/filters test/network test/fs test/sysutils" +DISTFILES_TEST = "test/apps test/apps-x11 test/apps-x11-xorg test/environment test/profiles test/utils test/compile test/filters test/network test/fs test/sysutils" dist: mv config.status config.status.old @@ -195,6 +199,9 @@ test-apps: test-apps-x11: cd test/apps-x11; ./apps-x11.sh | grep TESTING +test-apps-x11-xorg: + cd test/apps-x11-xorg; ./apps-x11-xorg.sh | grep TESTING + test-sysutils: cd test/sysutils; ./sysutils.sh | grep TESTING @@ -213,5 +220,5 @@ test-network: test-fs: cd test/fs; ./fs.sh | grep TESTING -test: test-profiles test-fs test-utils test-environment test-apps test-apps-x11 test-filters +test: test-profiles test-fs test-utils test-environment test-apps test-apps-x11 test-apps-x11-xorg test-filters echo "TEST COMPLETE" diff --git a/README b/README index 043e7445a..428f610f9 100644 --- a/README +++ b/README @@ -47,6 +47,7 @@ Aleksey Manevich (https://github.com/manevich) - added --join-or-start command - CVE-2016-7545 Fred-Barclay (https://github.com/Fred-Barclay) + - lots of profile fixes - added Vivaldi, Atril profiles - added PaleMoon profile - split Icedove and Thunderbird profiles @@ -69,7 +70,7 @@ Fred-Barclay (https://github.com/Fred-Barclay) - added audacity profile - fixed Telegram and qtox profiles - added Atom Beta and Atom profiles - - tightened 0ad, atril, evince, gthumb, pix, qtox, and xreader profiles. + - tightened 0ad, atril, evince, gthumb, pix, qtox, and xreader profiles - several private-bin conversions - added jitsi profile - pidgin private-bin conversion @@ -77,13 +78,32 @@ Fred-Barclay (https://github.com/Fred-Barclay) - added gnome-chess profile - added DOSBox profile - evince profile enhancement + - tightened Spotify profile + - added xiphos and Tor Browser Bundle profiles +Impyy (https://github.com/Impyy) + - added mumble profile +valoq (https://github.com/valoq) + - LibreOffice profile fixes + - cherrytree profile fixes + - added support for /srv in --whitelist feature + - Eye of GNOME, Evolution, display (imagemagik) and Wire profiles + - blacklist suid binaries in disable-common.inc +Vadim A. Misbakh-Soloviov (https://github.com/msva) + - profile fixes +Rafael Cavalcanti (https://github.com/rccavalcanti) + - chromium profile fixes for Arch Linux +Deelvesh Bunjun (https://github.com/DeelveshBunjun) + - added xpdf profile +vismir2 (https://github.com/vismir2) + - claws-mail, mutt, git, emacs, vim profiles +Dara Adib (https://github.com/daradib) + - ssh profile fix + - evince profile fix vismir2 (https://github.com/vismir2) - feh, ranger, 7z, keepass, keepassx and zathura profiles - lots of profile fixes graywolf (https://github.com/graywolf) - spelling fix -Dara Adib (https://github.com/daradib) - - ssh profile fix Tomasz Jan Góralczyk (https://github.com/tjg) - fixed Steam profile pwnage-pineapple (https://github.com/pwnage-pineapple) diff --git a/README.md b/README.md index 6e50a7645..c6484d3b7 100644 --- a/README.md +++ b/README.md @@ -40,75 +40,17 @@ FAQ: https://firejail.wordpress.com/support/frequently-asked-questions/ If you keep your Firejail profiles in a public repository, please give us a link: * https://github.com/chiraag-nataraj/firejail-profiles + +* https://github.com/triceratops1/fe + +Use this issue to request new profiles: https://github.com/netblue30/firejail/issues/825 ````` ````` -# Current development version: 0.9.43 - -## X11 development -````` - --x11=none - Blacklist /tmp/.X11-unix directory, ${HOME}/.Xauthority and the - file specified in ${XAUTHORITY} environment variable. Remove - DISPLAY and XAUTHORITY environment variables. Stop with error - message if X11 abstract socket will be accessible in jail. - - --x11=xorg - Sandbox the application using the untrusted mode implemented by - X11 security extension. The extension is available in Xorg - package and it is installed by default on most Linux distribu‐ - tions. It provides support for a simple trusted/untrusted con‐ - nection model. Untrusted clients are restricted in certain ways - to prevent them from reading window contents of other clients, - stealing input events, etc. - - The untrusted mode has several limitations. A lot of regular - programs assume they are a trusted X11 clients and will crash - or lock up when run in untrusted mode. Chromium browser and - xterm are two examples. Firefox and transmission-gtk seem to be - working fine. A network namespace is not required for this - option. - - Example: - $ firejail --x11=xorg firefox +# Current development version: 0.9.45 ````` -## Other command line options ````` - --put=name|pid src-filename dest-filename - Put src-filename in sandbox container. The container is specified by name or PID. - - --allusers - All user home directories are visible inside the sandbox. By default, only current user home - directory is visible. - - Example: - $ firejail --allusers - - --join-or-start=name - Join the sandbox identified by name or start a new one. Same as "firejail --join=name" if - sandbox with specified name exists, otherwise same as "firejail --name=name ..." - Note that in contrary to other join options there is respective profile option. - - --no3d Disable 3D hardware acceleration. - - Example: - $ firejail --no3d firefox - - --veth-name=name - Use this name for the interface connected to the bridge for - --net=bridge_interface commands, instead of the default one. - - Example: - $ firejail --net=br0 --veth-name=if0 - -````` - -## New profile commands - -x11 xpra, x11 xephyr, x11 none, x11 xorg, allusers, join-or-start - -## New profiles - -qpdfview, mupdf, Luminance HDR, Synfig Studio, Gimp, Inkscape, feh, ranger, zathura, 7z, keepass, keepassx +## New Profiles +xiphos, Tor Browser Bundle, display (imagemagik), Wire, mumble diff --git a/RELNOTES b/RELNOTES index bdafb6ff0..44d313999 100644 --- a/RELNOTES +++ b/RELNOTES @@ -1,9 +1,19 @@ -firejail (0.9.43) baseline; urgency=low +firejail (0.9.45) baseline; urgency=low + * development version, work in progress + * security: overwrite /etc/resolv.conf found by Martin Carpenter + * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm) + * feature: split most of networking code in a separate executable + * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire + * bugfixes + -- netblue30 Sun, 23 Oct 2016 08:00:00 -0500 + +firejail (0.9.44) baseline; urgency=low * CVE-2016-7545 submitted by Aleksey Manevich - * development version * modifs: removed man firejail-config * modifs: --private-tmp whitelists /tmp/.X11-unix directory * modifs: Nvidia drivers added to --private-dev + * modifs: /srv supported by --whitelist + * feature: allow user access to /sys/fs (--noblacklist=/sys/fs) * feature: support starting/joining sandbox is a single command (--join-or-start) * feature: X11 detection support for --audit @@ -15,10 +25,15 @@ firejail (0.9.43) baseline; urgency=low * feature: X11 security extension (--x11=xorg) * feature: disable 3D hardware acceleration (--no3d) * feature: x11 xpra, x11 xephyr, x11 block, allusers, no3d profile commands + * feature: move files in sandbox (--put) + * feature: accept wildcard patterns in user name field of restricted + shell login feature * new profiles: qpdfview, mupdf, Luminance HDR, Synfig Studio, Gimp, Inkscape - * new profiles: feh, ranger, zathura, 7z, keepass, keepassx + * new profiles: feh, ranger, zathura, 7z, keepass, keepassx, + * new profiles: claws-mail, mutt, git, emacs, vim, xpdf, VirtualBox, OpenShot + * new profiles: Flowblade, Eye of GNOME (eog), Evolution * bugfixes - -- netblue30 Fri, 9 Sept 2016 08:00:00 -0500 + -- netblue30 Fri, 21 Oct 2016 08:00:00 -0500 firejail (0.9.42) baseline; urgency=low * security: --whitelist deleted files, submitted by Vasya Novikov diff --git a/configure b/configure index 5e066a44d..a89fddbef 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for firejail 0.9.43. +# Generated by GNU Autoconf 2.69 for firejail 0.9.45. # # Report bugs to . # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='firejail' PACKAGE_TARNAME='firejail' -PACKAGE_VERSION='0.9.43' -PACKAGE_STRING='firejail 0.9.43' +PACKAGE_VERSION='0.9.45' +PACKAGE_STRING='firejail 0.9.45' PACKAGE_BUGREPORT='netblue30@yahoo.com' PACKAGE_URL='http://firejail.wordpress.com' @@ -1259,7 +1259,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures firejail 0.9.43 to adapt to many kinds of systems. +\`configure' configures firejail 0.9.45 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1320,7 +1320,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of firejail 0.9.43:";; + short | recursive ) echo "Configuration of firejail 0.9.45:";; esac cat <<\_ACEOF @@ -1424,7 +1424,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -firejail configure 0.9.43 +firejail configure 0.9.45 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1726,7 +1726,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by firejail $as_me 0.9.43, which was +It was created by firejail $as_me 0.9.45, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3759,7 +3759,7 @@ if test "$prefix" = /usr; then sysconfdir="/etc" fi -ac_config_files="$ac_config_files Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile" +ac_config_files="$ac_config_files Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -4303,7 +4303,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by firejail $as_me 0.9.43, which was +This file was extended by firejail $as_me 0.9.45, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4357,7 +4357,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -firejail config.status 0.9.43 +firejail config.status 0.9.45 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -4470,6 +4470,7 @@ do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/lib/Makefile") CONFIG_FILES="$CONFIG_FILES src/lib/Makefile" ;; + "src/fnet/Makefile") CONFIG_FILES="$CONFIG_FILES src/fnet/Makefile" ;; "src/firejail/Makefile") CONFIG_FILES="$CONFIG_FILES src/firejail/Makefile" ;; "src/firemon/Makefile") CONFIG_FILES="$CONFIG_FILES src/firemon/Makefile" ;; "src/libtrace/Makefile") CONFIG_FILES="$CONFIG_FILES src/libtrace/Makefile" ;; @@ -4478,6 +4479,7 @@ do "src/ftee/Makefile") CONFIG_FILES="$CONFIG_FILES src/ftee/Makefile" ;; "src/faudit/Makefile") CONFIG_FILES="$CONFIG_FILES src/faudit/Makefile" ;; "src/libconnect/Makefile") CONFIG_FILES="$CONFIG_FILES src/libconnect/Makefile" ;; + "src/fseccomp/Makefile") CONFIG_FILES="$CONFIG_FILES src/fseccomp/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac diff --git a/configure.ac b/configure.ac index a1d65cc63..9e7680d7d 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.68]) -AC_INIT(firejail, 0.9.43, netblue30@yahoo.com, , http://firejail.wordpress.com) +AC_INIT(firejail, 0.9.45, netblue30@yahoo.com, , http://firejail.wordpress.com) AC_CONFIG_SRCDIR([src/firejail/main.c]) #AC_CONFIG_HEADERS([config.h]) @@ -148,7 +148,8 @@ if test "$prefix" = /usr; then sysconfdir="/etc" fi -AC_OUTPUT(Makefile src/lib/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile) +AC_OUTPUT(Makefile src/lib/Makefile src/fnet/Makefile src/firejail/Makefile src/firemon/Makefile src/libtrace/Makefile src/libtracelog/Makefile \ +src/firecfg/Makefile src/ftee/Makefile src/faudit/Makefile src/libconnect/Makefile src/fseccomp/Makefile) echo echo "Configuration options:" diff --git a/etc/Wire.profile b/etc/Wire.profile new file mode 100644 index 000000000..b488d75e4 --- /dev/null +++ b/etc/Wire.profile @@ -0,0 +1,22 @@ +# wire messenger profile + +noblacklist ~/.config/Wire + +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-devel.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all +netfilter +nonewprivs +nogroups +noroot +protocol unix,inet,inet6,netlink +seccomp +shell none + +private-tmp +private-dev + +# please note: the wire binary is currently identified with a capital W. This might change in future versions diff --git a/etc/atom-beta.profile b/etc/atom-beta.profile index 9a8d93875..fa0b316bb 100644 --- a/etc/atom-beta.profile +++ b/etc/atom-beta.profile @@ -8,8 +8,8 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot nosound protocol unix,inet,inet6,netlink diff --git a/etc/atom.profile b/etc/atom.profile index 3cb86847e..61930d5c1 100644 --- a/etc/atom.profile +++ b/etc/atom.profile @@ -8,8 +8,8 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot nosound protocol unix,inet,inet6,netlink diff --git a/etc/atril.profile b/etc/atril.profile index d9e10b072..fbcca0c1b 100644 --- a/etc/atril.profile +++ b/etc/atril.profile @@ -7,8 +7,8 @@ include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all -nonewprivs nogroups +nonewprivs noroot nosound protocol unix diff --git a/etc/audacity.profile b/etc/audacity.profile index be3fac9be..827fa4301 100644 --- a/etc/audacity.profile +++ b/etc/audacity.profile @@ -8,8 +8,8 @@ include /etc/firejail/disable-programs.inc caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot protocol unix seccomp diff --git a/etc/aweather.profile b/etc/aweather.profile index 4e5c36f50..fa8654f1e 100644 --- a/etc/aweather.profile +++ b/etc/aweather.profile @@ -11,8 +11,8 @@ whitelist ~/.config/aweather caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot nosound protocol unix,inet,inet6 diff --git a/etc/cherrytree.profile b/etc/cherrytree.profile index 7c324a34b..139dec8ec 100644 --- a/etc/cherrytree.profile +++ b/etc/cherrytree.profile @@ -1,6 +1,7 @@ # cherrytree note taking application noblacklist /usr/bin/python2* noblacklist /usr/lib/python3* +noblacklist ${HOME}/.config/cherrytree include /etc/firejail/disable-common.inc include /etc/firejail/disable-programs.inc include /etc/firejail/disable-devel.inc @@ -8,20 +9,10 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter +nogroups nonewprivs noroot nosound seccomp protocol unix,inet,inet6,netlink tracelog - -include /etc/firejail/whitelist-common.inc - -# no private-bin support for various reasons: -#10:25:34 exec 11249 (root) NEW SANDBOX: /usr/bin/firejail /usr/bin/cherrytree -#10:25:34 exec 11252 (netblue) /bin/bash -c "/usr/bin/cherrytree" -#10:25:34 exec 11252 (netblue) /usr/bin/python /usr/bin/cherrytree -#10:25:34 exec 11253 (netblue) sh -c /sbin/ldconfig -p 2>/dev/null -#10:25:34 exec 11255 (netblue) sh -c if type gcc >/dev/null 2>&1; then CC=gcc; elif type cc >/dev/null 2>&1; then CC=cc;else exit 10; fi;LANG=C LC_ALL=C $CC -Wl,-t -o /tmp/tmpiYr44S 2>&1 -llibc -# it requires acces to browser to show the online help -# it doesn't play nicely with expect diff --git a/etc/chromium.profile b/etc/chromium.profile index 0d383aebf..4109af9a4 100644 --- a/etc/chromium.profile +++ b/etc/chromium.profile @@ -25,4 +25,7 @@ whitelist ~/keepassx.kdbx whitelist ~/.lastpass whitelist ~/.config/lastpass +# specific to Arch +whitelist ~/.config/chromium-flags.conf + include /etc/firejail/whitelist-common.inc diff --git a/etc/disable-common.inc b/etc/disable-common.inc index 4f854c8d8..38a8b86d6 100644 --- a/etc/disable-common.inc +++ b/etc/disable-common.inc @@ -1,6 +1,7 @@ # History files in $HOME blacklist-nolog ${HOME}/.history blacklist-nolog ${HOME}/.*_history +blacklist-nolog ${HOME}/.bash_history blacklist ${HOME}/.local/share/systemd blacklist-nolog ${HOME}/.adobe blacklist-nolog ${HOME}/.macromedia @@ -23,6 +24,7 @@ blacklist ${HOME}/.config/openbox/autostart blacklist ${HOME}/.config/openbox/environment blacklist ${HOME}/.gnomerc blacklist /etc/X11/Xsession.d/ +blacklist ${HOME}/.xpra # VirtualBox blacklist ${HOME}/.VirtualBox @@ -96,9 +98,6 @@ read-only ${HOME}/.emacs.d read-only ${HOME}/.nano read-only ${HOME}/.tmux.conf read-only ${HOME}/.iscreenrc -read-only ${HOME}/.muttrc -read-only ${HOME}/.mutt/muttrc -read-only ${HOME}/.msmtprc read-only ${HOME}/.reportbugrc read-only ${HOME}/.xmonad read-only ${HOME}/.xscreensaver @@ -137,6 +136,11 @@ blacklist /etc/gshadow+ blacklist /etc/ssh blacklist /var/backup +# system directories +blacklist /sbin +blacklist /usr/sbin +blacklist /usr/local/sbin + # system management blacklist ${PATH}/umount blacklist ${PATH}/mount @@ -149,11 +153,22 @@ blacklist ${PATH}/xev blacklist ${PATH}/strace blacklist ${PATH}/nc blacklist ${PATH}/ncat - -# system directories -blacklist /sbin -blacklist /usr/sbin -blacklist /usr/local/sbin +blacklist ${PATH}/gpasswd +blacklist ${PATH}/newgidmap +blacklist ${PATH}/newgrp +blacklist ${PATH}/newuidmap +blacklist ${PATH}/pkexec +blacklist ${PATH}/sg +blacklist ${PATH}/rsh +blacklist ${PATH}/rlogin +blacklist ${PATH}/rcp +blacklist ${PATH}/crontab +blacklist ${PATH}/ksu +blacklist ${PATH}/chsh +blacklist ${PATH}/chfn +blacklist ${PATH}/chage +blacklist ${PATH}/expiry +blacklist ${PATH}/unix_chkpwd # prevent lxterminal connecting to an existing lxterminal session blacklist /tmp/.lxterminal-socket* @@ -172,3 +187,7 @@ blacklist ${PATH}/roxterm-config blacklist ${PATH}/terminix blacklist ${PATH}/urxvtc blacklist ${PATH}/urxvtcd + +# kernel files +blacklist /vmlinuz* +blacklist /initrd* diff --git a/etc/disable-devel.inc b/etc/disable-devel.inc index 971857710..2ac367f37 100644 --- a/etc/disable-devel.inc +++ b/etc/disable-devel.inc @@ -20,7 +20,7 @@ blacklist /usr/bin/x86_64-unknown-linux-gnu-gcc* # clang/llvm blacklist /usr/bin/clang* blacklist /usr/bin/llvm* -blacklist /usb/bin/lldb* +blacklist /usr/bin/lldb* blacklist /usr/lib/llvm* # tcc - Tiny C Compiler diff --git a/etc/disable-programs.inc b/etc/disable-programs.inc index c13885739..0d9bd1bb4 100644 --- a/etc/disable-programs.inc +++ b/etc/disable-programs.inc @@ -7,6 +7,8 @@ blacklist ${HOME}/.wine blacklist ${HOME}/.Mathematica blacklist ${HOME}/.Wolfram Research blacklist ${HOME}/.stellarium +blacklist ${HOME}/.sword +blacklist ${HOME}/.xiphos blacklist ${HOME}/.config/Atom blacklist ${HOME}/.config/gthumb blacklist ${HOME}/.config/mupen64plus @@ -33,6 +35,13 @@ blacklist ${HOME}/.synfig blacklist ${HOME}/.inkscape blacklist ${HOME}/.gimp* blacklist ${HOME}/.config/zathura +blacklist ${HOME}/.config/cherrytree +blacklist ${HOME}/.xpdfrc +blacklist ${HOME}/.openshot +blacklist ${HOME}/.openshot_qt +blacklist ${HOME}/.flowblade +blacklist ${HOME}/.config/flowblade +blacklist ${HOME}/.config/eog # Media players @@ -70,8 +79,12 @@ blacklist ${HOME}/.8pecxstudios blacklist ${HOME}/.config/brave blacklist ${HOME}/.config/inox blacklist ${HOME}/.muttrc +blacklist ${HOME}/.mutt blacklist ${HOME}/.mutt/muttrc blacklist ${HOME}/.msmtprc +blacklist ${HOME}/.config/evolution +blacklist ${HOME}/.local/share/evolution +blacklist ${HOME}/.cache/evolution # Instant Messaging blacklist ${HOME}/.config/hexchat @@ -93,6 +106,7 @@ blacklist ${HOME}/.config/Slack blacklist ${HOME}/.cache/gajim blacklist ${HOME}/.local/share/gajim blacklist ${HOME}/.config/gajim +blacklist ${HOME}/.config/Wire # Games blacklist ${HOME}/.hedgewars diff --git a/etc/display.profile b/etc/display.profile new file mode 100644 index 000000000..ec041bff7 --- /dev/null +++ b/etc/display.profile @@ -0,0 +1,23 @@ +# display (ImageMagick tool) image viewer profile +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-devel.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all +seccomp +protocol unix +netfilter +net none +nonewprivs +noroot +nogroups +nosound +shell none +x11 xorg + +private-bin display +private-tmp +private-dev +private-etc none + diff --git a/etc/eog.profile b/etc/eog.profile new file mode 100644 index 000000000..7eb7fd127 --- /dev/null +++ b/etc/eog.profile @@ -0,0 +1,22 @@ +# eog (gnome image viewer) profile + +noblacklist ~/.config/eog + +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-devel.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all +netfilter +nogroups +nonewprivs +noroot +protocol unix +seccomp +shell none + +private-bin eog +private-dev +private-etc fonts +private-tmp diff --git a/etc/evince.profile b/etc/evince.profile index 374fa4aaa..894c7c70d 100644 --- a/etc/evince.profile +++ b/etc/evince.profile @@ -15,5 +15,4 @@ shell none tracelog private-bin evince,evince-previewer,evince-thumbnailer -whitelist /tmp/.X11-unix private-dev diff --git a/etc/evolution.profile b/etc/evolution.profile new file mode 100644 index 000000000..d097c0f34 --- /dev/null +++ b/etc/evolution.profile @@ -0,0 +1,25 @@ +# evolution profile + +noblacklist ~/.config/evolution +noblacklist ~/.local/share/evolution +noblacklist ~/.cache/evolution +noblacklist ~/.pki +noblacklist ~/.pki/nssdb +noblacklist ~/.gnupg + +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-devel.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all +netfilter +nogroups +nonewprivs +noroot +protocol unix,inet,inet6 +seccomp +shell none + +private-dev +private-tmp diff --git a/etc/feh.profile b/etc/feh.profile index 5fcb6bf25..e3b1ec528 100644 --- a/etc/feh.profile +++ b/etc/feh.profile @@ -5,14 +5,14 @@ include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all -seccomp -protocol unix netfilter net none +nogroups nonewprivs noroot -nogroups nosound +protocol unix +seccomp shell none private-bin feh diff --git a/etc/file.profile b/etc/file.profile index 2e54030b1..199a97fad 100644 --- a/etc/file.profile +++ b/etc/file.profile @@ -1,16 +1,17 @@ # file profile -quiet ignore noroot include /etc/firejail/default.profile -tracelog -net none -shell none -private-bin file -private-etc magic.mgc,magic,localtime -hostname file -private-dev -nosound -no3d blacklist /tmp/.X11-unix +hostname file +net none +no3d +nosound +quiet +shell none +tracelog + +private-dev +private-bin file +private-etc magic.mgc,magic,localtime diff --git a/etc/filezilla.profile b/etc/filezilla.profile index 551c17a78..fe1d9d20d 100644 --- a/etc/filezilla.profile +++ b/etc/filezilla.profile @@ -13,10 +13,9 @@ noroot nosound protocol unix,inet,inet6 seccomp - shell none -private-bin filezilla,uname,sh,python,lsb_release,fzputtygen,fzsftp -whitelist /tmp/.X11-unix -private-dev -nosound +private-bin filezilla,uname,sh,python,lsb_release,fzputtygen,fzsftp +private-dev + +whitelist /tmp/.X11-unix diff --git a/etc/firejail-default b/etc/firejail-default index 0b771f834..1b0eb7658 100644 --- a/etc/firejail-default +++ b/etc/firejail-default @@ -31,6 +31,9 @@ profile firejail-default { /{,var/}run/user/**/pulse/ rw, /{,var/}run/user/**/pulse/** rw, /{,var/}run/firejail/mnt/fslogger r, +/{,var/}run/firejail/appimage r, +/{,var/}run/firejail/appimage/** r, +/{,var/}run/firejail/appimage/** ix, /{run,dev}/shm/ r, /{run,dev}/shm/** rmwk, diff --git a/etc/flowblade.profile b/etc/flowblade.profile new file mode 100644 index 000000000..12afdb0aa --- /dev/null +++ b/etc/flowblade.profile @@ -0,0 +1,13 @@ +# FlowBlade profile +noblacklist ${HOME}/.flowblade +noblacklist ${HOME}/.config/flowblade +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all +netfilter +nonewprivs +noroot +protocol unix,inet,inet6,netlink +seccomp diff --git a/etc/franz.profile b/etc/franz.profile index 3cb7942ab..0b3be551b 100644 --- a/etc/franz.profile +++ b/etc/franz.profile @@ -6,12 +6,12 @@ include /etc/firejail/disable-programs.inc include /etc/firejail/disable-devel.inc caps.drop all -seccomp -protocol unix,inet,inet6,netlink netfilter -#tracelog nonewprivs noroot +protocol unix,inet,inet6,netlink +seccomp +#tracelog whitelist ${DOWNLOADS} mkdir ~/.config/Franz diff --git a/etc/gajim.profile b/etc/gajim.profile index 04902a734..809378ef9 100644 --- a/etc/gajim.profile +++ b/etc/gajim.profile @@ -22,8 +22,8 @@ include /etc/firejail/disable-devel.inc caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot protocol unix,inet,inet6 seccomp diff --git a/etc/gimp.profile b/etc/gimp.profile index 23361b771..cb441fc9d 100644 --- a/etc/gimp.profile +++ b/etc/gimp.profile @@ -6,13 +6,15 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter +nogroups nonewprivs noroot +nosound protocol unix seccomp -private-dev -private-tmp + noexec ${HOME} noexec /tmp -nogroups -nosound + +private-dev +private-tmp diff --git a/etc/git.profile b/etc/git.profile index 2fb55377d..73122d347 100644 --- a/etc/git.profile +++ b/etc/git.profile @@ -12,15 +12,15 @@ include /etc/firejail/disable-common.inc include /etc/firejail/disable-programs.inc include /etc/firejail/disable-passwdmgr.inc -quiet caps.drop all netfilter +nogroups nonewprivs noroot -nogroups nosound protocol unix,inet,inet6 +quiet seccomp shell none diff --git a/etc/gpredict.profile b/etc/gpredict.profile index 353ecceae..801304c18 100644 --- a/etc/gpredict.profile +++ b/etc/gpredict.profile @@ -6,13 +6,12 @@ include /etc/firejail/disable-passwdmgr.inc include /etc/firejail/disable-programs.inc # Whitelist -mkdir ~/.config/Gpredict whitelist ~/.config/Gpredict caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot nosound protocol unix,inet,inet6 @@ -21,5 +20,6 @@ shell none tracelog private-bin gpredict +private-etc fonts,resolv.conf private-dev private-tmp diff --git a/etc/gwenview.profile b/etc/gwenview.profile index 67f10c4e1..c866c9e63 100644 --- a/etc/gwenview.profile +++ b/etc/gwenview.profile @@ -7,14 +7,15 @@ include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all +nogroups nonewprivs noroot -nogroups -private-dev protocol unix seccomp nosound +private-dev + #Experimental: #shell none #private-bin gwenview diff --git a/etc/gzip.profile b/etc/gzip.profile index 5e73969c4..d51b9a951 100644 --- a/etc/gzip.profile +++ b/etc/gzip.profile @@ -1,12 +1,14 @@ # gzip profile -quiet ignore noroot include /etc/firejail/default.profile -tracelog -net none -shell none -blacklist /tmp/.X11-unix -private-dev -nosound -no3d +blacklist /tmp/.X11-unix + +net none +no3d +nosound +quiet +shell none +tracelog + +private-dev diff --git a/etc/inkscape.profile b/etc/inkscape.profile index cf885fba2..a0e86b6c9 100644 --- a/etc/inkscape.profile +++ b/etc/inkscape.profile @@ -6,13 +6,15 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter +nogroups nonewprivs noroot +nosound protocol unix seccomp -private-dev -private-tmp + noexec ${HOME} noexec /tmp -nogroups -nosound + +private-dev +private-tmp diff --git a/etc/jitsi.profile b/etc/jitsi.profile index c61158f8b..046499abe 100644 --- a/etc/jitsi.profile +++ b/etc/jitsi.profile @@ -6,8 +6,8 @@ include /etc/firejail/disable-passwdmgr.inc include /etc/firejail/disable-programs.inc caps.drop all -nonewprivs nogroups +nonewprivs noroot protocol unix,inet,inet6 seccomp diff --git a/etc/keepass.profile b/etc/keepass.profile index b2085f53d..23f9a7b40 100644 --- a/etc/keepass.profile +++ b/etc/keepass.profile @@ -13,7 +13,7 @@ nogroups nonewprivs noroot nosound -protocol unix +protocol unix,inet,inet6 seccomp netfilter shell none diff --git a/etc/kmail.profile b/etc/kmail.profile index 8c8fd18c4..bc21ba604 100644 --- a/etc/kmail.profile +++ b/etc/kmail.profile @@ -8,8 +8,8 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot protocol unix,inet,inet6,netlink seccomp diff --git a/etc/less.profile b/etc/less.profile index 6dfae027e..08758aead 100644 --- a/etc/less.profile +++ b/etc/less.profile @@ -2,8 +2,10 @@ quiet ignore noroot include /etc/firejail/default.profile -tracelog + net none -shell none -private-dev nosound +shell none +tracelog + +private-dev diff --git a/etc/libreoffice.profile b/etc/libreoffice.profile index 75a52e9ff..d6aceb7a8 100644 --- a/etc/libreoffice.profile +++ b/etc/libreoffice.profile @@ -1,5 +1,6 @@ # Firejail profile for LibreOffice noblacklist ~/.config/libreoffice +noblacklist /usr/local/sbin include /etc/firejail/disable-common.inc include /etc/firejail/disable-programs.inc include /etc/firejail/disable-devel.inc @@ -10,9 +11,9 @@ netfilter nogroups nonewprivs noroot -protocol unix,inet,inet6,netlink +protocol unix,inet,inet6 seccomp tracelog private-dev -whitelist /tmp/.X11-unix/ +# whitelist /tmp/.X11-unix/ diff --git a/etc/luminance-hdr.profile b/etc/luminance-hdr.profile index 6e059ea52..76e864e0c 100644 --- a/etc/luminance-hdr.profile +++ b/etc/luminance-hdr.profile @@ -5,17 +5,19 @@ include /etc/firejail/disable-programs.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all +ipc-namespace netfilter -protocol unix +nogroups nonewprivs noroot +nosound +protocol unix seccomp shell none tracelog -private-tmp -private-dev + noexec ${HOME} noexec /tmp -nogroups -nosound -ipc-namespace + +private-tmp +private-dev diff --git a/etc/mumble.profile b/etc/mumble.profile new file mode 100644 index 000000000..ddd70822d --- /dev/null +++ b/etc/mumble.profile @@ -0,0 +1,26 @@ +# mumble profile +noblacklist ${HOME}/.config/Mumble +noblacklist ${HOME}/.local/share/data/Mumble +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-devel.inc +include /etc/firejail/disable-passwdmgr.inc + +mkdir ${HOME}/.config/Mumble +mkdir ${HOME}/.local/share/data/Mumble +whitelist ${HOME}/.config/Mumble +whitelist ${HOME}/.local/share/data/Mumble +include /etc/firejail/whitelist-common.inc + +caps.drop all +netfilter +nonewprivs +nogroups +noroot +protocol unix,inet,inet6 +seccomp +shell none +tracelog + +private-bin mumble +private-tmp diff --git a/etc/mutt.profile b/etc/mutt.profile index cda7fc4bf..b532ded67 100644 --- a/etc/mutt.profile +++ b/etc/mutt.profile @@ -2,6 +2,7 @@ noblacklist ~/.muttrc noblacklist ~/.mutt +noblacklist ~/.mutt/muttrc noblacklist ~/.mailcap noblacklist ~/.gnupg noblacklist ~/.mail diff --git a/etc/okular.profile b/etc/okular.profile index df142ccfc..b43a5fbea 100644 --- a/etc/okular.profile +++ b/etc/okular.profile @@ -9,14 +9,15 @@ include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all -nonewprivs nogroups +nonewprivs noroot -private-dev protocol unix seccomp nosound +private-dev + #Experimental: #net none #shell none diff --git a/etc/openshot.profile b/etc/openshot.profile new file mode 100644 index 000000000..f12bd7d11 --- /dev/null +++ b/etc/openshot.profile @@ -0,0 +1,13 @@ +# OpenShot profile +noblacklist ${HOME}/.openshot +noblacklist ${HOME}/.openshot_qt +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all +netfilter +nonewprivs +noroot +protocol unix,inet,inet6,netlink +seccomp diff --git a/etc/pidgin.profile b/etc/pidgin.profile index 47be2b6ea..850706145 100644 --- a/etc/pidgin.profile +++ b/etc/pidgin.profile @@ -8,8 +8,8 @@ include /etc/firejail/disable-programs.inc caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot protocol unix,inet,inet6 seccomp diff --git a/etc/pix.profile b/etc/pix.profile index 80c05fd09..e21ddadc6 100644 --- a/etc/pix.profile +++ b/etc/pix.profile @@ -8,8 +8,8 @@ include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all -nonewprivs nogroups +nonewprivs noroot nosound protocol unix @@ -20,4 +20,3 @@ tracelog private-bin pix whitelist /tmp/.X11-unix private-dev - diff --git a/etc/psi-plus.profile b/etc/psi-plus.profile index 22c5bafc5..a9323448b 100644 --- a/etc/psi-plus.profile +++ b/etc/psi-plus.profile @@ -14,10 +14,10 @@ whitelist ~/.local/share/psi+ mkdir ~/.cache/psi+ whitelist ~/.cache/psi+ -include /etc/firejail/whitelist-common.inc - caps.drop all netfilter noroot protocol unix,inet,inet6 seccomp + +include /etc/firejail/whitelist-common.inc diff --git a/etc/qbittorrent.profile b/etc/qbittorrent.profile index 138b6db55..67829c9ca 100644 --- a/etc/qbittorrent.profile +++ b/etc/qbittorrent.profile @@ -15,6 +15,6 @@ seccomp # there are some problems with "Open destination folder", see bug #536 #shell none #private-bin qbittorrent -whitelist /tmp/.X11-unix private-dev -nosound + +whitelist /tmp/.X11-unix diff --git a/etc/qpdfview.profile b/etc/qpdfview.profile index 07ea173e6..06c0db206 100644 --- a/etc/qpdfview.profile +++ b/etc/qpdfview.profile @@ -18,5 +18,5 @@ shell none tracelog private-bin qpdfview -private-tmp private-dev +private-tmp diff --git a/etc/qtox.profile b/etc/qtox.profile index 927487037..81d8aa10e 100644 --- a/etc/qtox.profile +++ b/etc/qtox.profile @@ -11,8 +11,8 @@ whitelist ${DOWNLOADS} caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot protocol unix,inet,inet6 seccomp diff --git a/etc/quiterss.profile b/etc/quiterss.profile index 2ab5d8a8e..2b28fce73 100644 --- a/etc/quiterss.profile +++ b/etc/quiterss.profile @@ -14,16 +14,17 @@ whitelist ${HOME}/.cache/QuiteRss caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot -private-bin quiterss -private-dev nosound -#private-etc X11,ssl protocol unix,inet,inet6 seccomp shell none tracelog +private-bin quiterss +private-dev +#private-etc X11,ssl + include /etc/firejail/whitelist-common.inc diff --git a/etc/ranger.profile b/etc/ranger.profile index a040cd6bc..323e64dee 100644 --- a/etc/ranger.profile +++ b/etc/ranger.profile @@ -12,13 +12,12 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter net none +nogroups nonewprivs noroot -nogroups protocol unix seccomp nosound private-tmp private-dev - diff --git a/etc/rhythmbox.profile b/etc/rhythmbox.profile index 0e8527ae7..e5e192486 100644 --- a/etc/rhythmbox.profile +++ b/etc/rhythmbox.profile @@ -5,8 +5,8 @@ include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all -nogroups netfilter +nogroups nonewprivs noroot protocol unix,inet,inet6 diff --git a/etc/rtorrent.profile b/etc/rtorrent.profile index 15df2c374..1226a51cd 100644 --- a/etc/rtorrent.profile +++ b/etc/rtorrent.profile @@ -16,4 +16,3 @@ shell none private-bin rtorrent whitelist /tmp/.X11-unix private-dev -nosound diff --git a/etc/server.profile b/etc/server.profile index 22cef0a3c..b8a34feb2 100644 --- a/etc/server.profile +++ b/etc/server.profile @@ -6,11 +6,12 @@ include /etc/firejail/disable-common.inc include /etc/firejail/disable-programs.inc include /etc/firejail/disable-passwdmgr.inc -private -private-dev -nosound -no3d -private-tmp blacklist /tmp/.X11-unix + +no3d +nosound seccomp +private +private-dev +private-tmp diff --git a/etc/slack.profile b/etc/slack.profile index 1009f7ee0..a85a28f03 100644 --- a/etc/slack.profile +++ b/etc/slack.profile @@ -1,3 +1,4 @@ +# Firejail profile for Slack noblacklist ${HOME}/.config/Slack noblacklist ${HOME}/Downloads @@ -6,25 +7,25 @@ include /etc/firejail/disable-programs.inc include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc +blacklist /var + +caps.drop all +name slack +netfilter +nogroups +nonewprivs +noroot +protocol unix,inet,inet6,netlink +seccomp +shell none + +private-bin slack +private-dev +private-etc fonts,resolv.conf,ld.so.conf,ld.so.cache,localtime +private-tmp + mkdir ${HOME}/.config mkdir ${HOME}/.config/Slack whitelist ${HOME}/.config/Slack whitelist ${HOME}/Downloads - -protocol unix,inet,inet6,netlink -private-dev -private-tmp -private-etc fonts,resolv.conf,ld.so.conf,ld.so.cache,localtime -name slack -blacklist /var - include /etc/firejail/whitelist-common.inc - -caps.drop all -seccomp -netfilter -nonewprivs -nogroups -noroot -shell none -private-bin slack diff --git a/etc/spotify.profile b/etc/spotify.profile index 73d427db3..6dbcc03ee 100644 --- a/etc/spotify.profile +++ b/etc/spotify.profile @@ -7,16 +7,13 @@ include /etc/firejail/disable-programs.inc include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc -# Whitelist the folders needed by Spotify - This is more restrictive -# than a blacklist though, but this is all spotify requires for -# streaming audio +# Whitelist the folders needed by Spotify mkdir ${HOME}/.config/spotify whitelist ${HOME}/.config/spotify mkdir ${HOME}/.local/share/spotify whitelist ${HOME}/.local/share/spotify mkdir ${HOME}/.cache/spotify whitelist ${HOME}/.cache/spotify -include /etc/firejail/whitelist-common.inc caps.drop all netfilter @@ -27,5 +24,20 @@ protocol unix,inet,inet6,netlink seccomp shell none -#private-bin spotify +private-bin spotify +private-etc fonts,machine-id,pulse,resolv.conf private-dev +private-tmp + +blacklist ${HOME}/.Xauthority +blacklist ${HOME}/.bashrc +blacklist /boot +blacklist /lost+found +blacklist /media +blacklist /mnt +blacklist /opt +blacklist /root +blacklist /sbin +blacklist /srv +blacklist /sys +blacklist /var diff --git a/etc/start-tor-browser.profile b/etc/start-tor-browser.profile new file mode 100644 index 000000000..ee19cee25 --- /dev/null +++ b/etc/start-tor-browser.profile @@ -0,0 +1,20 @@ +# Firejail profile for the Tor Brower Bundle +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-devel.inc +include /etc/firejail/disable-passwdmgr.inc +include /etc/firejail/disable-programs.inc + +caps.drop all +netfilter +nogroups +nonewprivs +noroot +protocol unix,inet,inet6 +seccomp +shell none +tracelog + +private-bin bash,grep,sed,tail,env,gpg,id,readlink,dirname,test,mkdir,ln,sed,cp,rm,getconf +private-etc fonts +private-dev +private-tmp diff --git a/etc/strings.profile b/etc/strings.profile index f99a65009..7c464bf88 100644 --- a/etc/strings.profile +++ b/etc/strings.profile @@ -1,10 +1,11 @@ # strings profile -quiet ignore noroot include /etc/firejail/default.profile -tracelog -net none -shell none -private-dev -nosound +net none +nosound +quiet +shell none +tracelog + +private-dev diff --git a/etc/synfigstudio.profile b/etc/synfigstudio.profile index d46467b99..69b2a0db2 100644 --- a/etc/synfigstudio.profile +++ b/etc/synfigstudio.profile @@ -11,7 +11,9 @@ nonewprivs noroot protocol unix seccomp -private-dev -private-tmp + noexec ${HOME} noexec /tmp + +private-dev +private-tmp diff --git a/etc/tar.profile b/etc/tar.profile index 663ac3805..91fdaf48d 100644 --- a/etc/tar.profile +++ b/etc/tar.profile @@ -1,18 +1,18 @@ # tar profile -quiet ignore noroot include /etc/firejail/default.profile -tracelog +blacklist /tmp/.X11-unix + +hostname tar net none +no3d +nosound +quiet shell none +tracelog # support compressed archives private-bin sh,tar,gtar,compress,gzip,lzma,xz,bzip2,lbzip2,lzip,lzop private-dev -nosound -no3d private-etc passwd,group,localtime -hostname tar -blacklist /tmp/.X11-unix - diff --git a/etc/telegram.profile b/etc/telegram.profile index 8e91e426b..7615c8eef 100644 --- a/etc/telegram.profile +++ b/etc/telegram.profile @@ -10,4 +10,3 @@ nonewprivs noroot protocol unix,inet,inet6 seccomp - diff --git a/etc/transmission-gtk.profile b/etc/transmission-gtk.profile index 0cfa4fcfc..316cdfec6 100644 --- a/etc/transmission-gtk.profile +++ b/etc/transmission-gtk.profile @@ -18,6 +18,6 @@ shell none tracelog private-bin transmission-gtk -whitelist /tmp/.X11-unix private-dev +whitelist /tmp/.X11-unix diff --git a/etc/transmission-qt.profile b/etc/transmission-qt.profile index 754211a63..51c58e224 100644 --- a/etc/transmission-qt.profile +++ b/etc/transmission-qt.profile @@ -14,9 +14,10 @@ noroot nosound protocol unix,inet,inet6 seccomp +shell none tracelog -shell none private-bin transmission-qt -whitelist /tmp/.X11-unix private-dev + +whitelist /tmp/.X11-unix diff --git a/etc/uget-gtk.profile b/etc/uget-gtk.profile index 522b4bd1e..f42e6c69a 100644 --- a/etc/uget-gtk.profile +++ b/etc/uget-gtk.profile @@ -9,17 +9,16 @@ caps.drop all netfilter nonewprivs noroot +nosound protocol unix,inet,inet6 seccomp +shell none +private-bin uget-gtk +private-dev + +whitelist /tmp/.X11-unix whitelist ${DOWNLOADS} mkdir ~/.config/uGet whitelist ~/.config/uGet include /etc/firejail/whitelist-common.inc - -shell none -private-bin uget-gtk -whitelist /tmp/.X11-unix -private-dev -nosound - diff --git a/etc/unrar.profile b/etc/unrar.profile index f29d1b51b..0700cafe9 100644 --- a/etc/unrar.profile +++ b/etc/unrar.profile @@ -1,17 +1,18 @@ # unrar profile -quiet ignore noroot include /etc/firejail/default.profile -tracelog -net none -shell none -private-bin unrar -private-dev -nosound -no3d -private-etc passwd,group,localtime -hostname unrar -private-tmp blacklist /tmp/.X11-unix +hostname unrar +net none +no3d +nosound +quiet +shell none +tracelog + +private-bin unrar +private-dev +private-etc passwd,group,localtime +private-tmp diff --git a/etc/unzip.profile b/etc/unzip.profile index 07224855f..a43785795 100644 --- a/etc/unzip.profile +++ b/etc/unzip.profile @@ -1,16 +1,16 @@ # unzip profile -quiet ignore noroot include /etc/firejail/default.profile - -tracelog -net none -shell none -private-bin unzip -private-etc passwd,group,localtime -hostname unzip -private-dev -nosound -no3d blacklist /tmp/.X11-unix +hostname unzip +net none +no3d +nosound +quiet +shell none +tracelog + +private-bin unzip +private-dev +private-etc passwd,group,localtime diff --git a/etc/uudeview.profile b/etc/uudeview.profile index 8ea9d5163..5ba0896ab 100644 --- a/etc/uudeview.profile +++ b/etc/uudeview.profile @@ -1,15 +1,15 @@ # uudeview profile -quiet ignore noroot include /etc/firejail/default.profile -tracelog +blacklist /etc + +hostname uudeview net none +nosound +quiet shell none +tracelog + private-bin uudeview private-dev -private-etc nonexisting_fakefile_for_empty_etc -hostname uudeview -nosound -uudeview - diff --git a/etc/vim.profile b/etc/vim.profile index 3c1fefe41..b161fcbb0 100644 --- a/etc/vim.profile +++ b/etc/vim.profile @@ -1,5 +1,4 @@ # vim profile - noblacklist ~/.vim noblacklist ~/.vimrc noblacklist ~/.viminfo @@ -10,8 +9,8 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter +nogroups nonewprivs noroot -nogroups protocol unix,inet,inet6 seccomp diff --git a/etc/virtualbox.profile b/etc/virtualbox.profile new file mode 100644 index 000000000..148b7efc8 --- /dev/null +++ b/etc/virtualbox.profile @@ -0,0 +1,12 @@ +# VirtualBox profile + +noblacklist ${HOME}/.VirtualBox +noblacklist ${HOME}/VirtualBox VMs +noblacklist ${HOME}/.config/VirtualBox +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all + + diff --git a/etc/vlc.profile b/etc/vlc.profile index cdd098dd5..446e47864 100644 --- a/etc/vlc.profile +++ b/etc/vlc.profile @@ -14,7 +14,6 @@ noroot protocol unix,inet,inet6 seccomp shell none -tracelog private-bin vlc,cvlc,nvlc,rvlc,qvlc,svlc private-dev diff --git a/etc/whitelist-common.inc b/etc/whitelist-common.inc index fd44c2528..e533fe596 100644 --- a/etc/whitelist-common.inc +++ b/etc/whitelist-common.inc @@ -14,6 +14,7 @@ whitelist ~/.fonts.d whitelist ~/.fontconfig whitelist ~/.fonts.conf whitelist ~/.fonts.conf.d +whitelist ~/.local/share/fonts whitelist ~/.config/fontconfig whitelist ~/.cache/fontconfig diff --git a/etc/xiphos.profile b/etc/xiphos.profile new file mode 100644 index 000000000..b7fb6ecf3 --- /dev/null +++ b/etc/xiphos.profile @@ -0,0 +1,30 @@ +# Firejail profile for xiphos +noblacklist ~/.sword +noblacklist ~/.xiphos + +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-devel.inc +include /etc/firejail/disable-passwdmgr.inc +include /etc/firejail/disable-programs.inc + +blacklist ~/.bashrc +blacklist ~/.Xauthority + +caps.drop all +netfilter +nogroups +nonewprivs +noroot +nosound +protocol unix,inet,inet6 +seccomp +shell none +tracelog + +private-bin xiphos +private-etc fonts,resolv.conf,sword +private-dev +private-tmp + +whitelist ${HOME}/.sword +whitelist ${HOME}/.xiphos diff --git a/etc/xpdf.profile b/etc/xpdf.profile new file mode 100644 index 000000000..7ea368bbe --- /dev/null +++ b/etc/xpdf.profile @@ -0,0 +1,18 @@ +################################ +# xpdf application profile +################################ +noblacklist ${HOME}/.xpdfrc +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-programs.inc +include /etc/firejail/disable-passwdmgr.inc + +caps.drop all +net none +nonewprivs +noroot +protocol unix +shell none +seccomp + +private-dev +private-tmp diff --git a/etc/xplayer.profile b/etc/xplayer.profile index 54d5ed89b..191d2f67f 100644 --- a/etc/xplayer.profile +++ b/etc/xplayer.profile @@ -9,8 +9,8 @@ include /etc/firejail/disable-passwdmgr.inc caps.drop all netfilter -nonewprivs nogroups +nonewprivs noroot protocol unix,inet,inet6 seccomp diff --git a/etc/xzdec.profile b/etc/xzdec.profile index a9d027c38..04f98cef6 100644 --- a/etc/xzdec.profile +++ b/etc/xzdec.profile @@ -1,12 +1,14 @@ # xzdec profile -quiet ignore noroot include /etc/firejail/default.profile -tracelog -net none -shell none -blacklist /tmp/.X11-unix -private-dev -nosound -no3d +blacklist /tmp/.X11-unix + +net none +no3d +nosound +quiet +shell none +tracelog + +private-dev diff --git a/etc/zathura.profile b/etc/zathura.profile index d29762889..99a8ea90d 100644 --- a/etc/zathura.profile +++ b/etc/zathura.profile @@ -7,14 +7,14 @@ include /etc/firejail/disable-devel.inc include /etc/firejail/disable-passwdmgr.inc caps.drop all -seccomp -protocol unix netfilter +nogroups nonewprivs noroot -nogroups nosound shell none +seccomp +protocol unix private-bin zathura private-dev diff --git a/mkuid.sh b/mkuid.sh index c95741043..a59f58143 100755 --- a/mkuid.sh +++ b/mkuid.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh echo "extracting UID_MIN and GID_MIN" echo "#ifndef FIREJAIL_UIDS_H" > uids.h diff --git a/platform/debian/conffiles b/platform/debian/conffiles index 03fb2fe75..df660ab4f 100644 --- a/platform/debian/conffiles +++ b/platform/debian/conffiles @@ -155,3 +155,19 @@ /etc/firejail/7z.profile /etc/firejail/keepass.profile /etc/firejail/keepassx.profile +/etc/firejail/claws-mail.profile +/etc/firejail/mutt.profile +/etc/firejail/git.profile +/etc/firejail/emacs.profile +/etc/firejail/vim.profile +/etc/firejail/xpdf.profile +/etc/firejail/virtualbox.profile +/etc/firejail/openshot.profile +/etc/firejail/flowblade.profile +/etc/firejail/eog.profile +/etc/firejail/evolution.profile +/etc/firejail/start-tor-browser.profile +/etc/firejail/xiphos.profile +/etc/firejail/display.profile +/etc/firejail/Wire.profile +/etc/firejail/mumble.profile diff --git a/platform/rpm/old-mkrpm.sh b/platform/rpm/old-mkrpm.sh new file mode 100755 index 000000000..017d5e1c3 --- /dev/null +++ b/platform/rpm/old-mkrpm.sh @@ -0,0 +1,542 @@ +#!/bin/bash +VERSION="0.9.44" +rm -fr ~/rpmbuild +rm -f firejail-$VERSION-1.x86_64.rpm + +mkdir -p ~/rpmbuild/{RPMS,SRPMS,BUILD,SOURCES,SPECS,tmp} +cat <~/.rpmmacros +%_topdir %(echo $HOME)/rpmbuild +%_tmppath %{_topdir}/tmp +EOF + +cd ~/rpmbuild +echo "building directory tree" + +mkdir -p firejail-$VERSION/usr/bin +install -m 755 /usr/bin/firejail firejail-$VERSION/usr/bin/. +install -m 755 /usr/bin/firemon firejail-$VERSION/usr/bin/. +install -m 755 /usr/bin/firecfg firejail-$VERSION/usr/bin/. + +mkdir -p firejail-$VERSION/usr/lib/firejail +install -m 755 /usr/lib/firejail/faudit firejail-$VERSION/usr/lib/firejail/. +install -m 644 /usr/lib/firejail/firecfg.config firejail-$VERSION/usr/lib/firejail/. +install -m 755 /usr/lib/firejail/fshaper.sh firejail-$VERSION/usr/lib/firejail/. +install -m 755 /usr/lib/firejail/ftee firejail-$VERSION/usr/lib/firejail/. +install -m 644 /usr/lib/firejail/libtrace.so firejail-$VERSION/usr/lib/firejail/. +install -m 644 /usr/lib/firejail/libtracelog.so firejail-$VERSION/usr/lib/firejail/. +install -m 644 /usr/lib/firejail/libconnect.so firejail-$VERSION/usr/lib/firejail/. + +mkdir -p firejail-$VERSION/usr/share/man/man1 +install -m 644 /usr/share/man/man1/firejail.1.gz firejail-$VERSION/usr/share/man/man1/. +install -m 644 /usr/share/man/man1/firemon.1.gz firejail-$VERSION/usr/share/man/man1/. +install -m 644 /usr/share/man/man1/firecfg.1.gz firejail-$VERSION/usr/share/man/man1/. + +mkdir -p firejail-$VERSION/usr/share/man/man5 +install -m 644 /usr/share/man/man5/firejail-profile.5.gz firejail-$VERSION/usr/share/man/man5/. +install -m 644 /usr/share/man/man5/firejail-login.5.gz firejail-$VERSION/usr/share/man/man5/. + +mkdir -p firejail-$VERSION/usr/share/doc/packages/firejail +install -m 644 /usr/share/doc/firejail/COPYING firejail-$VERSION/usr/share/doc/packages/firejail/. +install -m 644 /usr/share/doc/firejail/README firejail-$VERSION/usr/share/doc/packages/firejail/. +install -m 644 /usr/share/doc/firejail/RELNOTES firejail-$VERSION/usr/share/doc/packages/firejail/. + +mkdir -p firejail-$VERSION/etc/firejail +install -m 644 /etc/firejail/0ad.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/abrowser.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/atom-beta.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/atom.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/atril.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/audacious.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/audacity.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/aweather.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/bitlbee.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/brave.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/cherrytree.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/chromium-browser.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/chromium.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/clementine.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/cmus.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/conkeror.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/corebird.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/cpio.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/cyberfox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/Cyberfox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/deadbeef.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/default.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/deluge.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/dillo.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/disable-common.inc firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/disable-devel.inc firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/disable-passwdmgr.inc firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/disable-programs.inc firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/dnscrypt-proxy.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/dnsmasq.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/dosbox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/dropbox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/empathy.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/eom.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/epiphany.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/evince.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/fbreader.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/file.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/filezilla.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/firefox-esr.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/firefox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/firejail.config firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/flashpeak-slimjet.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/franz.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gajim.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gitter.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gnome-chess.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gnome-mplayer.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/google-chrome-beta.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/google-chrome.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/google-chrome-stable.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/google-chrome-unstable.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/google-play-music-desktop-player.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gpredict.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gtar.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gthumb.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gwenview.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gzip.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/hedgewars.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/hexchat.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/icecat.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/icedove.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/iceweasel.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/inox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/jitsi.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/kmail.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/konversation.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/less.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/libreoffice.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/localc.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/lodraw.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/loffice.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/lofromtemplate.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/login.users firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/loimpress.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/lomath.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/loweb.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/lowriter.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/lxterminal.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/mathematica.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/Mathematica.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/mcabber.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/midori.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/mpv.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/mupen64plus.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/netsurf.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/nolocal.net firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/okular.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/openbox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/opera-beta.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/opera.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/palemoon.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/parole.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/pidgin.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/pix.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/polari.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/psi-plus.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/qbittorrent.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/qtox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/quassel.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/quiterss.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/qutebrowser.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/rhythmbox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/rtorrent.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/seamonkey-bin.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/seamonkey.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/server.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/skypeforlinux.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/skype.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/slack.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/snap.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/soffice.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/spotify.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/ssh.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/steam.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/stellarium.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/strings.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/tar.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/telegram.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/Telegram.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/thunderbird.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/totem.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/transmission-gtk.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/transmission-qt.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/uget-gtk.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/unbound.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/unrar.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/unzip.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/uudeview.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/vivaldi-beta.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/vivaldi.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/vlc.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/warzone2100.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/webserver.net firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/weechat-curses.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/weechat.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/wesnoth.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/whitelist-common.inc firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/wine.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/xchat.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/xplayer.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/xreader.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/xviewer.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/xzdec.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/xz.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/zathura.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/7z.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/keepass.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/keepassx.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/claws-mail.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/mutt.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/git.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/emacs.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/vim.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/xpdf.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/virtualbox.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/openshot.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/flowblade.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/eog.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/evolution.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/feh.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/gimp.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/inkscape.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/luminance-hdr.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/mupdf.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/qpdfview.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/ranger.profile firejail-$VERSION/etc/firejail/. +install -m 644 /etc/firejail/synfigstudio.profile firejail-$VERSION/etc/firejail/. + + +mkdir -p firejail-$VERSION/usr/share/bash-completion/completions +install -m 644 /usr/share/bash-completion/completions/firejail firejail-$VERSION/usr/share/bash-completion/completions/. +install -m 644 /usr/share/bash-completion/completions/firemon firejail-$VERSION/usr/share/bash-completion/completions/. +install -m 644 /usr/share/bash-completion/completions/firecfg firejail-$VERSION/usr/share/bash-completion/completions/. + +echo "building tar.gz archive" +tar -czvf firejail-$VERSION.tar.gz firejail-$VERSION + +cp firejail-$VERSION.tar.gz SOURCES/. + +echo "building config spec" +cat < SPECS/firejail.spec +%define __spec_install_post %{nil} +%define debug_package %{nil} +%define __os_install_post %{_dbpath}/brp-compress + +Summary: Linux namepaces sandbox program +Name: firejail +Version: $VERSION +Release: 1 +License: GPL+ +Group: Development/Tools +SOURCE0 : %{name}-%{version}.tar.gz +URL: http://firejail.wordpress.com + +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root + +%description +Firejail is a SUID sandbox program that reduces the risk of security +breaches by restricting the running environment of untrusted applications +using Linux namespaces. It includes a sandbox profile for Mozilla Firefox. + +%prep +%setup -q + +%build + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot} + +cp -a * %{buildroot} + + +%clean +rm -rf %{buildroot} + + +%files +%defattr(-,root,root,-) +%config(noreplace) %{_sysconfdir}/%{name}/0ad.profile +%config(noreplace) %{_sysconfdir}/%{name}/abrowser.profile +%config(noreplace) %{_sysconfdir}/%{name}/atom-beta.profile +%config(noreplace) %{_sysconfdir}/%{name}/atom.profile +%config(noreplace) %{_sysconfdir}/%{name}/atril.profile +%config(noreplace) %{_sysconfdir}/%{name}/audacious.profile +%config(noreplace) %{_sysconfdir}/%{name}/audacity.profile +%config(noreplace) %{_sysconfdir}/%{name}/aweather.profile +%config(noreplace) %{_sysconfdir}/%{name}/bitlbee.profile +%config(noreplace) %{_sysconfdir}/%{name}/brave.profile +%config(noreplace) %{_sysconfdir}/%{name}/cherrytree.profile +%config(noreplace) %{_sysconfdir}/%{name}/chromium-browser.profile +%config(noreplace) %{_sysconfdir}/%{name}/chromium.profile +%config(noreplace) %{_sysconfdir}/%{name}/clementine.profile +%config(noreplace) %{_sysconfdir}/%{name}/cmus.profile +%config(noreplace) %{_sysconfdir}/%{name}/conkeror.profile +%config(noreplace) %{_sysconfdir}/%{name}/corebird.profile +%config(noreplace) %{_sysconfdir}/%{name}/cpio.profile +%config(noreplace) %{_sysconfdir}/%{name}/cyberfox.profile +%config(noreplace) %{_sysconfdir}/%{name}/Cyberfox.profile +%config(noreplace) %{_sysconfdir}/%{name}/deadbeef.profile +%config(noreplace) %{_sysconfdir}/%{name}/default.profile +%config(noreplace) %{_sysconfdir}/%{name}/deluge.profile +%config(noreplace) %{_sysconfdir}/%{name}/dillo.profile +%config(noreplace) %{_sysconfdir}/%{name}/disable-common.inc +%config(noreplace) %{_sysconfdir}/%{name}/disable-devel.inc +%config(noreplace) %{_sysconfdir}/%{name}/disable-passwdmgr.inc +%config(noreplace) %{_sysconfdir}/%{name}/disable-programs.inc +%config(noreplace) %{_sysconfdir}/%{name}/dnscrypt-proxy.profile +%config(noreplace) %{_sysconfdir}/%{name}/dnsmasq.profile +%config(noreplace) %{_sysconfdir}/%{name}/dosbox.profile +%config(noreplace) %{_sysconfdir}/%{name}/dropbox.profile +%config(noreplace) %{_sysconfdir}/%{name}/empathy.profile +%config(noreplace) %{_sysconfdir}/%{name}/eom.profile +%config(noreplace) %{_sysconfdir}/%{name}/epiphany.profile +%config(noreplace) %{_sysconfdir}/%{name}/evince.profile +%config(noreplace) %{_sysconfdir}/%{name}/fbreader.profile +%config(noreplace) %{_sysconfdir}/%{name}/file.profile +%config(noreplace) %{_sysconfdir}/%{name}/filezilla.profile +%config(noreplace) %{_sysconfdir}/%{name}/firefox-esr.profile +%config(noreplace) %{_sysconfdir}/%{name}/firefox.profile +%config(noreplace) %{_sysconfdir}/%{name}/firejail.config +%config(noreplace) %{_sysconfdir}/%{name}/flashpeak-slimjet.profile +%config(noreplace) %{_sysconfdir}/%{name}/franz.profile +%config(noreplace) %{_sysconfdir}/%{name}/gajim.profile +%config(noreplace) %{_sysconfdir}/%{name}/gitter.profile +%config(noreplace) %{_sysconfdir}/%{name}/gnome-chess.profile +%config(noreplace) %{_sysconfdir}/%{name}/gnome-mplayer.profile +%config(noreplace) %{_sysconfdir}/%{name}/google-chrome-beta.profile +%config(noreplace) %{_sysconfdir}/%{name}/google-chrome.profile +%config(noreplace) %{_sysconfdir}/%{name}/google-chrome-stable.profile +%config(noreplace) %{_sysconfdir}/%{name}/google-chrome-unstable.profile +%config(noreplace) %{_sysconfdir}/%{name}/google-play-music-desktop-player.profile +%config(noreplace) %{_sysconfdir}/%{name}/gpredict.profile +%config(noreplace) %{_sysconfdir}/%{name}/gtar.profile +%config(noreplace) %{_sysconfdir}/%{name}/gthumb.profile +%config(noreplace) %{_sysconfdir}/%{name}/gwenview.profile +%config(noreplace) %{_sysconfdir}/%{name}/gzip.profile +%config(noreplace) %{_sysconfdir}/%{name}/hedgewars.profile +%config(noreplace) %{_sysconfdir}/%{name}/hexchat.profile +%config(noreplace) %{_sysconfdir}/%{name}/icecat.profile +%config(noreplace) %{_sysconfdir}/%{name}/icedove.profile +%config(noreplace) %{_sysconfdir}/%{name}/iceweasel.profile +%config(noreplace) %{_sysconfdir}/%{name}/inox.profile +%config(noreplace) %{_sysconfdir}/%{name}/jitsi.profile +%config(noreplace) %{_sysconfdir}/%{name}/kmail.profile +%config(noreplace) %{_sysconfdir}/%{name}/konversation.profile +%config(noreplace) %{_sysconfdir}/%{name}/less.profile +%config(noreplace) %{_sysconfdir}/%{name}/libreoffice.profile +%config(noreplace) %{_sysconfdir}/%{name}/localc.profile +%config(noreplace) %{_sysconfdir}/%{name}/lodraw.profile +%config(noreplace) %{_sysconfdir}/%{name}/loffice.profile +%config(noreplace) %{_sysconfdir}/%{name}/lofromtemplate.profile +%config(noreplace) %{_sysconfdir}/%{name}/login.users +%config(noreplace) %{_sysconfdir}/%{name}/loimpress.profile +%config(noreplace) %{_sysconfdir}/%{name}/lomath.profile +%config(noreplace) %{_sysconfdir}/%{name}/loweb.profile +%config(noreplace) %{_sysconfdir}/%{name}/lowriter.profile +%config(noreplace) %{_sysconfdir}/%{name}/lxterminal.profile +%config(noreplace) %{_sysconfdir}/%{name}/mathematica.profile +%config(noreplace) %{_sysconfdir}/%{name}/Mathematica.profile +%config(noreplace) %{_sysconfdir}/%{name}/mcabber.profile +%config(noreplace) %{_sysconfdir}/%{name}/midori.profile +%config(noreplace) %{_sysconfdir}/%{name}/mpv.profile +%config(noreplace) %{_sysconfdir}/%{name}/mupen64plus.profile +%config(noreplace) %{_sysconfdir}/%{name}/netsurf.profile +%config(noreplace) %{_sysconfdir}/%{name}/nolocal.net +%config(noreplace) %{_sysconfdir}/%{name}/okular.profile +%config(noreplace) %{_sysconfdir}/%{name}/openbox.profile +%config(noreplace) %{_sysconfdir}/%{name}/opera-beta.profile +%config(noreplace) %{_sysconfdir}/%{name}/opera.profile +%config(noreplace) %{_sysconfdir}/%{name}/palemoon.profile +%config(noreplace) %{_sysconfdir}/%{name}/parole.profile +%config(noreplace) %{_sysconfdir}/%{name}/pidgin.profile +%config(noreplace) %{_sysconfdir}/%{name}/pix.profile +%config(noreplace) %{_sysconfdir}/%{name}/polari.profile +%config(noreplace) %{_sysconfdir}/%{name}/psi-plus.profile +%config(noreplace) %{_sysconfdir}/%{name}/qbittorrent.profile +%config(noreplace) %{_sysconfdir}/%{name}/qtox.profile +%config(noreplace) %{_sysconfdir}/%{name}/quassel.profile +%config(noreplace) %{_sysconfdir}/%{name}/quiterss.profile +%config(noreplace) %{_sysconfdir}/%{name}/qutebrowser.profile +%config(noreplace) %{_sysconfdir}/%{name}/rhythmbox.profile +%config(noreplace) %{_sysconfdir}/%{name}/rtorrent.profile +%config(noreplace) %{_sysconfdir}/%{name}/seamonkey-bin.profile +%config(noreplace) %{_sysconfdir}/%{name}/seamonkey.profile +%config(noreplace) %{_sysconfdir}/%{name}/server.profile +%config(noreplace) %{_sysconfdir}/%{name}/skypeforlinux.profile +%config(noreplace) %{_sysconfdir}/%{name}/skype.profile +%config(noreplace) %{_sysconfdir}/%{name}/slack.profile +%config(noreplace) %{_sysconfdir}/%{name}/snap.profile +%config(noreplace) %{_sysconfdir}/%{name}/soffice.profile +%config(noreplace) %{_sysconfdir}/%{name}/spotify.profile +%config(noreplace) %{_sysconfdir}/%{name}/ssh.profile +%config(noreplace) %{_sysconfdir}/%{name}/steam.profile +%config(noreplace) %{_sysconfdir}/%{name}/stellarium.profile +%config(noreplace) %{_sysconfdir}/%{name}/strings.profile +%config(noreplace) %{_sysconfdir}/%{name}/tar.profile +%config(noreplace) %{_sysconfdir}/%{name}/telegram.profile +%config(noreplace) %{_sysconfdir}/%{name}/Telegram.profile +%config(noreplace) %{_sysconfdir}/%{name}/thunderbird.profile +%config(noreplace) %{_sysconfdir}/%{name}/totem.profile +%config(noreplace) %{_sysconfdir}/%{name}/transmission-gtk.profile +%config(noreplace) %{_sysconfdir}/%{name}/transmission-qt.profile +%config(noreplace) %{_sysconfdir}/%{name}/uget-gtk.profile +%config(noreplace) %{_sysconfdir}/%{name}/unbound.profile +%config(noreplace) %{_sysconfdir}/%{name}/unrar.profile +%config(noreplace) %{_sysconfdir}/%{name}/unzip.profile +%config(noreplace) %{_sysconfdir}/%{name}/uudeview.profile +%config(noreplace) %{_sysconfdir}/%{name}/vivaldi-beta.profile +%config(noreplace) %{_sysconfdir}/%{name}/vivaldi.profile +%config(noreplace) %{_sysconfdir}/%{name}/vlc.profile +%config(noreplace) %{_sysconfdir}/%{name}/warzone2100.profile +%config(noreplace) %{_sysconfdir}/%{name}/webserver.net +%config(noreplace) %{_sysconfdir}/%{name}/weechat-curses.profile +%config(noreplace) %{_sysconfdir}/%{name}/weechat.profile +%config(noreplace) %{_sysconfdir}/%{name}/wesnoth.profile +%config(noreplace) %{_sysconfdir}/%{name}/whitelist-common.inc +%config(noreplace) %{_sysconfdir}/%{name}/wine.profile +%config(noreplace) %{_sysconfdir}/%{name}/xchat.profile +%config(noreplace) %{_sysconfdir}/%{name}/xplayer.profile +%config(noreplace) %{_sysconfdir}/%{name}/xreader.profile +%config(noreplace) %{_sysconfdir}/%{name}/xviewer.profile +%config(noreplace) %{_sysconfdir}/%{name}/xzdec.profile +%config(noreplace) %{_sysconfdir}/%{name}/xz.profile +%config(noreplace) %{_sysconfdir}/%{name}/zathura.profile +%config(noreplace) %{_sysconfdir}/%{name}/7z.profile +%config(noreplace) %{_sysconfdir}/%{name}/keepass.profile +%config(noreplace) %{_sysconfdir}/%{name}/keepassx.profile +%config(noreplace) %{_sysconfdir}/%{name}/claws-mail.profile +%config(noreplace) %{_sysconfdir}/%{name}/mutt.profile +%config(noreplace) %{_sysconfdir}/%{name}/git.profile +%config(noreplace) %{_sysconfdir}/%{name}/emacs.profile +%config(noreplace) %{_sysconfdir}/%{name}/vim.profile +%config(noreplace) %{_sysconfdir}/%{name}/xpdf.profile +%config(noreplace) %{_sysconfdir}/%{name}/virtualbox.profile +%config(noreplace) %{_sysconfdir}/%{name}/openshot.profile +%config(noreplace) %{_sysconfdir}/%{name}/flowblade.profile +%config(noreplace) %{_sysconfdir}/%{name}/eog.profile +%config(noreplace) %{_sysconfdir}/%{name}/evolution.profile +%config(noreplace) %{_sysconfdir}/%{name}/feh.profile +%config(noreplace) %{_sysconfdir}/%{name}/inkscape.profile +%config(noreplace) %{_sysconfdir}/%{name}/gimp.profile +%config(noreplace) %{_sysconfdir}/%{name}/luminance-hdr.profile +%config(noreplace) %{_sysconfdir}/%{name}/mupdf.profile +%config(noreplace) %{_sysconfdir}/%{name}/qpdfview.profile +%config(noreplace) %{_sysconfdir}/%{name}/ranger.profile +%config(noreplace) %{_sysconfdir}/%{name}/synfigstudio.profile + +/usr/bin/firejail +/usr/bin/firemon +/usr/bin/firecfg + +/usr/lib/firejail/libtrace.so +/usr/lib/firejail/libtracelog.so +/usr/lib/firejail/libconnect.so +/usr/lib/firejail/faudit +/usr/lib/firejail/ftee +/usr/lib/firejail/firecfg.config +/usr/lib/firejail/fshaper.sh + +/usr/share/doc/packages/firejail/COPYING +/usr/share/doc/packages/firejail/README +/usr/share/doc/packages/firejail/RELNOTES +/usr/share/man/man1/firejail.1.gz +/usr/share/man/man1/firemon.1.gz +/usr/share/man/man1/firecfg.1.gz +/usr/share/man/man5/firejail-profile.5.gz +/usr/share/man/man5/firejail-login.5.gz +/usr/share/bash-completion/completions/firejail +/usr/share/bash-completion/completions/firemon +/usr/share/bash-completion/completions/firecfg + +%post +chmod u+s /usr/bin/firejail + +%changelog +* Fri Oct 21 2016 netblue30 0.9.44-1 + - CVE-2016-7545 submitted by Aleksey Manevich + - modifs: removed man firejail-config + - modifs: --private-tmp whitelists /tmp/.X11-unix directory + - modifs: Nvidia drivers added to --private-dev + - modifs: /srv supported by --whitelist + - feature: allow user access to /sys/fs (--noblacklist=/sys/fs) + - feature: support starting/joining sandbox is a single command + (--join-or-start) + - feature: X11 detection support for --audit + - feature: assign a name to the interface connected to the bridge + (--veth-name) + - feature: all user home directories are visible (--allusers) + - feature: add files to sandbox container (--put) + - feature: blocking x11 (--x11=block) + - feature: X11 security extension (--x11=xorg) + - feature: disable 3D hardware acceleration (--no3d) + - feature: x11 xpra, x11 xephyr, x11 block, allusers, no3d profile commands + - feature: move files in sandbox (--put) + - feature: accept wildcard patterns in user name field of restricted + shell login feature + - new profiles: qpdfview, mupdf, Luminance HDR, Synfig Studio, Gimp, Inkscape + - new profiles: feh, ranger, zathura, 7z, keepass, keepassx, + - new profiles: claws-mail, mutt, git, emacs, vim, xpdf, VirtualBox, OpenShot + - new profiles: Flowblade, Eye of GNOME (eog), Evolution + - bugfixes + +* Thu Sep 8 2016 netblue30 0.9.42-1 + - security: --whitelist deleted files, submitted by Vasya Novikov + - security: disable x32 ABI in seccomp, submitted by Jann Horn + - security: tighten --chroot, submitted by Jann Horn + - security: terminal sandbox escape, submitted by Stephan Sokolow + - security: several TOCTOU fixes submitted by Aleksey Manevich + - modifs: bringing back --private-home option + - modifs: deprecated --user option, please use "sudo -u username firejail" + - modifs: allow symlinks in home directory for --whitelist option + - modifs: Firejail prompt is enabled by env variable FIREJAIL_PROMPT="yes" + - modifs: recursive mkdir + - modifs: include /dev/snd in --private-dev + - modifs: seccomp filter update + - modifs: release archives moved to .xz format + - feature: AppImage support (--appimage) + - feature: AppArmor support (--apparmor) + - feature: Ubuntu snap support (/etc/firejail/snap.profile) + - feature: Sandbox auditing support (--audit) + - feature: remove environment variable (--rmenv) + - feature: noexec support (--noexec) + - feature: clean local overlay storage directory (--overlay-clean) + - feature: store and reuse overlay (--overlay-named) + - feature: allow debugging inside the sandbox with gdb and strace + (--allow-debuggers) + - feature: mkfile profile command + - feature: quiet profile command + - feature: x11 profile command + - feature: option to fix desktop files (firecfg --fix) + - compile time: Busybox support (--enable-busybox-workaround) + - compile time: disable overlayfs (--disable-overlayfs) + - compile time: disable whitlisting (--disable-whitelist) + - compile time: disable global config (--disable-globalcfg) + - run time: enable/disable overlayfs (overlayfs yes/no) + - run time: enable/disable quiet as default (quiet-by-default yes/no) + - run time: user-defined network filter (netfilter-default) + - run time: enable/disable whitelisting (whitelist yes/no) + - run time: enable/disable remounting of /proc and /sys + (remount-proc-sys yes/no) + - run time: enable/disable chroot desktop features (chroot-desktop yes/no) + - profiles: Gitter, gThumb, mpv, Franz messenger, LibreOffice + - profiles: pix, audacity, xz, xzdec, gzip, cpio, less + - profiles: Atom Beta, Atom, jitsi, eom, uudeview + - profiles: tar (gtar), unzip, unrar, file, skypeforlinux, + - profiles: inox, Slack, gnome-chess. Gajim IM client, DOSBox + - bugfixes + +EOF + +echo "building rpm" +rpmbuild -ba SPECS/firejail.spec +rpm -qpl RPMS/x86_64/firejail-$VERSION-1.x86_64.rpm +cd .. +rm -f firejail-$VERSION-1.x86_64.rpm +cp rpmbuild/RPMS/x86_64/firejail-$VERSION-1.x86_64.rpm . + diff --git a/src/faudit/syscall.c b/src/faudit/syscall.c index 9924be00f..3c87305df 100644 --- a/src/faudit/syscall.c +++ b/src/faudit/syscall.c @@ -92,7 +92,8 @@ void syscall_run(const char *name) { errExit("fork"); if (child == 0) { execl(prog, prog, "syscall", name, NULL); - exit(1); + perror("execl"); + _exit(1); } // wait for the child to finish diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config index 95d3d5caa..e3e333497 100644 --- a/src/firecfg/firecfg.config +++ b/src/firecfg/firecfg.config @@ -42,11 +42,13 @@ opera-beta opera palemoon qutebrowser +start-tor-browser seamonkey seamonkey-bin thunderbird vivaldi-beta vivaldi +evolution # chat/messaging bitlbee @@ -76,6 +78,7 @@ unbound mupen64plus wine dosbox +virtualbox # games 0ad @@ -134,8 +137,12 @@ Mathematica mathematica okular pix +xpdf xreader zathura +openshot +flowblade +eog # other ssh @@ -144,6 +151,7 @@ atom ranger keepass keepassx +xiphos # weather/climate aweather diff --git a/src/firejail/Makefile.in b/src/firejail/Makefile.in index fce460906..c99b6c30c 100644 --- a/src/firejail/Makefile.in +++ b/src/firejail/Makefile.in @@ -30,11 +30,11 @@ BINOBJS = $(foreach file, $(OBJS), $file) CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread -%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/libnetlink.h ../include/pid.h +%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/euid_common.h ../include/pid.h ../include/seccomp.h ../include/syscall.h $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ firejail: $(OBJS) ../lib/libnetlink.o ../lib/common.o - $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) + $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/common.o $(LIBS) $(EXTRA_LDFLAGS) clean:; rm -f *.o firejail firejail.1 firejail.1.gz diff --git a/src/firejail/appimage.c b/src/firejail/appimage.c index 05bd8a1d8..322798ee5 100644 --- a/src/firejail/appimage.c +++ b/src/firejail/appimage.c @@ -39,7 +39,7 @@ void appimage_set(const char *appimage_path) { assert(appimage_path); assert(devloop == NULL); // don't call this twice! EUID_ASSERT(); - + #ifdef LOOP_CTL_GET_FREE // test for older kernels; this definition is found in /usr/include/linux/loop.h // check appimage_path if (access(appimage_path, R_OK) == -1) { @@ -47,6 +47,12 @@ void appimage_set(const char *appimage_path) { exit(1); } + // get appimage type and ELF size + // a value of 0 means we are dealing with a type1 appimage + long unsigned int size = appimage2_size(appimage_path); + if (arg_debug) + printf("AppImage ELF size %lu\n", size); + // open as user to prevent race condition int ffd = open(appimage_path, O_RDONLY|O_CLOEXEC); if (ffd == -1) { @@ -54,9 +60,8 @@ void appimage_set(const char *appimage_path) { exit(1); } - EUID_ROOT(); - // find or allocate a free loop device to use + EUID_ROOT(); int cfd = open("/dev/loop-control", O_RDWR); int devnr = ioctl(cfd, LOOP_CTL_GET_FREE); if (devnr == -1) { @@ -72,38 +77,56 @@ void appimage_set(const char *appimage_path) { fprintf(stderr, "Error: cannot configure the loopback device\n"); exit(1); } + + if (size) { + struct loop_info64 info; + memset(&info, 0, sizeof(struct loop_info64)); + info.lo_offset = size; + if (ioctl(lfd, LOOP_SET_STATUS64, &info) == -1) + errExit("configure appimage offset"); + } + close(lfd); close(ffd); - EUID_USER(); - // creates directory with perms 0700 - char dirname[] = "/tmp/firejail-mnt-XXXXXX"; - mntdir = strdup(mkdtemp(dirname)); - if (mntdir == NULL) { - fprintf(stderr, "Error: cannot create temporary directory\n"); + // creates appimage mount point perms 0700 + if (asprintf(&mntdir, "%s/.appimage-%u", RUN_FIREJAIL_APPIMAGE_DIR, getpid()) == -1) + errExit("asprintf"); + EUID_ROOT(); + if (mkdir(mntdir, 0700) == -1) { + fprintf(stderr, "Error: cannot create appimage mount point\n"); exit(1); } if (chmod(mntdir, 0700) == -1) errExit("chmod"); + if (chown(mntdir, getuid(), getgid()) == -1) + errExit("chown"); + EUID_USER(); ASSERT_PERMS(mntdir, getuid(), getgid(), 0700); + // mount char *mode; if (asprintf(&mode, "mode=700,uid=%d,gid=%d", getuid(), getgid()) == -1) errExit("asprintf"); - EUID_ROOT(); - if (mount(devloop, mntdir, "iso9660",MS_MGC_VAL|MS_RDONLY, mode) < 0) - errExit("mounting appimage"); - + + if (size == 0) { + if (mount(devloop, mntdir, "iso9660",MS_MGC_VAL|MS_RDONLY, mode) < 0) + errExit("mounting appimage"); + } + else { + if (mount(devloop, mntdir, "squashfs",MS_MGC_VAL|MS_RDONLY, mode) < 0) + errExit("mounting appimage"); + } if (arg_debug) printf("appimage mounted on %s\n", mntdir); EUID_USER(); + // set environment if (appimage_path && setenv("APPIMAGE", appimage_path, 1) < 0) errExit("setenv"); - if (mntdir && setenv("APPDIR", mntdir, 1) < 0) errExit("setenv"); @@ -121,16 +144,32 @@ void appimage_set(const char *appimage_path) { void appimage_clear(void) { int rv; + EUID_ROOT(); if (mntdir) { - rv = umount2(mntdir, MNT_FORCE); - if (rv == -1 && errno == EBUSY) { - sleep(1); + int i; + int rv = 0; + for (i = 0; i < 5; i++) { rv = umount2(mntdir, MNT_FORCE); - (void) rv; + if (rv == 0) + break; + if (rv == -1 && errno == EBUSY) { + if (!arg_quiet) + printf("Warning: EBUSY error trying to unmount %s\n", mntdir); + sleep(2); + continue; + } + // rv = -1 + if (!arg_quiet) { + printf("Warning: error trying to unmount %s\n", mntdir); + perror("umount"); + } + } + + if (rv == 0) { + rmdir(mntdir); + free(mntdir); } - rmdir(mntdir); - free(mntdir); } if (devloop) { diff --git a/src/firejail/appimage_size.c b/src/firejail/appimage_size.c new file mode 100644 index 000000000..3f5c3150c --- /dev/null +++ b/src/firejail/appimage_size.c @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +/* +Compile with: +gcc elfsize.c -o elfsize +Example: +ls -l 126584 +Calculation using the values also reported by readelf -h: +Start of section headers e_shoff 124728 +Size of section headers e_shentsize 64 +Number of section headers e_shnum 29 +e_shoff + ( e_shentsize * e_shnum ) = 126584 +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef Elf32_Nhdr Elf_Nhdr; + +static Elf64_Ehdr ehdr; + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define ELFDATANATIVE ELFDATA2LSB +#elif __BYTE_ORDER == __BIG_ENDIAN +#define ELFDATANATIVE ELFDATA2MSB +#else +#error "Unknown machine endian" +#endif + +static uint16_t file16_to_cpu(uint16_t val) { + if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) + val = bswap_16(val); + return val; +} + + +static uint32_t file32_to_cpu(uint32_t val) { + if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) + val = bswap_32(val); + return val; +} + + +static uint64_t file64_to_cpu(uint64_t val) { + if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE) + val = bswap_64(val); + return val; +} + + +// return 0 if error +static long unsigned int read_elf32(int fd) { + Elf32_Ehdr ehdr32; + ssize_t ret; + + ret = pread(fd, &ehdr32, sizeof(ehdr32), 0); + if (ret < 0 || (size_t)ret != sizeof(ehdr)) + return 0; + + ehdr.e_shoff = file32_to_cpu(ehdr32.e_shoff); + ehdr.e_shentsize = file16_to_cpu(ehdr32.e_shentsize); + ehdr.e_shnum = file16_to_cpu(ehdr32.e_shnum); + + return(ehdr.e_shoff + (ehdr.e_shentsize * ehdr.e_shnum)); +} + + +// return 0 if error +static long unsigned int read_elf64(int fd) { + Elf64_Ehdr ehdr64; + ssize_t ret; + + ret = pread(fd, &ehdr64, sizeof(ehdr64), 0); + if (ret < 0 || (size_t)ret != sizeof(ehdr)) + return 0; + + ehdr.e_shoff = file64_to_cpu(ehdr64.e_shoff); + ehdr.e_shentsize = file16_to_cpu(ehdr64.e_shentsize); + ehdr.e_shnum = file16_to_cpu(ehdr64.e_shnum); + + return(ehdr.e_shoff + (ehdr.e_shentsize * ehdr.e_shnum)); +} + + +// return 0 if error +// return 0 if this is not an appimgage2 file +long unsigned int appimage2_size(const char *fname) { +/* TODO, FIXME: This assumes that the section header table (SHT) is +the last part of the ELF. This is usually the case but +it could also be that the last section is the last part +of the ELF. This should be checked for. +*/ + ssize_t ret; + int fd; + long unsigned int size = 0; + + fd = open(fname, O_RDONLY); + if (fd < 0) + return 0; + + ret = pread(fd, ehdr.e_ident, EI_NIDENT, 0); + if (ret != EI_NIDENT) + goto getout; + + if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) && + (ehdr.e_ident[EI_DATA] != ELFDATA2MSB)) + goto getout; + + if(ehdr.e_ident[EI_CLASS] == ELFCLASS32) { + size = read_elf32(fd); + } + else if(ehdr.e_ident[EI_CLASS] == ELFCLASS64) { + size = read_elf64(fd); + } + else { + goto getout; + } + if (size == 0) + goto getout; + + + // look for a LZMA header at this location + unsigned char buf[4]; + ret = pread(fd, buf, 4, size); + if (ret != 4) { + size = 0; + goto getout; + } + if (memcmp(buf, "hsqs", 4) != 0) + size = 0; + +getout: + close(fd); + return size; +} + + diff --git a/src/firejail/arp.c b/src/firejail/arp.c index fb5e426b0..ddb75905f 100644 --- a/src/firejail/arp.c +++ b/src/firejail/arp.c @@ -40,6 +40,7 @@ typedef struct arp_hdr_t { uint8_t target_ip[4]; } ArpHdr; + // returns 0 if the address is not in use, -1 otherwise int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr) { if (strlen(dev) > IFNAMSIZ) { @@ -286,189 +287,4 @@ uint32_t arp_assign(const char *dev, Bridge *br) { return ip; } -// scan interface (--scan option) -void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) { - assert(dev); - assert(ifip); - -// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n", -// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask)); - - if (strlen(dev) > IFNAMSIZ) { - fprintf(stderr, "Error: invalid network device name %s\n", dev); - exit(1); - } - - // find interface mac address - int sock; - if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) - errExit("socket"); - struct ifreq ifr; - memset(&ifr, 0, sizeof (ifr)); - strncpy(ifr.ifr_name, dev, IFNAMSIZ); - if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) - errExit("ioctl"); - close(sock); - uint8_t mac[6]; - memcpy (mac, ifr.ifr_hwaddr.sa_data, 6); - - // open layer2 socket - if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) - errExit("socket"); - - // try all possible ip addresses in ascending order - uint32_t range = ~ifmask + 1; // the number of potential addresses - // this software is not supported for /31 networks - if (range < 4) { - fprintf(stderr, "Warning: this option is not supported for /31 networks\n"); - close(sock); - return; - } - - uint32_t dest = (ifip & ifmask) + 1; - uint32_t last = dest + range - 1; - uint32_t src = htonl(ifip); - - // wait not more than one second for an answer - int header_printed = 0; - uint32_t last_ip = 0; - struct timeval ts; - ts.tv_sec = 2; // 2 seconds receive timeout - ts.tv_usec = 0; - - while (1) { - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(sock, &rfds); - fd_set wfds; - FD_ZERO(&wfds); - FD_SET(sock, &wfds); - int maxfd = sock; - - uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc - memset(frame, 0, ETH_FRAME_LEN); - - int nready; - if (dest < last) - nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL); - else - nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts); - - if (nready < 0) - errExit("select"); - - if (nready == 0) { // timeout - break; - } - - if (FD_ISSET(sock, &wfds) && dest < last) { - // configure layer2 socket address information - struct sockaddr_ll addr; - memset(&addr, 0, sizeof(addr)); - if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) - errExit("if_nametoindex"); - addr.sll_family = AF_PACKET; - memcpy (addr.sll_addr, mac, 6); - addr.sll_halen = htons(6); - - // build the arp packet header - ArpHdr hdr; - memset(&hdr, 0, sizeof(hdr)); - hdr.htype = htons(1); - hdr.ptype = htons(ETH_P_IP); - hdr.hlen = 6; - hdr.plen = 4; - hdr.opcode = htons(1); //ARPOP_REQUEST - memcpy(hdr.sender_mac, mac, 6); - memcpy(hdr.sender_ip, (uint8_t *)&src, 4); - uint32_t dst = htonl(dest); - memcpy(hdr.target_ip, (uint8_t *)&dst, 4); - - // build ethernet frame - uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc - memset(frame, 0, sizeof(frame)); - frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; - memcpy(frame + 6, mac, 6); - frame[12] = ETH_P_ARP / 256; - frame[13] = ETH_P_ARP % 256; - memcpy (frame + 14, &hdr, sizeof(hdr)); - - // send packet - int len; - if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) - errExit("send"); -//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest)); - fflush(0); - dest++; - } - - if (FD_ISSET(sock, &rfds)) { - // read the incoming packet - int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); - if (len < 0) { - perror("recvfrom"); - } - - // parse the incoming packet - if ((unsigned int) len < 14 + sizeof(ArpHdr)) - continue; - - // look only at ARP packets - if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) - continue; - - ArpHdr hdr; - memcpy(&hdr, frame + 14, sizeof(ArpHdr)); - - if (hdr.opcode == htons(2)) { - // check my mac and my address - if (memcmp(mac, hdr.target_mac, 6) != 0) - continue; - uint32_t ip; - memcpy(&ip, hdr.target_ip, 4); - if (ip != src) - continue; - memcpy(&ip, hdr.sender_ip, 4); - ip = ntohl(ip); - - if (ip == last_ip) // filter duplicates - continue; - last_ip = ip; - - // printing - if (header_printed == 0) { - printf(" Network scan:\n"); - - // print parent interface - if (cfg.bridge0.configured && cfg.bridge0.ip && cfg.bridge0.macvlan && - (cfg.bridge0.ip & cfg.bridge0.mask) == (ifip & cfg.bridge0.mask)) - printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", - PRINT_MAC(cfg.bridge0.mac), PRINT_IP(cfg.bridge0.ip)); - - if (cfg.bridge1.configured && cfg.bridge1.ip && cfg.bridge1.macvlan && - (cfg.bridge1.ip & cfg.bridge1.mask) == (ifip & cfg.bridge1.mask)) - printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", - PRINT_MAC(cfg.bridge1.mac), PRINT_IP(cfg.bridge1.ip)); - - if (cfg.bridge2.configured && cfg.bridge2.ip && cfg.bridge2.macvlan && - (cfg.bridge2.ip & cfg.bridge2.mask) == (ifip & cfg.bridge2.mask)) - printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", - PRINT_MAC(cfg.bridge2.mac), PRINT_IP(cfg.bridge2.ip)); - - if (cfg.bridge3.configured && cfg.bridge3.ip && cfg.bridge3.macvlan && - (cfg.bridge3.ip & cfg.bridge3.mask) == (ifip & cfg.bridge3.mask)) - printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", - PRINT_MAC(cfg.bridge3.mac), PRINT_IP(cfg.bridge3.ip)); - - header_printed = 1; - } - printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", - PRINT_MAC(hdr.sender_mac), PRINT_IP(ip)); - } - } - } - - close(sock); -} - diff --git a/src/firejail/errno.c b/src/firejail/errno.c index c493dfa09..8215c99a1 100644 --- a/src/firejail/errno.c +++ b/src/firejail/errno.c @@ -17,7 +17,6 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #ifdef HAVE_SECCOMP #include "firejail.h" #include @@ -205,16 +204,4 @@ char *errno_find_nr(int nr) { return "unknown"; } - -void errno_print(void) { - EUID_ASSERT(); - - int i; - int elems = sizeof(errnolist) / sizeof(errnolist[0]); - for (i = 0; i < elems; i++) { - printf("%d\t- %s\n", errnolist[i].nr, errnolist[i].name); - } - printf("\n"); -} - #endif // HAVE_SECCOMP diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index f4d468394..cf540ff91 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h @@ -28,6 +28,7 @@ // filesystem #define RUN_FIREJAIL_BASEDIR "/run" #define RUN_FIREJAIL_DIR "/run/firejail" +#define RUN_FIREJAIL_APPIMAGE_DIR "/run/firejail/appimage" #define RUN_FIREJAIL_NAME_DIR "/run/firejail/name" #define RUN_FIREJAIL_X11_DIR "/run/firejail/x11" #define RUN_FIREJAIL_NETWORK_DIR "/run/firejail/network" @@ -36,7 +37,6 @@ #define RUN_RO_DIR "/run/firejail/firejail.ro.dir" #define RUN_RO_FILE "/run/firejail/firejail.ro.file" #define RUN_MNT_DIR "/run/firejail/mnt" // a tmpfs is mounted on this directory before any of the files below are created -#define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" #define RUN_CGROUP_CFG "/run/firejail/mnt/cgroup" #define RUN_CPU_CFG "/run/firejail/mnt/cpu" #define RUN_GROUPS_CFG "/run/firejail/mnt/groups" @@ -47,6 +47,12 @@ #define RUN_BIN_DIR "/run/firejail/mnt/bin" #define RUN_PULSE_DIR "/run/firejail/mnt/pulse" +#define RUN_SECCOMP_CFG "/run/firejail/mnt/seccomp" // configured filter +#define RUN_SECCOMP_PROTOCOL "/run/firejail/mnt/seccomp.protocol" // protocol filter +#define RUN_SECCOMP_AMD64 "/run/firejail/mnt/seccomp.amd64" // amd64 filter installed on i386 architectures +#define RUN_SECCOMP_I386 "/run/firejail/mnt/seccomp.i386" // i386 filter installed on amd64 architectures + + #define RUN_DEV_DIR "/run/firejail/mnt/dev" #define RUN_DEVLOG_FILE "/run/firejail/mnt/devlog" @@ -59,6 +65,7 @@ #define RUN_WHITELIST_VAR_DIR "/run/firejail/mnt/orig-var" #define RUN_WHITELIST_DEV_DIR "/run/firejail/mnt/orig-dev" #define RUN_WHITELIST_OPT_DIR "/run/firejail/mnt/orig-opt" +#define RUN_WHITELIST_SRV_DIR "/run/firejail/mnt/orig-srv" #define RUN_XAUTHORITY_FILE "/run/firejail/mnt/.Xauthority" #define RUN_XAUTHORITY_SEC_FILE "/run/firejail/mnt/sec.Xauthority" @@ -72,6 +79,8 @@ #define RUN_GROUP_FILE "/run/firejail/mnt/group" #define RUN_FSLOGGER_FILE "/run/firejail/mnt/fslogger" + + // profiles #define DEFAULT_USER_PROFILE "default" #define DEFAULT_ROOT_PROFILE "server" @@ -172,6 +181,7 @@ typedef struct profile_entry_t { unsigned var_dir:1; // whitelist in /var directory unsigned dev_dir:1; // whitelist in /dev directory unsigned opt_dir:1; // whitelist in /opt directory + unsigned srv_dir:1; // whitelist in /srv directory }ProfileEntry; typedef struct config_t { @@ -358,21 +368,19 @@ void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu); void net_if_ip6(const char *ifname, const char *addr6); int net_get_if_addr(const char *bridge, uint32_t *ip, uint32_t *mask, uint8_t mac[6], int *mtu); int net_add_route(uint32_t dest, uint32_t mask, uint32_t gw); -void net_ifprint(void); -void net_bridge_add_interface(const char *bridge, const char *dev); uint32_t network_get_defaultgw(void); int net_config_mac(const char *ifname, const unsigned char mac[6]); int net_get_mac(const char *ifname, unsigned char mac[6]); +void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu); + +// preproc.c +void preproc_build_firejail_dir(void); +void preproc_mount_mnt_dir(void); +void preproc_build_cp_command(void); +void preproc_delete_cp_command(void) ; +void preproc_remount_mnt_dir(void); // fs.c -// build /run/firejail directory -void fs_build_firejail_dir(void); -// build /run/firejail/mnt directory -void fs_build_mnt_dir(void); -// grab a copy of cp command -void fs_build_cp_command(void); -// delete the temporary cp command -void fs_delete_cp_command(void) ; // blacklist files or directoies by mounting empty files on top of them void fs_blacklist(void); // remount a directory read-only @@ -389,7 +397,6 @@ void fs_overlayfs(void); // chroot into an existing directory; mount exiting /dev and update /etc/resolv.conf void fs_chroot(const char *rootdir); int fs_check_chroot_dir(const char *rootdir); -void fs_private_tmp(void); // profile.c // find and read the profile specified by name from dir directory @@ -426,13 +433,6 @@ int restricted_shell(const char *user); int arp_check(const char *dev, uint32_t destaddr, uint32_t srcaddr); // assign an IP address using arp scanning uint32_t arp_assign(const char *dev, Bridge *br); -// scan interface (--scan option) -void arp_scan(const char *dev, uint32_t srcaddr, uint32_t srcmask); - -// veth.c -int net_create_veth(const char *dev, const char *nsdev, unsigned pid); -int net_create_macvlan(const char *dev, const char *parent, unsigned pid); -int net_move_interface(const char *dev, unsigned pid); // util.c void drop_privs(int nogroups); @@ -457,10 +457,11 @@ char *expand_home(const char *path, const char* homedir); const char *gnu_basename(const char *path); uid_t pid_get_uid(pid_t pid); void invalid_filename(const char *fname); -uid_t get_tty_gid(void); -uid_t get_audio_gid(void); +uid_t get_group_id(const char *group); int remove_directory(const char *path); void flush_stdin(void); +void create_empty_dir_as_root(const char *dir, mode_t mode); +void create_empty_file_as_root(const char *dir, mode_t mode); // fs_var.c void fs_var_log(void); // mounting /var/log @@ -495,12 +496,14 @@ void fs_private_home_list(void); // seccomp.c +int seccomp_load(const char *fname); +void seccomp_filter_32(void); +void seccomp_filter_64(void); int seccomp_filter_drop(int enforce_seccomp); int seccomp_filter_keep(void); -void seccomp_set(void); +int seccomp_filter_errno(void); void seccomp_print_filter_name(const char *name); void seccomp_print_filter(pid_t pid); -int seccomp_filter_errno(void); // caps.c int caps_default_filter(void); @@ -517,8 +520,6 @@ void caps_print_filter_name(const char *name); const char *syscall_find_nr(int nr); // return -1 if error, 0 if no error int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg); -// print all available syscallsseccomp -void syscall_print(void); // fs_trace.c void fs_trace_preload(void); @@ -597,13 +598,10 @@ void fs_check_bin_list(void); void fs_private_bin_list(void); // protocol.c -void protocol_list(); -void protocol_print_filter_name(const char *name); -void protocol_print_filter(pid_t pid); -void protocol_store(const char *prlist); -void protocol_filter(void); void protocol_filter_save(void); void protocol_filter_load(const char *fname); +void protocol_print_filter_name(const char *name); +void protocol_print_filter(pid_t pid); // restrict_users.c void restrict_users(void); @@ -672,14 +670,33 @@ extern char *xephyr_extra_params; extern char *netfilter_default; int checkcfg(int val); void print_compiletime_support(void); +void x11_xorg(void); // appimage.c void appimage_set(const char *appimage_path); void appimage_clear(void); const char *appimage_getdir(void); +// appimage_size.c +long unsigned int appimage2_size(const char *fname); + // cmdline.c void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index); +// sbox.c +// programs +#define PATH_FNET (LIBDIR "/firejail/fnet") +#define PATH_FIREMON (PREFIX "/bin/firemon") +#define PATH_FSECCOMP (LIBDIR "/firejail/fseccomp") +// bitmapped filters for sbox_run +#define SBOX_ROOT (1 << 0) +#define SBOX_USER (1 << 1) +#define SBOX_SECCOMP (1 << 2) +#define SBOX_CAPS_NONE (1 << 3) // drop all capabilities +#define SBOX_CAPS_NETWORK (1 << 4) // caps filter for programs running network programs +// run sbox +int sbox_run(unsigned filter, int num, ...); + + #endif diff --git a/src/firejail/fs.c b/src/firejail/fs.c index b40f8a3fa..dbd7eced7 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c @@ -29,149 +29,7 @@ static void fs_rdwr(const char *dir); -static void create_dir_as_root(const char *dir, mode_t mode) { - assert(dir); - if (arg_debug) - printf("Creating %s directory\n", dir); - if (mkdir(dir, mode) == -1) - errExit("mkdir"); - if (chmod(dir, mode) == -1) - errExit("chmod"); - - ASSERT_PERMS(dir, 0, 0, mode); -} - -static void create_empty_dir(void) { - struct stat s; - - if (stat(RUN_RO_DIR, &s)) { - /* coverity[toctou] */ - if (mkdir(RUN_RO_DIR, S_IRUSR | S_IXUSR) == -1) - errExit("mkdir"); - if (chmod(RUN_RO_DIR, S_IRUSR | S_IXUSR) == -1) - errExit("chmod"); - ASSERT_PERMS(RUN_RO_DIR, 0, 0, S_IRUSR | S_IXUSR); - } -} - -static void create_empty_file(void) { - struct stat s; - - if (stat(RUN_RO_FILE, &s)) { - /* coverity[toctou] */ - FILE *fp = fopen(RUN_RO_FILE, "w"); - if (!fp) - errExit("fopen"); - - SET_PERMS_STREAM(fp, 0, 0, S_IRUSR); - fclose(fp); - } -} - -// build /run/firejail directory -void fs_build_firejail_dir(void) { - struct stat s; - - // CentOS 6 doesn't have /run directory - if (stat(RUN_FIREJAIL_BASEDIR, &s)) { - create_dir_as_root(RUN_FIREJAIL_BASEDIR, 0755); - } - else { // check /tmp/firejail directory belongs to root end exit if doesn't! - if (s.st_uid != 0 || s.st_gid != 0) { - fprintf(stderr, "Error: non-root %s directory, exiting...\n", RUN_FIREJAIL_DIR); - exit(1); - } - } - - if (stat(RUN_FIREJAIL_DIR, &s)) { - create_dir_as_root(RUN_FIREJAIL_DIR, 0755); - } - - if (stat(RUN_FIREJAIL_NETWORK_DIR, &s)) { - create_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755); - } - - if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s)) { - create_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755); - } - - if (stat(RUN_FIREJAIL_NAME_DIR, &s)) { - create_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755); - } - - if (stat(RUN_FIREJAIL_X11_DIR, &s)) { - create_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755); - } - - create_empty_dir(); - create_empty_file(); -} - - -// build /tmp/firejail/mnt directory -static int tmpfs_mounted = 0; -#ifdef HAVE_CHROOT -static void fs_build_remount_mnt_dir(void) { - tmpfs_mounted = 0; - fs_build_mnt_dir(); -} -#endif - -void fs_build_mnt_dir(void) { - struct stat s; - fs_build_firejail_dir(); - - // create /run/firejail/mnt directory - if (stat(RUN_MNT_DIR, &s)) { - create_dir_as_root(RUN_MNT_DIR, 0755); - } - - // ... and mount tmpfs on top of it - if (!tmpfs_mounted) { - // mount tmpfs on top of /run/firejail/mnt - if (arg_debug) - printf("Mounting tmpfs on %s directory\n", RUN_MNT_DIR); - if (mount("tmpfs", RUN_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) - errExit("mounting /tmp/firejail/mnt"); - tmpfs_mounted = 1; - fs_logger2("tmpfs", RUN_MNT_DIR); - } -} - -// grab a copy of cp command -void fs_build_cp_command(void) { - struct stat s; - fs_build_mnt_dir(); - if (stat(RUN_CP_COMMAND, &s)) { - char* fname = realpath("/bin/cp", NULL); - if (fname == NULL) { - fprintf(stderr, "Error: /bin/cp not found\n"); - exit(1); - } - if (stat(fname, &s)) { - fprintf(stderr, "Error: /bin/cp not found\n"); - exit(1); - } - if (is_link(fname)) { - fprintf(stderr, "Error: invalid /bin/cp file\n"); - exit(1); - } - int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755); - if (rv) { - fprintf(stderr, "Error: cannot access /bin/cp\n"); - exit(1); - } - ASSERT_PERMS(RUN_CP_COMMAND, 0, 0, 0755); - - free(fname); - } -} - -// delete the temporary cp command -void fs_delete_cp_command(void) { - unlink(RUN_CP_COMMAND); -} //*********************************************** // process profile file @@ -197,9 +55,6 @@ static void disable_file(OPERATION op, const char *filename) { assert(op srv_dir) { + fname = path + 4; // strlen("/srv") + if (*fname == '\0') { + fprintf(stderr, "Error: file %s is not in /srv directory, exiting...\n", path); + exit(1); + } + if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_SRV_DIR, fname) == -1) + errExit("asprintf"); + } // check if the file exists struct stat s; if (wfile && stat(wfile, &s) == 0) { @@ -317,7 +326,7 @@ void fs_whitelist(void) { int var_dir = 0; // /var directory flag int dev_dir = 0; // /dev directory flag int opt_dir = 0; // /opt directory flag - + int srv_dir = 0; // /srv directory flag // verify whitelist files, extract symbolic links, etc. while (entry) { // handle only whitelist commands @@ -387,7 +396,9 @@ void fs_whitelist(void) { dev_dir = 1; else if (strncmp(new_name, "/opt/", 5) == 0) opt_dir = 1; - + else if (strncmp(new_name, "/srv/", 5) == 0) + opt_dir = 1; + continue; } @@ -481,6 +492,16 @@ void fs_whitelist(void) { goto errexit; } } + else if (strncmp(new_name, "/srv/", 5) == 0) { + entry->srv_dir = 1; + srv_dir = 1; + // both path and absolute path are under /srv + if (strncmp(fname, "/srv/", 5) != 0) { + if (arg_debug) + fprintf(stderr, "Debug %d: fname #%s#\n", __LINE__, fname); + goto errexit; + } + } else { if (arg_debug) fprintf(stderr, "Debug %d: \n", __LINE__); @@ -508,10 +529,6 @@ void fs_whitelist(void) { entry = entry->next; } - // create mount points - fs_build_mnt_dir(); - - // /home/user if (home_dir) { // keep a copy of real home dir in RUN_WHITELIST_HOME_USER_DIR @@ -550,29 +567,6 @@ void fs_whitelist(void) { if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=1777,gid=0") < 0) errExit("mounting tmpfs on /tmp"); fs_logger("tmpfs /tmp"); - - // mount appimage directory if necessary - if (arg_appimage) { - const char *dir = appimage_getdir(); - assert(dir); - char *wdir; - if (asprintf(&wdir, "%s/%s", RUN_WHITELIST_TMP_DIR, dir + 4) == -1) - errExit("asprintf"); - - // create directory - if (mkdir(dir, 0755) < 0) - errExit("mkdir"); - if (chown(dir, getuid(), getgid()) < 0) - errExit("chown"); - if (chmod(dir, 0755) < 0) - errExit("chmod"); - - // mount - if (mount(wdir, dir, NULL, MS_BIND|MS_REC, NULL) < 0) - errExit("mount bind"); - fs_logger2("whitelist", dir); - free(wdir); - } } // /media mountpoint @@ -698,6 +692,36 @@ void fs_whitelist(void) { fs_logger("tmpfs /opt"); } + // /srv mountpoint + if (srv_dir) { + // check if /srv directory exists + struct stat s; + if (stat("/srv", &s) == 0) { + // keep a copy of real /srv directory in RUN_WHITELIST_SRV_DIR + int rv = mkdir(RUN_WHITELIST_SRV_DIR, 0755); + if (rv == -1) + errExit("mkdir"); + if (chown(RUN_WHITELIST_SRV_DIR, 0, 0) < 0) + errExit("chown"); + if (chmod(RUN_WHITELIST_SRV_DIR, 0755) < 0) + errExit("chmod"); + + if (mount("/srv", RUN_WHITELIST_SRV_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) + errExit("mount bind"); + + // mount tmpfs on /srv + if (arg_debug || arg_debug_whitelists) + printf("Mounting tmpfs on /srv directory\n"); + if (mount("tmpfs", "/srv", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting tmpfs on /srv"); + fs_logger("tmpfs /srv"); + } + else + srv_dir = 0; + } + + + // go through profile rules again, and interpret whitelist commands entry = cfg.profile; while (entry) { @@ -789,6 +813,13 @@ void fs_whitelist(void) { fs_logger2("tmpfs", RUN_WHITELIST_MNT_DIR); } + // mask the real /srv directory, currently mounted on RUN_WHITELIST_SRV_DIR + if (srv_dir) { + if (mount("tmpfs", RUN_WHITELIST_SRV_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mount tmpfs"); + fs_logger2("tmpfs", RUN_WHITELIST_SRV_DIR); + } + if (new_name) free(new_name); diff --git a/src/firejail/join.c b/src/firejail/join.c index ea44019ca..6f1e9455c 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c @@ -292,16 +292,16 @@ void join(pid_t pid, int argc, char **argv, int index) { if (apply_caps == 1) // not available for uid 0 caps_set(caps); #ifdef HAVE_SECCOMP - // set protocol filter + // read cfg.protocol from file if (getuid() != 0) protocol_filter_load(RUN_PROTOCOL_CFG); if (cfg.protocol) { // not available for uid 0 - protocol_filter(); + seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter } // set seccomp filter if (apply_seccomp == 1) // not available for uid 0 - seccomp_set(); + seccomp_load(RUN_SECCOMP_CFG); #endif // fix qt 4.8 diff --git a/src/firejail/list.c b/src/firejail/list.c deleted file mode 100644 index d093a1f85..000000000 --- a/src/firejail/list.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2014-2016 Firejail Authors - * - * This file is part of firejail project - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ -#include "firejail.h" -#include -#include - -static void set_privileges(void) { - struct stat s; - if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { - EUID_ROOT(); - - // elevate privileges - if (setreuid(0, 0)) - errExit("setreuid"); - if (setregid(0, 0)) - errExit("setregid"); - } - else - drop_privs(1); -} - -static char *get_firemon_path(const char *cmd) { - assert(cmd); - - // start the argv[0] program in a new sandbox - char *firemon; - if (asprintf(&firemon, "%s/bin/firemon %s", PREFIX, cmd) == -1) - errExit("asprintf"); - - return firemon; -} - -void top(void) { - EUID_ASSERT(); - drop_privs(1); - char *cmd = get_firemon_path("--top"); - - char *arg[4]; - arg[0] = "bash"; - arg[1] = "-c"; - arg[2] = cmd; - arg[3] = NULL; - execvp("/bin/bash", arg); -} - -void netstats(void) { - EUID_ASSERT(); - set_privileges(); - char *cmd = get_firemon_path("--netstats"); - - char *arg[4]; - arg[0] = "bash"; - arg[1] = "-c"; - arg[2] = cmd; - arg[3] = NULL; - execvp("/bin/bash", arg); -} - -void list(void) { - EUID_ASSERT(); - drop_privs(1); - char *cmd = get_firemon_path("--list"); - - char *arg[4]; - arg[0] = "bash"; - arg[1] = "-c"; - arg[2] = cmd; - arg[3] = NULL; - execvp("/bin/bash", arg); -} - -void tree(void) { - EUID_ASSERT(); - drop_privs(1); - char *cmd = get_firemon_path("--tree"); - - char *arg[4]; - arg[0] = "bash"; - arg[1] = "-c"; - arg[2] = cmd; - arg[3] = NULL; - execvp("/bin/bash", arg); -} - diff --git a/src/firejail/ls.c b/src/firejail/ls.c index 39efaa0a6..dba82be0b 100644 --- a/src/firejail/ls.c +++ b/src/firejail/ls.c @@ -358,7 +358,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { fprintf(stderr, "Error: Cannot read %s\n", fname1); exit(1); } - exit(0); + _exit(0); } // wait for the child to finish @@ -391,7 +391,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { exit(1); } fclose(fp); - exit(0); + _exit(0); } // wait for the child to finish @@ -445,7 +445,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { fprintf(stderr, "Error: Cannot read %s\n", src_fname); exit(1); } - exit(0); + _exit(0); } // wait for the child to finish @@ -494,7 +494,7 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { } } - exit(0); + _exit(0); } // wait for the child to finish diff --git a/src/firejail/main.c b/src/firejail/main.c index 6d4eb21df..fc86f9651 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c @@ -54,9 +54,9 @@ Config cfg; // configuration int arg_private = 0; // mount private /home and /tmp directoryu int arg_private_template = 0; // mount private /home using a template int arg_debug = 0; // print debug messages -int arg_debug_check_filename; // print debug messages for filename checking -int arg_debug_blacklists; // print debug messages for blacklists -int arg_debug_whitelists; // print debug messages for whitelists +int arg_debug_check_filename = 0; // print debug messages for filename checking +int arg_debug_blacklists = 0; // print debug messages for blacklists +int arg_debug_whitelists = 0; // print debug messages for whitelists int arg_nonetwork = 0; // --net=none int arg_command = 0; // -c int arg_overlay = 0; // overlay option @@ -404,8 +404,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { #ifdef HAVE_SECCOMP else if (strcmp(argv[i], "--debug-syscalls") == 0) { if (checkcfg(CFG_SECCOMP)) { - syscall_print(); - exit(0); + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-syscalls"); + exit(rv); } else { fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); @@ -414,7 +414,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { } else if (strcmp(argv[i], "--debug-errnos") == 0) { if (checkcfg(CFG_SECCOMP)) { - errno_print(); + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-errnos"); + exit(rv); } else { fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); @@ -438,8 +439,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { exit(0); } else if (strcmp(argv[i], "--debug-protocols") == 0) { - protocol_list(); - exit(0); + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP, "debug-protocols"); + exit(rv); } else if (strncmp(argv[i], "--protocol.print=", 17) == 0) { if (checkcfg(CFG_SECCOMP)) { @@ -498,27 +499,32 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { exit(0); } else if (strcmp(argv[i], "--list") == 0) { - list(); - exit(0); + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--list"); + exit(rv); } else if (strcmp(argv[i], "--tree") == 0) { - tree(); - exit(0); + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree"); + exit(rv); } else if (strcmp(argv[i], "--top") == 0) { - top(); - exit(0); + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--top"); + exit(rv); } #ifdef HAVE_NETWORK else if (strcmp(argv[i], "--netstats") == 0) { if (checkcfg(CFG_NETWORK)) { - netstats(); + struct stat s; + int rv; + if (stat("/proc/sys/kernel/grsecurity", &s) == 0) + rv = sbox_run(SBOX_ROOT | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats"); + else + rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--netstats"); + exit(rv); } else { fprintf(stderr, "Error: networking features are disabled in Firejail configuration file\n"); exit(1); } - exit(0); } #endif #ifdef HAVE_FILE_TRANSFER @@ -849,6 +855,9 @@ int main(int argc, char **argv) { int highest_errno = errno_highest_nr(); #endif + // build /run/firejail directory structure + preproc_build_firejail_dir(); + detect_quiet(argc, argv); detect_allow_debuggers(argc, argv); @@ -951,10 +960,8 @@ int main(int argc, char **argv) { // initialize globals init_cfg(argc, argv); - // check firejail directories EUID_ROOT(); - fs_build_firejail_dir(); bandwidth_del_run_file(sandbox_pid); network_del_run_file(sandbox_pid); delete_name_file(sandbox_pid); @@ -1112,7 +1119,16 @@ int main(int argc, char **argv) { #ifdef HAVE_SECCOMP else if (strncmp(argv[i], "--protocol=", 11) == 0) { if (checkcfg(CFG_SECCOMP)) { - protocol_store(argv[i] + 11); + if (cfg.protocol) { + if (!arg_quiet) + fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", argv[i] + 11); + } + else { + // store list + cfg.protocol = strdup(argv[i] + 11); + if (!cfg.protocol) + errExit("strdup"); + } } else { fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); @@ -1447,35 +1463,6 @@ int main(int argc, char **argv) { } } -#if 0 // disabled for now, it could be used to overwrite system directories - else if (strncmp(argv[i], "--overlay-path=", 15) == 0) { - if (checkcfg(CFG_OVERLAYFS)) { - if (cfg.chrootdir) { - fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); - exit(1); - } - struct stat s; - if (stat("/proc/sys/kernel/grsecurity", &s) == 0) { - fprintf(stderr, "Error: --overlay option is not available on Grsecurity systems\n"); - exit(1); - } - arg_overlay = 1; - arg_overlay_keep = 1; - arg_overlay_reuse = 1; - - char *dirname = argv[i] + 15; - if (dirname == '\0') { - fprintf(stderr, "Error: invalid overlay option\n"); - exit(1); - } - cfg.overlay_dir = expand_home(dirname, cfg.homedir); - } - else { - fprintf(stderr, "Error: overlayfs feature is disabled in Firejail configuration file\n"); - exit(1); - } - } -#endif else if (strcmp(argv[i], "--overlay-tmpfs") == 0) { if (checkcfg(CFG_OVERLAYFS)) { if (cfg.chrootdir) { @@ -1605,6 +1592,14 @@ int main(int argc, char **argv) { return 1; } + // don't allow "--chroot=/" + char *rpath = realpath(cfg.chrootdir, NULL); + if (rpath == NULL || strcmp(rpath, "/") == 0) { + fprintf(stderr, "Error: invalid chroot directory\n"); + exit(1); + } + free(rpath); + // check chroot directory structure if (fs_check_chroot_dir(cfg.chrootdir)) { fprintf(stderr, "Error: invalid chroot\n"); @@ -2506,7 +2501,7 @@ int main(int argc, char **argv) { network_main(child); if (arg_debug) printf("Host network configured\n"); - exit(0); + _exit(0); } // wait for the child to finish @@ -2555,16 +2550,30 @@ int main(int argc, char **argv) { ptr += strlen(ptr); // add tty group - gid_t ttygid = get_tty_gid(); - if (ttygid) { - sprintf(ptr, "%d %d 1\n", ttygid, ttygid); + gid_t g = get_group_id("tty"); + if (g) { + sprintf(ptr, "%d %d 1\n", g, g); ptr += strlen(ptr); } // add audio group - gid_t audiogid = get_audio_gid(); - if (ttygid) { - sprintf(ptr, "%d %d 1\n", audiogid, audiogid); + g = get_group_id("audio"); + if (g) { + sprintf(ptr, "%d %d 1\n", g, g); + ptr += strlen(ptr); + } + + // add video group + g = get_group_id("video"); + if (g) { + sprintf(ptr, "%d %d 1\n", g, g); + ptr += strlen(ptr); + } + + // add games group + g = get_group_id("games"); + if (g) { + sprintf(ptr, "%d %d 1\n", g, g); } EUID_ROOT(); diff --git a/src/firejail/netfilter.c b/src/firejail/netfilter.c index b50d61039..c1f9a2c37 100644 --- a/src/firejail/netfilter.c +++ b/src/firejail/netfilter.c @@ -145,7 +145,8 @@ void netfilter(const char *fname) { // wipe out environment variables environ = NULL; execl(iptables_restore, iptables_restore, NULL); - // it will never get here!!! + perror("execl"); + _exit(1); } // wait for the child to finish waitpid(child, NULL, 0); @@ -163,7 +164,8 @@ void netfilter(const char *fname) { errExit("setregid"); environ = NULL; execl(iptables, iptables, "-vL", NULL); - // it will never get here!!! + perror("execl"); + _exit(1); } // wait for the child to finish waitpid(child, NULL, 0); @@ -256,7 +258,8 @@ void netfilter6(const char *fname) { // wipe out environment variables environ = NULL; execl(ip6tables_restore, ip6tables_restore, NULL); - // it will never get here!!! + perror("execl"); + _exit(1); } // wait for the child to finish waitpid(child, NULL, 0); @@ -269,7 +272,8 @@ void netfilter6(const char *fname) { if (child == 0) { environ = NULL; execl(ip6tables, ip6tables, "-vL", NULL); - // it will never get here!!! + perror("execl"); + _exit(1); } // wait for the child to finish waitpid(child, NULL, 0); diff --git a/src/firejail/network.c b/src/firejail/network.c index 4473ef099..6d09d770f 100644 --- a/src/firejail/network.c +++ b/src/firejail/network.c @@ -28,70 +28,6 @@ #include #include -// scan interfaces in current namespace and print IP address/mask for each interface -void net_ifprint(void) { - uint32_t ip; - uint32_t mask; - struct ifaddrs *ifaddr, *ifa; - - if (getifaddrs(&ifaddr) == -1) - errExit("getifaddrs"); - - printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n", - "Interface", "MAC", "IP", "Mask", "Status"); - // walk through the linked list - for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - if (ifa->ifa_addr == NULL) - continue; - - if (ifa->ifa_addr->sa_family == AF_INET) { - struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask; - mask = ntohl(si->sin_addr.s_addr); - si = (struct sockaddr_in *) ifa->ifa_addr; - ip = ntohl(si->sin_addr.s_addr); - - // interface status - char *status; - if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) - status = "UP"; - else - status = "DOWN"; - - // ip address and mask - char ipstr[30]; - sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip)); - char maskstr[30]; - sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask)); - - // mac address - unsigned char mac[6]; - net_get_mac(ifa->ifa_name, mac); - char macstr[30]; - if (strcmp(ifa->ifa_name, "lo") == 0) - macstr[0] = '\0'; - else - sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac)); - - // print - printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n", - ifa->ifa_name, macstr, ipstr, maskstr, status); - - // network scanning - if (!arg_scan) // scanning disabled - continue; - if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning - continue; - if (mask2bits(mask) < 16) // not scanning large networks - continue; - if (!ip) // if not configured - continue; - // only if the interface is up and running - if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) - arp_scan(ifa->ifa_name, ip, mask); - } - } - freeifaddrs(ifaddr); -} int net_get_mtu(const char *ifname) { int mtu = 0; @@ -190,101 +126,11 @@ void net_if_up(const char *ifname) { fprintf(stderr, "Error: invalid network device name %s\n", ifname); exit(1); } - - int sock = socket(AF_INET,SOCK_DGRAM,0); - if (sock < 0) - errExit("socket"); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, + PATH_FNET, "ifup", ifname); +} - // get the existing interface flags - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_addr.sa_family = AF_INET; - // read the existing flags - if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { - close(sock); - printf("Error: cannot bring up interface %s\n", ifname); - errExit("ioctl"); - } - - ifr.ifr_flags |= IFF_UP; - - // set the new flags - if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) { - close(sock); - printf("Error: cannot bring up interface %s\n", ifname); - errExit("ioctl"); - } - - // checking - // read the existing flags - if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { - close(sock); - printf("Error: cannot bring up interface %s\n", ifname); - errExit("ioctl"); - } - - // wait not more than 500ms for the interface to come up - int cnt = 0; - while (cnt < 50) { - usleep(10000); // sleep 10ms - - // read the existing flags - if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { - close(sock); - printf("Error: cannot bring up interface %s\n", ifname); - errExit("ioctl"); - } - if (ifr.ifr_flags & IFF_RUNNING) - break; - cnt++; - } - - close(sock); -} - -// bring interface up -void net_if_down(const char *ifname) { - if (strlen(ifname) > IFNAMSIZ) { - fprintf(stderr, "Error: invalid network device name %s\n", ifname); - exit(1); - } - - int sock = socket(AF_INET,SOCK_DGRAM,0); - if (sock < 0) - errExit("socket"); - - // get the existing interface flags - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_addr.sa_family = AF_INET; - - // read the existing flags - if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { - close(sock); - printf("Error: cannot shut down interface %s\n", ifname); - errExit("ioctl"); - } - - ifr.ifr_flags &= ~IFF_UP; - - // set the new flags - if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) { - close(sock); - printf("Error: cannot shut down interface %s\n", ifname); - errExit("ioctl"); - } - - close(sock); -} - -struct ifreq6 { - struct in6_addr ifr6_addr; - uint32_t ifr6_prefixlen; - unsigned int ifr6_ifindex; -}; // configure interface ipv6 address // ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64 void net_if_ip6(const char *ifname, const char *addr6) { @@ -293,107 +139,11 @@ void net_if_ip6(const char *ifname, const char *addr6) { exit(1); } - // extract prefix - unsigned long prefix; - char *ptr; - if ((ptr = strchr(addr6, '/'))) { - prefix = atol(ptr + 1); - if (prefix > 128) { - fprintf(stderr, "Error: invalid prefix for IPv6 address %s\n", addr6); - exit(1); - } - *ptr = '\0'; // mark the end of the address - } - else - prefix = 128; + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5, + PATH_FNET, "config", "ipv6", ifname, addr6); - // extract address - struct sockaddr_in6 sin6; - memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr); - if (rv <= 0) { - fprintf(stderr, "Error: invalid IPv6 address %s\n", addr6); - exit(1); - } - - // open socket - int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); - if (sock < 0) { - fprintf(stderr, "Error: IPv6 is not supported on this system\n"); - exit(1); - } - - // find interface index - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_addr.sa_family = AF_INET; - if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) { - perror("ioctl SIOGIFINDEX"); - exit(1); - } - - // configure address - struct ifreq6 ifr6; - memset(&ifr6, 0, sizeof(ifr6)); - ifr6.ifr6_prefixlen = prefix; - ifr6.ifr6_ifindex = ifr.ifr_ifindex; - memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr)); - if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) { - perror("ioctl SIOCSIFADDR"); - exit(1); - } - - close(sock); } -// configure interface ipv4 address -void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) { - if (strlen(ifname) > IFNAMSIZ) { - fprintf(stderr, "Error: invalid network device name %s\n", ifname); - exit(1); - } - if (arg_debug) - printf("configure interface %s\n", ifname); - - int sock = socket(AF_INET,SOCK_DGRAM,0); - if (sock < 0) - errExit("socket"); - - struct ifreq ifr; - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_addr.sa_family = AF_INET; - - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip); - if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) { - close(sock); - errExit("ioctl"); - } - - if (ip != 0) { - ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask); - if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) { - close(sock); - errExit("ioctl"); - } - } - - // configure mtu - if (mtu > 0) { - ifr.ifr_mtu = mtu; - if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) { - close(sock); - errExit("ioctl"); - } - } - - close(sock); - usleep(10000); // sleep 10ms -} - - // add an IP route, return -1 if error, 0 if the route was added int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { int sock; @@ -431,52 +181,6 @@ int net_add_route(uint32_t ip, uint32_t mask, uint32_t gw) { } -// add a veth device to a bridge -void net_bridge_add_interface(const char *bridge, const char *dev) { - if (strlen(bridge) > IFNAMSIZ) { - fprintf(stderr, "Error: invalid network device name %s\n", bridge); - exit(1); - } - - // somehow adding the interface to the bridge resets MTU on bridge device!!! - // workaround: restore MTU on the bridge device - // todo: put a real fix in - int mtu1 = net_get_mtu(bridge); - - struct ifreq ifr; - int err; - int ifindex = if_nametoindex(dev); - - if (ifindex <= 0) - errExit("if_nametoindex"); - - int sock; - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - errExit("socket"); - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, bridge, IFNAMSIZ); -#ifdef SIOCBRADDIF - ifr.ifr_ifindex = ifindex; - err = ioctl(sock, SIOCBRADDIF, &ifr); - if (err < 0) -#endif - { - unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; - - ifr.ifr_data = (char *) args; - err = ioctl(sock, SIOCDEVPRIVATE, &ifr); - } - (void) err; - close(sock); - - int mtu2 = net_get_mtu(bridge); - if (mtu1 != mtu2) { - if (arg_debug) - printf("Restoring MTU for %s\n", bridge); - net_set_mtu(bridge, mtu1); - } -} #define BUFSIZE 1024 uint32_t network_get_defaultgw(void) { @@ -510,20 +214,15 @@ uint32_t network_get_defaultgw(void) { } int net_config_mac(const char *ifname, const unsigned char mac[6]) { - struct ifreq ifr; - int sock; + char *macstr; + if (asprintf(&macstr, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) == -1) + errExit("asprintf"); - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - errExit("socket"); - - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; - memcpy(ifr.ifr_hwaddr.sa_data, mac, 6); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 5, + PATH_FNET, "config", "mac", ifname, macstr); - if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1) - errExit("ioctl"); - close(sock); + free(macstr); return 0; } @@ -546,3 +245,27 @@ int net_get_mac(const char *ifname, unsigned char mac[6]) { close(sock); return 0; } + +void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu) { + assert(dev); + + char *ipstr; + if (asprintf(&ipstr, "%llu", (long long unsigned) ip) == -1) + errExit("asprintf"); + + char *maskstr; + if (asprintf(&maskstr, "%llu", (long long unsigned) mask) == -1) + errExit("asprintf"); + + char *mtustr; + if (asprintf(&mtustr, "%d", mtu) == -1) + errExit("asprintf"); + + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 7, + PATH_FNET, "config", "interface", dev, ipstr, maskstr, mtustr); + + free(ipstr); + free(maskstr); + free(mtustr); +} + diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c index 907b84642..8a9c47f0e 100644 --- a/src/firejail/network_main.c +++ b/src/firejail/network_main.c @@ -23,6 +23,7 @@ #include #include #include +#include // configure bridge structure // - extract ip address and mask from the bridge interface @@ -127,13 +128,11 @@ void net_configure_veth_pair(Bridge *br, const char *ifname, pid_t child) { else dev = br->veth_name; - net_create_veth(dev, ifname, child); - - // add interface to the bridge - net_bridge_add_interface(br->dev, dev); - - // bring up the interface - net_if_up(dev); + char *cstr; + if (asprintf(&cstr, "%d", child) == -1) + errExit("asprintf"); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 7, PATH_FNET, "create", "veth", dev, ifname, br->dev, cstr); + free(cstr); char *msg; if (asprintf(&msg, "%d.%d.%d.%d address assigned to sandbox", PRINT_IP(br->ipsandbox)) == -1) @@ -290,47 +289,53 @@ void net_dns_print(pid_t pid) { } void network_main(pid_t child) { + char *cstr; + if (asprintf(&cstr, "%d", child) == -1) + errExit("asprintf"); + // create veth pair or macvlan device if (cfg.bridge0.configured) { if (cfg.bridge0.macvlan == 0) { net_configure_veth_pair(&cfg.bridge0, "eth0", child); } else - net_create_macvlan(cfg.bridge0.devsandbox, cfg.bridge0.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge0.devsandbox, cfg.bridge0.dev, cstr); } if (cfg.bridge1.configured) { if (cfg.bridge1.macvlan == 0) net_configure_veth_pair(&cfg.bridge1, "eth1", child); else - net_create_macvlan(cfg.bridge1.devsandbox, cfg.bridge1.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge1.devsandbox, cfg.bridge1.dev, cstr); } if (cfg.bridge2.configured) { if (cfg.bridge2.macvlan == 0) net_configure_veth_pair(&cfg.bridge2, "eth2", child); else - net_create_macvlan(cfg.bridge2.devsandbox, cfg.bridge2.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge2.devsandbox, cfg.bridge2.dev, cstr); } if (cfg.bridge3.configured) { if (cfg.bridge3.macvlan == 0) net_configure_veth_pair(&cfg.bridge3, "eth3", child); else - net_create_macvlan(cfg.bridge3.devsandbox, cfg.bridge3.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 6, PATH_FNET, "create", "macvlan", cfg.bridge3.devsandbox, cfg.bridge3.dev, cstr); } // move interfaces in sandbox if (cfg.interface0.configured) { - net_move_interface(cfg.interface0.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface0.dev, cstr); } if (cfg.interface1.configured) { - net_move_interface(cfg.interface1.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface1.dev, cstr); } if (cfg.interface2.configured) { - net_move_interface(cfg.interface2.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr); } if (cfg.interface3.configured) { - net_move_interface(cfg.interface3.dev, child); + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 4, PATH_FNET, "moveif", cfg.interface3.dev, cstr); } + + free(cstr); } diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c new file mode 100644 index 000000000..2873571a9 --- /dev/null +++ b/src/firejail/preproc.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include + +static int tmpfs_mounted = 0; + +// build /run/firejail directory +void preproc_build_firejail_dir(void) { + struct stat s; + + // CentOS 6 doesn't have /run directory + if (stat(RUN_FIREJAIL_BASEDIR, &s)) { + create_empty_dir_as_root(RUN_FIREJAIL_BASEDIR, 0755); + } + + if (stat(RUN_FIREJAIL_DIR, &s)) { + create_empty_dir_as_root(RUN_FIREJAIL_DIR, 0755); + } + + if (stat(RUN_FIREJAIL_NETWORK_DIR, &s)) { + create_empty_dir_as_root(RUN_FIREJAIL_NETWORK_DIR, 0755); + } + + if (stat(RUN_FIREJAIL_BANDWIDTH_DIR, &s)) { + create_empty_dir_as_root(RUN_FIREJAIL_BANDWIDTH_DIR, 0755); + } + + if (stat(RUN_FIREJAIL_NAME_DIR, &s)) { + create_empty_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755); + } + + if (stat(RUN_FIREJAIL_X11_DIR, &s)) { + create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755); + } + + if (stat(RUN_FIREJAIL_APPIMAGE_DIR, &s)) { + create_empty_dir_as_root(RUN_FIREJAIL_APPIMAGE_DIR, 0755); + } + + if (stat(RUN_MNT_DIR, &s)) { + create_empty_dir_as_root(RUN_MNT_DIR, 0755); + } + + create_empty_file_as_root(RUN_RO_FILE, S_IRUSR); + create_empty_dir_as_root(RUN_RO_DIR, S_IRUSR); +} + +// build /run/firejail/mnt directory +void preproc_mount_mnt_dir(void) { + // mount tmpfs on top of /run/firejail/mnt + if (!tmpfs_mounted) { + if (arg_debug) + printf("Mounting tmpfs on %s directory\n", RUN_MNT_DIR); + if (mount("tmpfs", RUN_MNT_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) + errExit("mounting /run/firejail/mnt"); + tmpfs_mounted = 1; + fs_logger2("tmpfs", RUN_MNT_DIR); + + // create all seccomp files + // as root, create RUN_SECCOMP_I386 file + create_empty_file_as_root(RUN_SECCOMP_I386, 0644); + if (chown(RUN_SECCOMP_I386, getuid(), getgid()) == -1) + errExit("chown"); + if (chmod(RUN_SECCOMP_I386, 0644) == -1) + errExit("chmod"); + + // as root, create RUN_SECCOMP_AMD64 file + create_empty_file_as_root(RUN_SECCOMP_AMD64, 0644); + if (chown(RUN_SECCOMP_AMD64, getuid(), getgid()) == -1) + errExit("chown"); + if (chmod(RUN_SECCOMP_AMD64, 0644) == -1) + errExit("chmod"); + + // as root, create RUN_SECCOMP file + create_empty_file_as_root(RUN_SECCOMP_CFG, 0644); + if (chown(RUN_SECCOMP_CFG, getuid(), getgid()) == -1) + errExit("chown"); + if (chmod(RUN_SECCOMP_CFG, 0644) == -1) + errExit("chmod"); + + // as root, create RUN_SECCOMP_PROTOCOL file + create_empty_file_as_root(RUN_SECCOMP_PROTOCOL, 0644); + if (chown(RUN_SECCOMP_PROTOCOL, getuid(), getgid()) == -1) + errExit("chown"); + if (chmod(RUN_SECCOMP_PROTOCOL, 0644) == -1) + errExit("chmod"); + } +} + +// grab a copy of cp command +void preproc_build_cp_command(void) { + struct stat s; + preproc_mount_mnt_dir(); + if (stat(RUN_CP_COMMAND, &s)) { + char* fname = realpath("/bin/cp", NULL); + if (fname == NULL) { + fprintf(stderr, "Error: /bin/cp not found\n"); + exit(1); + } + if (stat(fname, &s)) { + fprintf(stderr, "Error: /bin/cp not found\n"); + exit(1); + } + if (is_link(fname)) { + fprintf(stderr, "Error: invalid /bin/cp file\n"); + exit(1); + } + int rv = copy_file(fname, RUN_CP_COMMAND, 0, 0, 0755); + if (rv) { + fprintf(stderr, "Error: cannot access /bin/cp\n"); + exit(1); + } + ASSERT_PERMS(RUN_CP_COMMAND, 0, 0, 0755); + + free(fname); + } +} + +// delete the temporary cp command +void preproc_delete_cp_command(void) { + unlink(RUN_CP_COMMAND); +} diff --git a/src/firejail/profile.c b/src/firejail/profile.c index e5c35a89d..f7d5e87e6 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c @@ -497,8 +497,18 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { if (strncmp(ptr, "protocol ", 9) == 0) { #ifdef HAVE_SECCOMP - if (checkcfg(CFG_SECCOMP)) - protocol_store(ptr + 9); + if (checkcfg(CFG_SECCOMP)) { + if (cfg.protocol) { + if (!arg_quiet) + fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", ptr + 9); + return 0; + } + + // store list + cfg.protocol = strdup(ptr + 9); + if (!cfg.protocol) + errExit("strdup"); + } else fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); #endif diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c index 1ef5bf13d..e8e88aee9 100644 --- a/src/firejail/protocol.c +++ b/src/firejail/protocol.c @@ -18,257 +18,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/* - struct sock_filter filter[] = { - VALIDATE_ARCHITECTURE, - EXAMINE_SYSCALL, - ONLY(SYS_socket), - EXAMINE_ARGUMENT(0), // allow only AF_INET and AF_INET6, drop everything else - WHITELIST(AF_INET), - WHITELIST(AF_INET6), - WHITELIST(AF_PACKET), - RETURN_ERRNO(ENOTSUP) - }; - struct sock_fprog prog = { - .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), - .filter = filter, - }; - - - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - perror("prctl(NO_NEW_PRIVS)"); - return 1; - } - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { - perror("prctl"); - return 1; - } -*/ - #ifdef HAVE_SECCOMP #include "firejail.h" -#include "seccomp.h" -#include -#include - -static char *protocol[] = { - "unix", - "inet", - "inet6", - "netlink", - "packet", - NULL -}; - -static struct sock_filter protocol_filter_command[] = { - WHITELIST(AF_UNIX), - WHITELIST(AF_INET), - WHITELIST(AF_INET6), - WHITELIST(AF_NETLINK), - WHITELIST(AF_PACKET) -}; -// Note: protocol[] and protocol_filter_command are synchronized - -// command length -struct sock_filter whitelist[] = { - WHITELIST(AF_UNIX) -}; -unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter); - - - -static int is_protocol(const char *p) { - int i = 0; - while (protocol[i] != NULL) { - if (strcmp(protocol[i], p) == 0) - return 1; - i++; - } - - return 0; -} - -static struct sock_filter *find_protocol_domain(const char *p) { - int i = 0; - while (protocol[i] != NULL) { - if (strcmp(protocol[i], p) == 0) - return &protocol_filter_command[i * whitelist_len]; - i++; - } - - return NULL; -} - -// --debug-protocols -void protocol_list(void) { - EUID_ASSERT(); - -#ifndef SYS_socket - fprintf(stderr, "Warning: --protocol not supported on this platform\n"); - return; -#endif - - int i = 0; - while (protocol[i] != NULL) { - printf("%s, ", protocol[i]); - i++; - } - printf("\n"); -} - - -// check protocol list and store it in cfg structure -void protocol_store(const char *prlist) { - EUID_ASSERT(); - assert(prlist); - - if (cfg.protocol && !arg_quiet) { - fprintf(stderr, "Warning: a protocol list is present, the new list \"%s\" will not be installed\n", prlist); - return; - } - - // temporary list - char *tmplist = strdup(prlist); - if (!tmplist) - errExit("strdup"); - - // check list - char *token = strtok(tmplist, ","); - if (!token) - goto errout; - - while (token) { - if (!is_protocol(token)) - goto errout; - token = strtok(NULL, ","); - } - free(tmplist); - - // store list - cfg.protocol = strdup(prlist); - if (!cfg.protocol) - errExit("strdup"); - return; - -errout: - fprintf(stderr, "Error: invalid protocol list\n"); - exit(1); -} - -// install protocol filter -void protocol_filter(void) { - assert(cfg.protocol); - if (arg_debug) - printf("Set protocol filter: %s\n", cfg.protocol); - -#ifndef SYS_socket - (void) find_protocol_domain; - fprintf(stderr, "Warning: --protocol not supported on this platform\n"); - return; -#else - // build the filter - struct sock_filter filter[32]; // big enough - memset(&filter[0], 0, sizeof(filter)); - uint8_t *ptr = (uint8_t *) &filter[0]; - - // header - struct sock_filter filter_start[] = { - VALIDATE_ARCHITECTURE, - EXAMINE_SYSCALL, - ONLY(SYS_socket), - EXAMINE_ARGUMENT(0) - }; - memcpy(ptr, &filter_start[0], sizeof(filter_start)); - ptr += sizeof(filter_start); - -#if 0 -printf("entries %u\n", (unsigned) (sizeof(filter_start) / sizeof(struct sock_filter))); -{ - unsigned j; - unsigned char *ptr2 = (unsigned char *) &filter[0]; - for (j = 0; j < sizeof(filter); j++, ptr2++) { - if ((j % (sizeof(struct sock_filter))) == 0) - printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter)))); - printf("%02x, ", (*ptr2) & 0xff); - } - printf("\n"); -} -printf("whitelist_len %u, struct sock_filter len %u\n", whitelist_len, (unsigned) sizeof(struct sock_filter)); -#endif - - - // parse list and add commands - char *tmplist = strdup(cfg.protocol); - if (!tmplist) - errExit("strdup"); - char *token = strtok(tmplist, ","); - if (!token) - errExit("strtok"); - - while (token) { - struct sock_filter *domain = find_protocol_domain(token); - assert(domain); - memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter)); - ptr += whitelist_len * sizeof(struct sock_filter); - token = strtok(NULL, ","); - -#if 0 -printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter)); -{ - unsigned j; - unsigned char *ptr2 = (unsigned char *) &filter[0]; - for (j = 0; j < sizeof(filter); j++, ptr2++) { - if ((j % (sizeof(struct sock_filter))) == 0) - printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter)))); - printf("%02x, ", (*ptr2) & 0xff); - } - printf("\n"); -} -#endif - - - } - free(tmplist); - - // add end of filter - struct sock_filter filter_end[] = { - RETURN_ERRNO(ENOTSUP) - }; - memcpy(ptr, &filter_end[0], sizeof(filter_end)); - ptr += sizeof(filter_end); - -#if 0 -printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter)); -{ - unsigned j; - unsigned char *ptr2 = (unsigned char *) &filter[0]; - for (j = 0; j < sizeof(filter); j++, ptr2++) { - if ((j % (sizeof(struct sock_filter))) == 0) - printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter)))); - printf("%02x, ", (*ptr2) & 0xff); - } - printf("\n"); -} -#endif - - // install filter - unsigned short entries = (unsigned short) ((uintptr_t) ptr - (uintptr_t) (filter)) / (unsigned) sizeof(struct sock_filter); - struct sock_fprog prog = { - .len = entries, - .filter = filter, - }; - - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); - return; - } -#endif // SYS_socket -} +#include "../include/seccomp.h" void protocol_filter_save(void) { // save protocol filter configuration in PROTOCOL_CFG - fs_build_mnt_dir(); - FILE *fp = fopen(RUN_PROTOCOL_CFG, "w"); if (!fp) errExit("fopen"); diff --git a/src/firejail/pulseaudio.c b/src/firejail/pulseaudio.c index 90997f934..e1a58c1c8 100644 --- a/src/firejail/pulseaudio.c +++ b/src/firejail/pulseaudio.c @@ -104,7 +104,6 @@ void pulseaudio_init(void) { return; // create the new user pulseaudio directory - fs_build_mnt_dir(); int rv = mkdir(RUN_PULSE_DIR, 0700); (void) rv; // in --chroot mode the directory can already be there if (chown(RUN_PULSE_DIR, getuid(), getgid()) < 0) diff --git a/src/firejail/restrict_users.c b/src/firejail/restrict_users.c index 5ef9524d7..57e84e5cc 100644 --- a/src/firejail/restrict_users.c +++ b/src/firejail/restrict_users.c @@ -73,7 +73,6 @@ static void sanitize_home(void) { return; } - fs_build_mnt_dir(); if (mkdir(RUN_WHITELIST_HOME_DIR, 0755) == -1) errExit("mkdir"); @@ -127,7 +126,6 @@ static void sanitize_passwd(void) { FILE *fpin = NULL; FILE *fpout = NULL; - fs_build_mnt_dir(); // open files /* coverity[toctou] */ @@ -261,7 +259,6 @@ static void sanitize_group(void) { FILE *fpin = NULL; FILE *fpout = NULL; - fs_build_mnt_dir(); // open files /* coverity[toctou] */ diff --git a/src/firejail/restricted_shell.c b/src/firejail/restricted_shell.c index 24ce27c2e..979bb1eed 100644 --- a/src/firejail/restricted_shell.c +++ b/src/firejail/restricted_shell.c @@ -18,6 +18,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "firejail.h" +#include #define MAX_READ 4096 // maximum line length char *restricted_user = NULL; @@ -49,7 +50,11 @@ int restricted_shell(const char *user) { if (*ptr == '\n' || *ptr == '#') continue; - // parse line + // + // parse line + // + + // extract users char *usr = ptr; char *args = strchr(usr, ':'); if (args == NULL) { @@ -63,7 +68,7 @@ int restricted_shell(const char *user) { if (ptr) *ptr = '\0'; - // if nothing follows, continue + // extract firejail command line arguments char *ptr2 = args; int found = 0; while (*ptr2 != '\0') { @@ -73,12 +78,13 @@ int restricted_shell(const char *user) { } ptr2++; } + // if nothing follows, continue if (!found) continue; - // process user - if (strcmp(user, usr) == 0) { - // extract program arguments + // user name globbing + if (fnmatch(usr, user, 0) == 0) { + // process program arguments fullargv[0] = "firejail"; int i; diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 8021ce9a3..3942e4da6 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c @@ -122,7 +122,7 @@ static void sandbox_if_up(Bridge *br) { assert(br); if (!br->configured) return; - + char *dev = br->devsandbox; net_if_up(dev); @@ -137,8 +137,7 @@ static void sandbox_if_up(Bridge *br) { assert(br->ipsandbox); if (arg_debug) printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); - net_if_ip(dev, br->ipsandbox, br->mask, br->mtu); - net_if_up(dev); + net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); } else if (br->arg_ip_none == 0 && br->macvlan == 1) { // reassign the macvlan address @@ -160,8 +159,7 @@ static void sandbox_if_up(Bridge *br) { if (arg_debug) printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(br->ipsandbox), dev); - net_if_ip(dev, br->ipsandbox, br->mask, br->mtu); - net_if_up(dev); + net_config_interface(dev, br->ipsandbox, br->mask, br->mtu); } if (br->ip6sandbox) @@ -256,32 +254,6 @@ static int monitor_application(pid_t app_pid) { // return the latest exit status. return status; - -#if 0 -// todo: find a way to shut down interfaces before closing the namespace -// the problem is we don't have enough privileges to shutdown interfaces in this moment - // shut down bridge/macvlan interfaces - if (any_bridge_configured()) { - - if (cfg.bridge0.configured) { - printf("Shutting down %s\n", cfg.bridge0.devsandbox); - net_if_down( cfg.bridge0.devsandbox); - } - if (cfg.bridge1.configured) { - printf("Shutting down %s\n", cfg.bridge1.devsandbox); - net_if_down( cfg.bridge1.devsandbox); - } - if (cfg.bridge2.configured) { - printf("Shutting down %s\n", cfg.bridge2.devsandbox); - net_if_down( cfg.bridge2.devsandbox); - } - if (cfg.bridge3.configured) { - printf("Shutting down %s\n", cfg.bridge3.devsandbox); - net_if_down( cfg.bridge3.devsandbox); - } - usleep(20000); // 20 ms sleep - } -#endif } void start_audit(void) { @@ -442,7 +414,8 @@ int sandbox(void* sandbox_arg) { if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0) { chk_chroot(); } - + // ... and mount a tmpfs on top of /run/firejail/mnt directory + preproc_mount_mnt_dir(); //**************************** // log sandbox data @@ -459,7 +432,7 @@ int sandbox(void* sandbox_arg) { fs_logger("install mount namespace"); //**************************** - // netfilter etc. + // netfilter //**************************** if (arg_netfilter && any_bridge_configured()) { // assuming by default the client filter netfilter(arg_netfilter_file); @@ -468,6 +441,105 @@ int sandbox(void* sandbox_arg) { netfilter6(arg_netfilter6_file); } + //**************************** + // networking + //**************************** + int gw_cfg_failed = 0; // default gw configuration flag + if (arg_nonetwork) { + net_if_up("lo"); + if (arg_debug) + printf("Network namespace enabled, only loopback interface available\n"); + } + else if (any_bridge_configured() || any_interface_configured()) { + // configure lo and eth0...eth3 + net_if_up("lo"); + + if (mac_not_zero(cfg.bridge0.macsandbox)) + net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox); + sandbox_if_up(&cfg.bridge0); + + if (mac_not_zero(cfg.bridge1.macsandbox)) + net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox); + sandbox_if_up(&cfg.bridge1); + + if (mac_not_zero(cfg.bridge2.macsandbox)) + net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox); + sandbox_if_up(&cfg.bridge2); + + if (mac_not_zero(cfg.bridge3.macsandbox)) + net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox); + sandbox_if_up(&cfg.bridge3); + + +// todo: this code seems to be dead!!! + // enable interfaces + if (cfg.interface0.configured && cfg.interface0.ip) { +assert(0); + if (arg_debug) + printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev); + net_config_interface(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu); + } + if (cfg.interface1.configured && cfg.interface1.ip) { +assert(0); + if (arg_debug) + printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev); + net_config_interface(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu); + } + if (cfg.interface2.configured && cfg.interface2.ip) { +assert(0); + if (arg_debug) + printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev); + net_config_interface(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu); + } + if (cfg.interface3.configured && cfg.interface3.ip) { +assert(0); + if (arg_debug) + printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev); + net_config_interface(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu); + } + + // add a default route + if (cfg.defaultgw) { + // set the default route + if (net_add_route(0, 0, cfg.defaultgw)) { + fprintf(stderr, "Warning: cannot configure default route\n"); + gw_cfg_failed = 1; + } + } + + if (arg_debug) + printf("Network namespace enabled\n"); + } + + + // print network configuration + if (!arg_quiet) { + if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) { + printf("\n"); + if (any_bridge_configured() || any_interface_configured()) { +// net_ifprint(); + if (arg_scan) + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 3, PATH_FNET, "printif", "scan"); + else + sbox_run(SBOX_ROOT | SBOX_CAPS_NETWORK | SBOX_SECCOMP, 2, PATH_FNET, "printif", "scan"); + + } + if (cfg.defaultgw != 0) { + if (gw_cfg_failed) + printf("Default gateway configuration failed\n"); + else + printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw)); + } + if (cfg.dns1 != 0) + printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); + if (cfg.dns2 != 0) + printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); + if (cfg.dns3 != 0) + printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); + printf("\n"); + } + } + // load IBUS env variables if (arg_nonetwork || any_bridge_configured() || any_interface_configured()) { // do nothing - there are problems with ibus version 1.5.11 @@ -475,9 +547,27 @@ int sandbox(void* sandbox_arg) { else env_ibus_load(); - // grab a copy of cp command - fs_build_cp_command(); - + //**************************** + // fs pre-processing: + // - copy some commands under /run + // - build seccomp filters + // - create an empty /etc/ld.so.preload + //**************************** + preproc_build_cp_command(); + +#ifdef HAVE_SECCOMP + if (cfg.protocol) { + if (arg_debug) + printf("Build protocol filter: %s\n", cfg.protocol); + + // build the seccomp filter as a regular user + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, + PATH_FSECCOMP, "protocol", "build", cfg.protocol, RUN_SECCOMP_PROTOCOL); + if (rv) + exit(rv); + } +#endif + // trace pre-install if (arg_trace || arg_tracelog || mask_x11_abstract_socket) fs_trace_preload(); @@ -488,6 +578,13 @@ int sandbox(void* sandbox_arg) { #ifdef HAVE_SECCOMP int enforce_seccomp = 0; #endif + if (arg_appimage) { + enforce_filters(); +#ifdef HAVE_SECCOMP + enforce_seccomp = 1; +#endif + } + #ifdef HAVE_CHROOT if (cfg.chrootdir) { fs_chroot(cfg.chrootdir); @@ -610,7 +707,6 @@ int sandbox(void* sandbox_arg) { EUID_USER(); profile_add("whitelist /tmp/.X11-unix"); EUID_ROOT(); -// fs_private_tmp(); } } @@ -657,102 +753,17 @@ int sandbox(void* sandbox_arg) { fs_dev_disable_3d(); //**************************** - // networking + // set dns //**************************** - int gw_cfg_failed = 0; // default gw configuration flag - if (arg_nonetwork) { - net_if_up("lo"); - if (arg_debug) - printf("Network namespace enabled, only loopback interface available\n"); - } - else if (any_bridge_configured() || any_interface_configured()) { - // configure lo and eth0...eth3 - net_if_up("lo"); - - if (mac_not_zero(cfg.bridge0.macsandbox)) - net_config_mac(cfg.bridge0.devsandbox, cfg.bridge0.macsandbox); - sandbox_if_up(&cfg.bridge0); - - if (mac_not_zero(cfg.bridge1.macsandbox)) - net_config_mac(cfg.bridge1.devsandbox, cfg.bridge1.macsandbox); - sandbox_if_up(&cfg.bridge1); - - if (mac_not_zero(cfg.bridge2.macsandbox)) - net_config_mac(cfg.bridge2.devsandbox, cfg.bridge2.macsandbox); - sandbox_if_up(&cfg.bridge2); - - if (mac_not_zero(cfg.bridge3.macsandbox)) - net_config_mac(cfg.bridge3.devsandbox, cfg.bridge3.macsandbox); - sandbox_if_up(&cfg.bridge3); - - // enable interfaces - if (cfg.interface0.configured && cfg.interface0.ip) { - if (arg_debug) - printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface0.ip), cfg.interface0.dev); - net_if_ip(cfg.interface0.dev, cfg.interface0.ip, cfg.interface0.mask, cfg.interface0.mtu); - net_if_up(cfg.interface0.dev); - } - if (cfg.interface1.configured && cfg.interface1.ip) { - if (arg_debug) - printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface1.ip), cfg.interface1.dev); - net_if_ip(cfg.interface1.dev, cfg.interface1.ip, cfg.interface1.mask, cfg.interface1.mtu); - net_if_up(cfg.interface1.dev); - } - if (cfg.interface2.configured && cfg.interface2.ip) { - if (arg_debug) - printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface2.ip), cfg.interface2.dev); - net_if_ip(cfg.interface2.dev, cfg.interface2.ip, cfg.interface2.mask, cfg.interface2.mtu); - net_if_up(cfg.interface2.dev); - } - if (cfg.interface3.configured && cfg.interface3.ip) { - if (arg_debug) - printf("Configuring %d.%d.%d.%d address on interface %s\n", PRINT_IP(cfg.interface3.ip), cfg.interface3.dev); - net_if_ip(cfg.interface3.dev, cfg.interface3.ip, cfg.interface3.mask, cfg.interface3.mtu); - net_if_up(cfg.interface3.dev); - } - - // add a default route - if (cfg.defaultgw) { - // set the default route - if (net_add_route(0, 0, cfg.defaultgw)) { - fprintf(stderr, "Warning: cannot configure default route\n"); - gw_cfg_failed = 1; - } - } - - if (arg_debug) - printf("Network namespace enabled\n"); - } - - // if any dns server is configured, it is time to set it now fs_resolvconf(); + + //**************************** + // fs post-processing + //**************************** + preproc_delete_cp_command(); fs_logger_print(); fs_logger_change_owner(); - // print network configuration - if (!arg_quiet) { - if (any_bridge_configured() || any_interface_configured() || cfg.defaultgw || cfg.dns1) { - printf("\n"); - if (any_bridge_configured() || any_interface_configured()) - net_ifprint(); - if (cfg.defaultgw != 0) { - if (gw_cfg_failed) - printf("Default gateway configuration failed\n"); - else - printf("Default gateway %d.%d.%d.%d\n", PRINT_IP(cfg.defaultgw)); - } - if (cfg.dns1 != 0) - printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns1)); - if (cfg.dns2 != 0) - printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns2)); - if (cfg.dns3 != 0) - printf("DNS server %d.%d.%d.%d\n", PRINT_IP(cfg.dns3)); - printf("\n"); - } - } - - fs_delete_cp_command(); - //**************************** // set application environment //**************************** @@ -808,12 +819,24 @@ int sandbox(void* sandbox_arg) { // set rlimits set_rlimits(); - // set seccomp + // set cpu affinity + if (cfg.cpus) { + save_cpu(); // save cpu affinity mask to CPU_CFG file + set_cpu_affinity(); + } + + // save cgroup in CGROUP_CFG file + if (cfg.cgroup) + save_cgroup(); + + // set seccomp //todo: push it down after drop_privs and/or configuring noroot #ifdef HAVE_SECCOMP // install protocol filter if (cfg.protocol) { - protocol_filter(); // install filter - protocol_filter_save(); // save filter in PROTOCOL_CFG + if (arg_debug) + printf("Install protocol filter: %s\n", cfg.protocol); + seccomp_load(RUN_SECCOMP_PROTOCOL); // install filter + protocol_filter_save(); // save filter in RUN_PROTOCOL_CFG } // if a keep list is available, disregard the drop list @@ -827,16 +850,6 @@ int sandbox(void* sandbox_arg) { } #endif - // set cpu affinity - if (cfg.cpus) { - save_cpu(); // save cpu affinity mask to CPU_CFG file - set_cpu_affinity(); - } - - // save cgroup in CGROUP_CFG file - if (cfg.cgroup) - save_cgroup(); - //**************************************** // drop privileges or create a new user namespace //**************************************** @@ -909,8 +922,6 @@ int sandbox(void* sandbox_arg) { int status = monitor_application(app_pid); // monitor application flush_stdin(); - - if (WIFEXITED(status)) { // if we had a proper exit, return that exit status return WEXITSTATUS(status); diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c new file mode 100644 index 000000000..6499b7005 --- /dev/null +++ b/src/firejail/sbox.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "firejail.h" +#include +#include +#include +#include +#include + #include +#include "../include/seccomp.h" + +static struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL, + +#if defined(__x86_64__) +#define X32_SYSCALL_BIT 0x40000000 + // handle X32 ABI + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), + RETURN_ERRNO(EPERM), +#endif + + // syscall list +#ifdef SYS_mount + BLACKLIST(SYS_mount), // mount/unmount filesystems +#endif +#ifdef SYS_umount2 + BLACKLIST(SYS_umount2), +#endif +#ifdef SYS_ptrace + BLACKLIST(SYS_ptrace), // trace processes +#endif +#ifdef SYS_kexec_file_load + BLACKLIST(SYS_kexec_file_load), +#endif +#ifdef SYS_kexec_load + BLACKLIST(SYS_kexec_load), // loading a different kernel +#endif +#ifdef SYS_name_to_handle_at + BLACKLIST(SYS_name_to_handle_at), +#endif +#ifdef SYS_open_by_handle_at + BLACKLIST(SYS_open_by_handle_at), // open by handle +#endif +#ifdef SYS_init_module + BLACKLIST(SYS_init_module), // kernel module handling +#endif +#ifdef SYS_finit_module // introduced in 2013 + BLACKLIST(SYS_finit_module), +#endif +#ifdef SYS_create_module + BLACKLIST(SYS_create_module), +#endif +#ifdef SYS_delete_module + BLACKLIST(SYS_delete_module), +#endif +#ifdef SYS_iopl + BLACKLIST(SYS_iopl), // io permissions +#endif +#ifdef SYS_ioperm + BLACKLIST(SYS_ioperm), +#endif +#ifdef SYS_iopl + BLACKLIST(SYS_iopl), // io permissions +#endif +#ifdef SYS_ioprio_set + BLACKLIST(SYS_ioprio_set), +#endif +#ifdef SYS_ni_syscall // new io permissions call on arm devices + BLACKLIST(SYS_ni_syscall), +#endif +#ifdef SYS_swapon + BLACKLIST(SYS_swapon), // swap on/off +#endif +#ifdef SYS_swapoff + BLACKLIST(SYS_swapoff), +#endif +#ifdef SYS_syslog + BLACKLIST(SYS_syslog), // kernel printk control +#endif + RETURN_ALLOW +}; + +static struct sock_fprog prog = { + .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), + .filter = filter, +}; + +typedef struct sbox_config { + char *name; + char *path; + unsigned filters; +} SboxConfig; + + +int sbox_run(unsigned filter, int num, ...) { + EUID_ROOT(); + + int i; + va_list valist; + va_start(valist, num); + + // build argument list + char *arg[num + 1]; + for (i = 0; i < num; i++) + arg[i] = va_arg(valist, char*); + arg[i] = NULL; + va_end(valist); + + if (arg_debug) { + printf("sbox run: "); + for (i = 0; i <= num; i++) + printf("%s ", arg[i]); + printf("\n"); + } + + pid_t child = fork(); + if (child < 0) + errExit("fork"); + if (child == 0) { + // apply filters + if (filter & SBOX_CAPS_NONE) { + caps_drop_all(); + } + else if (filter & SBOX_CAPS_NETWORK) { + uint64_t set = ((uint64_t) 1) << CAP_NET_ADMIN; + set |= ((uint64_t) 1) << CAP_NET_RAW; + caps_set(set); + } + + if (filter & SBOX_SECCOMP) { + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + perror("prctl(NO_NEW_PRIVS)"); + } + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { + perror("prctl(PR_SET_SECCOMP)"); + } + } + + if (filter & SBOX_ROOT) { + // elevate privileges in order to get grsecurity working + if (setreuid(0, 0)) + errExit("setreuid"); + if (setregid(0, 0)) + errExit("setregid"); + } + else if (filter & SBOX_USER) + drop_privs(1); + + if (arg[0]) // get rid of scan-build warning + execvp(arg[0], arg); + else + assert(0); + perror("execl"); + _exit(1); + } + + int status; + if (waitpid(child, &status, 0) == -1 ) { + errExit("waitpid"); + } + if (WIFEXITED(status) && status != 0) { + fprintf(stderr, "Error: failed to run %s\n", arg[0]); + exit(1); + } + + return status; +} diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c index c2da1168a..74d29fc9d 100644 --- a/src/firejail/seccomp.c +++ b/src/firejail/seccomp.c @@ -20,763 +20,205 @@ #ifdef HAVE_SECCOMP #include "firejail.h" -#include "seccomp.h" +#include "../include/seccomp.h" -#define SECSIZE 128 // initial filter size -static struct sock_filter *sfilter = NULL; -static int sfilter_alloc_size = 0; -static int sfilter_index = 0; - -// debug filter -void filter_debug(void) { - // start filter - struct sock_filter filter[] = { - VALIDATE_ARCHITECTURE, - EXAMINE_SYSCALL - }; - - // print sizes - printf("SECCOMP Filter:\n"); - if (sfilter == NULL) { - printf("SECCOMP filter not allocated\n"); - return; - } - if (sfilter_index < 4) - return; - - // test the start of the filter - if (memcmp(sfilter, filter, sizeof(filter)) == 0) { - printf(" VALIDATE_ARCHITECTURE\n"); - printf(" EXAMINE_SYSCAL\n"); - } - - // loop trough blacklists - int i = 4; - while (i < sfilter_index) { - // minimal parsing! - unsigned char *ptr = (unsigned char *) &sfilter[i]; - int *nr = (int *) (ptr + 4); - if (*ptr == 0x15 && *(ptr +14) == 0xff && *(ptr + 15) == 0x7f ) { - printf(" WHITELIST %d %s\n", *nr, syscall_find_nr(*nr)); - i += 2; - } - else if (*ptr == 0x15 && *(ptr +14) == 0 && *(ptr + 15) == 0) { - printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); - i += 2; - } - else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) { - int err = *(ptr + 13) << 8 | *(ptr + 12); - printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err)); - i += 2; - } - else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { - printf(" KILL_PROCESS\n"); - i++; - } - else if (*ptr == 0x06 && *(ptr +6) == 0xff && *(ptr + 7) == 0x7f ) { - printf(" RETURN_ALLOW\n"); - i++; - } - else { - printf(" UNKNOWN ENTRY!!!\n"); - i++; - } - } -} - -// initialize filter -static void filter_init(void) { - if (sfilter) { - assert(0); - return; - } - -// if (arg_debug) -// printf("Initialize seccomp filter\n"); - // allocate a filter of SECSIZE - sfilter = malloc(sizeof(struct sock_filter) * SECSIZE); - if (!sfilter) - errExit("malloc"); - memset(sfilter, 0, sizeof(struct sock_filter) * SECSIZE); - sfilter_alloc_size = SECSIZE; - - // copy the start entries -#if defined(__x86_64__) -#define X32_SYSCALL_BIT 0x40000000 - struct sock_filter filter[] = { - VALIDATE_ARCHITECTURE, - EXAMINE_SYSCALL, - // handle X32 ABI - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), - BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), - RETURN_ERRNO(EPERM) - }; -#else - struct sock_filter filter[] = { - VALIDATE_ARCHITECTURE, - EXAMINE_SYSCALL - }; -#endif - sfilter_index = sizeof(filter) / sizeof(struct sock_filter); - memcpy(sfilter, filter, sizeof(filter)); -} - -static void filter_realloc(void) { - assert(sfilter); - assert(sfilter_alloc_size); - assert(sfilter_index); - if (arg_debug) - printf("Allocating more seccomp filter entries\n"); - - // allocate the new memory - struct sock_filter *old = sfilter; - sfilter = malloc(sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); - if (!sfilter) - errExit("malloc"); - memset(sfilter, 0, sizeof(struct sock_filter) * (sfilter_alloc_size + SECSIZE)); - - // copy old filter - memcpy(sfilter, old, sizeof(struct sock_filter) * sfilter_alloc_size); - sfilter_alloc_size += SECSIZE; -} - -static void filter_add_whitelist(int syscall, int arg) { - (void) arg; - assert(sfilter); - assert(sfilter_alloc_size); - assert(sfilter_index); -// if (arg_debug) -// printf("Whitelisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); - - if ((sfilter_index + 2) > sfilter_alloc_size) - filter_realloc(); - - struct sock_filter filter[] = { - WHITELIST(syscall) - }; -#if 0 -{ - int i; - unsigned char *ptr = (unsigned char *) &filter[0]; - for (i = 0; i < sizeof(filter); i++, ptr++) - printf("%x, ", (*ptr) & 0xff); - printf("\n"); -} -#endif - memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); - sfilter_index += sizeof(filter) / sizeof(struct sock_filter); -} - -static void filter_add_blacklist(int syscall, int arg) { - (void) arg; - assert(sfilter); - assert(sfilter_alloc_size); - assert(sfilter_index); -// if (arg_debug) -// printf("Blacklisting syscall %d %s\n", syscall, syscall_find_nr(syscall)); - - if ((sfilter_index + 2) > sfilter_alloc_size) - filter_realloc(); - - struct sock_filter filter[] = { - BLACKLIST(syscall) - }; -#if 0 -{ - int i; - unsigned char *ptr = (unsigned char *) &filter[0]; - for (i = 0; i < sizeof(filter); i++, ptr++) - printf("%x, ", (*ptr) & 0xff); - printf("\n"); -} -#endif - memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); - sfilter_index += sizeof(filter) / sizeof(struct sock_filter); -} - -static void filter_add_errno(int syscall, int arg) { - assert(sfilter); - assert(sfilter_alloc_size); - assert(sfilter_index); -// if (arg_debug) -// printf("Errno syscall %d %d %s\n", syscall, arg, syscall_find_nr(syscall)); - - if ((sfilter_index + 2) > sfilter_alloc_size) - filter_realloc(); - - struct sock_filter filter[] = { - BLACKLIST_ERRNO(syscall, arg) - }; -#if 0 -{ - int i; - unsigned char *ptr = (unsigned char *) &filter[0]; - for (i = 0; i < sizeof(filter); i++, ptr++) - printf("%x, ", (*ptr) & 0xff); - printf("\n"); -} -#endif - memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); - sfilter_index += sizeof(filter) / sizeof(struct sock_filter); -} - -static void filter_end_blacklist(void) { - assert(sfilter); - assert(sfilter_alloc_size); - assert(sfilter_index); -// if (arg_debug) -// printf("Ending syscall filter\n"); - - if ((sfilter_index + 2) > sfilter_alloc_size) - filter_realloc(); - - struct sock_filter filter[] = { - RETURN_ALLOW - }; -#if 0 -{ - int i; - unsigned char *ptr = (unsigned char *) &filter[0]; - for (i = 0; i < sizeof(filter); i++, ptr++) - printf("%x, ", (*ptr) & 0xff); - printf("\n"); -} -#endif - memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); - sfilter_index += sizeof(filter) / sizeof(struct sock_filter); -} - -static void filter_end_whitelist(void) { - assert(sfilter); - assert(sfilter_alloc_size); - assert(sfilter_index); - if (arg_debug) - printf("Ending syscall filter\n"); - - if ((sfilter_index + 2) > sfilter_alloc_size) - filter_realloc(); - - struct sock_filter filter[] = { - KILL_PROCESS - }; -#if 0 -{ - int i; - unsigned char *ptr = (unsigned char *) &filter[0]; - for (i = 0; i < sizeof(filter); i++, ptr++) - printf("%x, ", (*ptr) & 0xff); - printf("\n"); -} -#endif - memcpy(&sfilter[sfilter_index], filter, sizeof(filter)); - sfilter_index += sizeof(filter) / sizeof(struct sock_filter); -} - - -// save seccomp filter in /run/firejail/mnt/seccomp -static void write_seccomp_file(void) { - fs_build_mnt_dir(); - assert(sfilter); - - int fd = open(RUN_SECCOMP_CFG, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); - if (fd == -1) - errExit("open"); - - if (arg_debug) - printf("Save seccomp filter, size %u bytes\n", (unsigned) (sfilter_index * sizeof(struct sock_filter))); - errno = 0; - ssize_t sz = write(fd, sfilter, sfilter_index * sizeof(struct sock_filter)); - if (sz != (ssize_t)(sfilter_index * sizeof(struct sock_filter))) { - fprintf(stderr, "Error: cannot save seccomp filter\n"); - exit(1); - } - SET_PERMS_FD(fd, 0, 0, S_IRUSR | S_IWUSR); - close(fd); -} - -// read seccomp filter from /run/firejail/mnt/seccomp -static void read_seccomp_file(const char *fname) { - assert(sfilter == NULL && sfilter_index == 0); +int seccomp_load(const char *fname) { + assert(fname); // check file struct stat s; if (stat(fname, &s) == -1) { - fprintf(stderr, "Warning: seccomp file not found\n"); - return; - } - ssize_t sz = s.st_size; - if (sz == 0 || (sz % sizeof(struct sock_filter)) != 0) { - fprintf(stderr, "Error: invalid seccomp file\n"); + fprintf(stderr, "Error: cannot read protocol filter file\n"); exit(1); } - sfilter = malloc(sz); - if (!sfilter) - errExit("malloc"); - - // read file - /* coverity[toctou] */ - int fd = open(fname,O_RDONLY); - if (fd == -1) - errExit("open"); - errno = 0; - ssize_t size = read(fd, sfilter, sz); - if (size != sz) { - fprintf(stderr, "Error: invalid seccomp file\n"); - exit(1); + int size = s.st_size; + unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); +//printf("size %d, entries %d\n", s.st_size, entries); + + // read filter + struct sock_filter filter[entries]; + memset(&filter[0], 0, sizeof(filter)); + int src = open(fname, O_RDONLY); + int rd = 0; + while (rd < size) { + int rv = read(src, (unsigned char *) filter + rd, size - rd); + if (rv == -1) { + fprintf(stderr, "Error: cannot read %s file\n", fname); + exit(1); + } + rd += rv; } - sfilter_index = sz / sizeof(struct sock_filter); - - if (arg_debug) - printf("Read seccomp filter, size %u bytes\n", (unsigned) (sfilter_index * sizeof(struct sock_filter))); - - close(fd); - - if (arg_debug) - filter_debug(); -} - -// i386 filter installed on amd64 architectures -void seccomp_filter_32(void) { - // hardcoded syscall values - struct sock_filter filter[] = { - VALIDATE_ARCHITECTURE_32, - EXAMINE_SYSCALL, - BLACKLIST(21), // mount - BLACKLIST(52), // umount2 -// todo: implement --allow-debuggers - BLACKLIST(26), // ptrace - BLACKLIST(283), // kexec_load - BLACKLIST(341), // name_to_handle_at - BLACKLIST(342), // open_by_handle_at - BLACKLIST(127), // create_module - BLACKLIST(128), // init_module - BLACKLIST(350), // finit_module - BLACKLIST(129), // delete_module - BLACKLIST(110), // iopl - BLACKLIST(101), // ioperm - BLACKLIST(289), // ioprio_set - BLACKLIST(87), // swapon - BLACKLIST(115), // swapoff - BLACKLIST(103), // syslog - BLACKLIST(347), // process_vm_readv - BLACKLIST(348), // process_vm_writev - BLACKLIST(135), // sysfs - BLACKLIST(149), // _sysctl - BLACKLIST(124), // adjtimex - BLACKLIST(343), // clock_adjtime - BLACKLIST(253), // lookup_dcookie - BLACKLIST(336), // perf_event_open - BLACKLIST(338), // fanotify_init - BLACKLIST(349), // kcmp - BLACKLIST(286), // add_key - BLACKLIST(287), // request_key - BLACKLIST(288), // keyctl - BLACKLIST(86), // uselib - BLACKLIST(51), // acct - BLACKLIST(123), // modify_ldt - BLACKLIST(217), // pivot_root - BLACKLIST(245), // io_setup - BLACKLIST(246), // io_destroy - BLACKLIST(247), // io_getevents - BLACKLIST(248), // io_submit - BLACKLIST(249), // io_cancel - BLACKLIST(257), // remap_file_pages - BLACKLIST(274), // mbind - BLACKLIST(275), // get_mempolicy - BLACKLIST(276), // set_mempolicy - BLACKLIST(294), // migrate_pages - BLACKLIST(317), // move_pages - BLACKLIST(316), // vmsplice - BLACKLIST(61), // chroot - BLACKLIST(88), // reboot - BLACKLIST(169), // nfsservctl - BLACKLIST(130), // get_kernel_syms - - RETURN_ALLOW - }; + close(src); + // install filter struct sock_fprog prog = { - .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), + .len = entries, .filter = filter, }; - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - ; - } - else if (arg_debug) { - printf("Dual i386/amd64 seccomp filter configured\n"); - } -} - -// amd64 filter installed on i386 architectures -void seccomp_filter_64(void) { - // hardcoded syscall values - struct sock_filter filter[] = { - VALIDATE_ARCHITECTURE_64, - EXAMINE_SYSCALL, - BLACKLIST(165), // mount - BLACKLIST(166), // umount2 -// todo: implement --allow-debuggers - BLACKLIST(101), // ptrace - BLACKLIST(246), // kexec_load - BLACKLIST(304), // open_by_handle_at - BLACKLIST(303), // name_to_handle_at - BLACKLIST(174), // create_module - BLACKLIST(175), // init_module - BLACKLIST(313), // finit_module - BLACKLIST(176), // delete_module - BLACKLIST(172), // iopl - BLACKLIST(173), // ioperm - BLACKLIST(251), // ioprio_set - BLACKLIST(167), // swapon - BLACKLIST(168), // swapoff - BLACKLIST(103), // syslog - BLACKLIST(310), // process_vm_readv - BLACKLIST(311), // process_vm_writev - BLACKLIST(139), // sysfs - BLACKLIST(156), // _sysctl - BLACKLIST(159), // adjtimex - BLACKLIST(305), // clock_adjtime - BLACKLIST(212), // lookup_dcookie - BLACKLIST(298), // perf_event_open - BLACKLIST(300), // fanotify_init - BLACKLIST(312), // kcmp - BLACKLIST(248), // add_key - BLACKLIST(249), // request_key - BLACKLIST(250), // keyctl - BLACKLIST(134), // uselib - BLACKLIST(163), // acct - BLACKLIST(154), // modify_ldt - BLACKLIST(155), // pivot_root - BLACKLIST(206), // io_setup - BLACKLIST(207), // io_destroy - BLACKLIST(208), // io_getevents - BLACKLIST(209), // io_submit - BLACKLIST(210), // io_cancel - BLACKLIST(216), // remap_file_pages - BLACKLIST(237), // mbind - BLACKLIST(239), // get_mempolicy - BLACKLIST(238), // set_mempolicy - BLACKLIST(256), // migrate_pages - BLACKLIST(279), // move_pages - BLACKLIST(278), // vmsplice - BLACKLIST(161), // chroot - BLACKLIST(184), // tuxcall - BLACKLIST(169), // reboot - BLACKLIST(180), // nfsservctl - BLACKLIST(177), // get_kernel_syms - - RETURN_ALLOW - }; - - struct sock_fprog prog = { - .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), - .filter = filter, - }; - - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - ; - } - else if (arg_debug) { - printf("Dual i386/amd64 seccomp filter configured\n"); - } -} - - -// drop filter for seccomp option -int seccomp_filter_drop(int enforce_seccomp) { - filter_init(); - - // default seccomp - if (cfg.seccomp_list_drop == NULL) { -#if defined(__x86_64__) - seccomp_filter_32(); -#endif -#if defined(__i386__) - seccomp_filter_64(); -#endif - -#ifdef SYS_mount - filter_add_blacklist(SYS_mount, 0); -#endif -#ifdef SYS_umount2 - filter_add_blacklist(SYS_umount2, 0); -#endif - - if (!arg_allow_debuggers) { -#ifdef SYS_ptrace - filter_add_blacklist(SYS_ptrace, 0); -#endif - } - -#ifdef SYS_kexec_load - filter_add_blacklist(SYS_kexec_load, 0); -#endif -#ifdef SYS_kexec_file_load - filter_add_blacklist(SYS_kexec_file_load, 0); -#endif -#ifdef SYS_open_by_handle_at - filter_add_blacklist(SYS_open_by_handle_at, 0); -#endif -#ifdef SYS_name_to_handle_at - filter_add_blacklist(SYS_name_to_handle_at, 0); -#endif -#ifdef SYS_init_module - filter_add_blacklist(SYS_init_module, 0); -#endif -#ifdef SYS_finit_module // introduced in 2013 - filter_add_blacklist(SYS_finit_module, 0); -#endif -#ifdef SYS_create_module - filter_add_blacklist(SYS_create_module, 0); -#endif -#ifdef SYS_delete_module - filter_add_blacklist(SYS_delete_module, 0); -#endif -#ifdef SYS_iopl - filter_add_blacklist(SYS_iopl, 0); -#endif -#ifdef SYS_ioperm - filter_add_blacklist(SYS_ioperm, 0); -#endif -#ifdef SYS_ioprio_set - filter_add_blacklist(SYS_ioprio_set, 0); -#endif -#ifdef SYS_ni_syscall // new io permissions call on arm devices - filter_add_blacklist(SYS_ni_syscall, 0); -#endif -#ifdef SYS_swapon - filter_add_blacklist(SYS_swapon, 0); -#endif -#ifdef SYS_swapoff - filter_add_blacklist(SYS_swapoff, 0); -#endif -#ifdef SYS_syslog - filter_add_blacklist(SYS_syslog, 0); -#endif - if (!arg_allow_debuggers) { -#ifdef SYS_process_vm_readv - filter_add_blacklist(SYS_process_vm_readv, 0); -#endif - } - -#ifdef SYS_process_vm_writev - filter_add_blacklist(SYS_process_vm_writev, 0); -#endif - -// mknod removed in 0.9.29 - it brakes Zotero extension -//#ifdef SYS_mknod -// filter_add_blacklist(SYS_mknod, 0); -//#endif - - // new syscalls in 0.9,23 -#ifdef SYS_sysfs - filter_add_blacklist(SYS_sysfs, 0); -#endif -#ifdef SYS__sysctl - filter_add_blacklist(SYS__sysctl, 0); -#endif -#ifdef SYS_adjtimex - filter_add_blacklist(SYS_adjtimex, 0); -#endif -#ifdef SYS_clock_adjtime - filter_add_blacklist(SYS_clock_adjtime, 0); -#endif -#ifdef SYS_lookup_dcookie - filter_add_blacklist(SYS_lookup_dcookie, 0); -#endif -#ifdef SYS_perf_event_open - filter_add_blacklist(SYS_perf_event_open, 0); -#endif -#ifdef SYS_fanotify_init - filter_add_blacklist(SYS_fanotify_init, 0); -#endif -#ifdef SYS_kcmp - filter_add_blacklist(SYS_kcmp, 0); -#endif - -// 0.9.32 -#ifdef SYS_add_key - filter_add_blacklist(SYS_add_key, 0); -#endif -#ifdef SYS_request_key - filter_add_blacklist(SYS_request_key, 0); -#endif -#ifdef SYS_keyctl - filter_add_blacklist(SYS_keyctl, 0); -#endif -#ifdef SYS_uselib - filter_add_blacklist(SYS_uselib, 0); -#endif -#ifdef SYS_acct - filter_add_blacklist(SYS_acct, 0); -#endif -#ifdef SYS_modify_ldt - filter_add_blacklist(SYS_modify_ldt, 0); -#endif - //#ifdef SYS_unshare - // filter_add_blacklist(SYS_unshare, 0); - //#endif -#ifdef SYS_pivot_root - filter_add_blacklist(SYS_pivot_root, 0); -#endif - //#ifdef SYS_quotactl - // filter_add_blacklist(SYS_quotactl, 0); - //#endif -#ifdef SYS_io_setup - filter_add_blacklist(SYS_io_setup, 0); -#endif -#ifdef SYS_io_destroy - filter_add_blacklist(SYS_io_destroy, 0); -#endif -#ifdef SYS_io_getevents - filter_add_blacklist(SYS_io_getevents, 0); -#endif -#ifdef SYS_io_submit - filter_add_blacklist(SYS_io_submit, 0); -#endif -#ifdef SYS_io_cancel - filter_add_blacklist(SYS_io_cancel, 0); -#endif -#ifdef SYS_remap_file_pages - filter_add_blacklist(SYS_remap_file_pages, 0); -#endif -#ifdef SYS_mbind - filter_add_blacklist(SYS_mbind, 0); -#endif -#ifdef SYS_get_mempolicy - filter_add_blacklist(SYS_get_mempolicy, 0); -#endif -#ifdef SYS_set_mempolicy - filter_add_blacklist(SYS_set_mempolicy, 0); -#endif -#ifdef SYS_migrate_pages - filter_add_blacklist(SYS_migrate_pages, 0); -#endif -#ifdef SYS_move_pages - filter_add_blacklist(SYS_move_pages, 0); -#endif -#ifdef SYS_vmsplice - filter_add_blacklist(SYS_vmsplice, 0); -#endif -#ifdef SYS_chroot - filter_add_blacklist(SYS_chroot, 0); -#endif - //#ifdef SYS_set_robust_list - // filter_add_blacklist(SYS_set_robust_list, 0); - //#endif - //#ifdef SYS_get_robust_list - // filter_add_blacklist(SYS_get_robust_list, 0); - //#endif - - // CHECK_SECCOMP(seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(clone), 1, - // SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER))); - -// 0.9.39 -#ifdef SYS_tuxcall - filter_add_blacklist(SYS_tuxcall, 0); -#endif -#ifdef SYS_reboot - filter_add_blacklist(SYS_reboot, 0); -#endif -#ifdef SYS_nfsservctl - filter_add_blacklist(SYS_nfsservctl, 0); -#endif -#ifdef SYS_get_kernel_syms - filter_add_blacklist(SYS_get_kernel_syms, 0); -#endif - - } - - // default seccomp filter with additional drop list - if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) { - if (syscall_check_list(cfg.seccomp_list, filter_add_blacklist, 0)) { - fprintf(stderr, "Error: cannot load seccomp filter\n"); - exit(1); - } - } - // drop list - else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { - if (syscall_check_list(cfg.seccomp_list_drop, filter_add_blacklist, 0)) { - fprintf(stderr, "Error: cannot load seccomp filter\n"); - exit(1); - } - } - - - filter_end_blacklist(); - if (arg_debug) - filter_debug(); - - // save seccomp filter in /tmp/firejail/mnt/seccomp - // in order to use it in --join operations - write_seccomp_file(); - - - struct sock_fprog prog = { - .len = sfilter_index, - .filter = sfilter, - }; - - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - if (enforce_seccomp) { - fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n"); - exit(1); - } - else - fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); - - return 1; - } - - return 0; -} - -// keep filter for seccomp option -int seccomp_filter_keep(void) { - filter_init(); - - // these 4 syscalls are used by firejail after the seccomp filter is initialized - filter_add_whitelist(SYS_setuid, 0); - filter_add_whitelist(SYS_setgid, 0); - filter_add_whitelist(SYS_setgroups, 0); - filter_add_whitelist(SYS_dup, 0); - - // apply keep list - if (cfg.seccomp_list_keep) { - if (syscall_check_list(cfg.seccomp_list_keep, filter_add_whitelist, 0)) { - fprintf(stderr, "Error: cannot load seccomp filter\n"); - exit(1); - } - } - - filter_end_whitelist(); - if (arg_debug) - filter_debug(); - - // save seccomp filter in /tmp/firejail/mnt/seccomp - // in order to use it in --join operations - write_seccomp_file(); - - - struct sock_fprog prog = { - .len = sfilter_index, - .filter = sfilter, - }; - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); return 1; } - else if (arg_debug) { - printf("seccomp enabled\n"); - } return 0; } + + + +// i386 filter installed on amd64 architectures +void seccomp_filter_32(void) { + if (arg_debug) + printf("Build secondary 32-bit filter\n"); + + // build the seccomp filter as a regular user + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, + PATH_FSECCOMP, "secondary", "32", RUN_SECCOMP_I386); + if (rv) + exit(rv); + + if (seccomp_load(RUN_SECCOMP_I386) == 0) { + if (arg_debug) + printf("Dual i386/amd64 seccomp filter configured\n"); + } +} + +// amd64 filter installed on i386 architectures +void seccomp_filter_64(void) { + if (arg_debug) + printf("Build secondary 64-bit filter\n"); + + // build the seccomp filter as a regular user + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, + PATH_FSECCOMP, "secondary", "64", RUN_SECCOMP_AMD64); + if (rv) + exit(rv); + + if (seccomp_load(RUN_SECCOMP_AMD64) == 0) { + if (arg_debug) + printf("Dual i386/amd64 seccomp filter configured\n"); + } +} + + +// drop filter for seccomp option +int seccomp_filter_drop(int enforce_seccomp) { + // default seccomp + if (cfg.seccomp_list_drop == NULL && cfg.seccomp_list == NULL) { +#if defined(__x86_64__) + seccomp_filter_32(); +#endif +#if defined(__i386__) + seccomp_filter_64(); +#endif + if (arg_debug) + printf("Build default seccomp filter\n"); + // build the seccomp filter as a regular user + int rv; + if (arg_allow_debuggers) + rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, + PATH_FSECCOMP, "default", RUN_SECCOMP_CFG, "allow-debuggers"); + else + rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, + PATH_FSECCOMP, "default", RUN_SECCOMP_CFG); + if (rv) + exit(rv); + } + + // default seccomp filter with additional drop list + else if (cfg.seccomp_list && cfg.seccomp_list_drop == NULL) { +#if defined(__x86_64__) + seccomp_filter_32(); +#endif +#if defined(__i386__) + seccomp_filter_64(); +#endif + if (arg_debug) + printf("Build default+drop seccomp filter\n"); + if (strlen(cfg.seccomp_list) == 0) { + fprintf(stderr, "Error: empty syscall lists are not allowed\n"); + exit(1); + } + + // build the seccomp filter as a regular user + int rv; + if (arg_allow_debuggers) + rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 6, + PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list, "allow-debuggers"); + else + rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, + PATH_FSECCOMP, "default", "drop", RUN_SECCOMP_CFG, cfg.seccomp_list); + if (rv) + exit(rv); + } + + // drop list without defaults - secondary filters are not installed + else if (cfg.seccomp_list == NULL && cfg.seccomp_list_drop) { + if (arg_debug) + printf("Build drop seccomp filter\n"); + if (strlen(cfg.seccomp_list_drop) == 0) { + fprintf(stderr, "Error: empty syscall lists are not allowed\n"); + exit(1); + } + + // build the seccomp filter as a regular user + int rv; + if (arg_allow_debuggers) + rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 5, + PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop, "allow-debuggers"); + else + rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, + PATH_FSECCOMP, "drop", RUN_SECCOMP_CFG, cfg.seccomp_list_drop); + + if (rv) + exit(rv); + } + else { + assert(0); + } + + // load the filter + if (seccomp_load(RUN_SECCOMP_CFG) == 0) { + if (arg_debug) + printf("seccomp filter configured\n"); + } + else if (enforce_seccomp) { + fprintf(stderr, "Error: a seccomp-enabled Linux kernel is required, exiting...\n"); + exit(1); + } + + if (arg_debug) + sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 3, + PATH_FSECCOMP, "print", RUN_SECCOMP_CFG); + + return seccomp_load(RUN_SECCOMP_CFG); +} + +// keep filter for seccomp option +int seccomp_filter_keep(void) { + if (arg_debug) + printf("Build drop seccomp filter\n"); + if (strlen(cfg.seccomp_list_keep) == 0) { + fprintf(stderr, "Error: empty syscall lists are not allowed\n"); + exit(1); + } + + // build the seccomp filter as a regular user + int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 4, + PATH_FSECCOMP, "keep", RUN_SECCOMP_CFG, cfg.seccomp_list_keep); + if (rv) + exit(rv); + if (arg_debug) + printf("seccomp filter configured\n"); + + + return seccomp_load(RUN_SECCOMP_CFG); +} + // errno filter for seccomp option int seccomp_filter_errno(void) { +#if 0 //todo: disabled temporarely, bring it back int i; int higest_errno = errno_highest_nr(); filter_init(); @@ -796,45 +238,14 @@ int seccomp_filter_errno(void) { if (arg_debug) filter_debug(); - // save seccomp filter in /tmp/firejail/mnt/seccomp + // save seccomp filter in /run/firejail/mnt/seccomp // in order to use it in --join operations write_seccomp_file(); - - struct sock_fprog prog = { - .len = sfilter_index, - .filter = sfilter, - }; - - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); - return 1; - } - else if (arg_debug) { - printf("seccomp enabled\n"); - } - + return seccomp_load(RUN_SECCOMP_CFG); +#else +printf("*** --seccomp. is temporarily disabled, it will be brought back soon ***\n"); return 0; -} - - - -void seccomp_set(void) { - // read seccomp filter from /tmp/firejail/mnt/seccomp - read_seccomp_file(RUN_SECCOMP_CFG); - - // apply filter - struct sock_fprog prog = { - .len = sfilter_index, - .filter = sfilter, - }; - - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) || prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - fprintf(stderr, "Warning: seccomp disabled, it requires a Linux kernel version 3.5 or newer.\n"); - return; - } - else if (arg_debug) { - printf("seccomp enabled\n"); - } +#endif } void seccomp_print_filter_name(const char *name) { @@ -891,10 +302,11 @@ void seccomp_print_filter(pid_t pid) { exit(1); } - // read and print the filter - read_seccomp_file(fname); - drop_privs(1); - filter_debug(); + // read and print the filter - run this as root, the user doesn't have access + int rv = sbox_run(SBOX_ROOT | SBOX_SECCOMP, 3, + PATH_FSECCOMP, "print", fname); + if (rv) + exit(rv); free(fname); exit(0); diff --git a/src/firejail/util.c b/src/firejail/util.c index 7aa0ae0e8..9752504e5 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c @@ -171,11 +171,17 @@ void logerr(const char *msg) { } -// return -1 if error, 0 if no error +// return -1 if error, 0 if no error; if destname already exists, return error int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, mode_t mode) { assert(srcname); assert(destname); + struct stat s; + if (stat(destname, &s) == 0) { + fprintf(stderr, "Error: file %s already exists\n", destname); + return -1; + } + // open source int src = open(srcname, O_RDONLY); if (src < 0) { @@ -649,25 +655,14 @@ void invalid_filename(const char *fname) { } -uid_t get_tty_gid(void) { +uid_t get_group_id(const char *group) { // find tty group id - gid_t ttygid = 0; - struct group *g = getgrnam("tty"); + gid_t gid = 0; + struct group *g = getgrnam(group); if (g) - ttygid = g->gr_gid; + gid = g->gr_gid; - return ttygid; -} - - -uid_t get_audio_gid(void) { - // find tty group id - gid_t audiogid = 0; - struct group *g = getgrnam("audio"); - if (g) - audiogid = g->gr_gid; - - return audiogid; + return gid; } @@ -701,3 +696,38 @@ void flush_stdin(void) { } } +void create_empty_dir_as_root(const char *dir, mode_t mode) { + assert(dir); + struct stat s; + + if (stat(dir, &s)) { + if (arg_debug) + printf("Creating empty %s directory\n", dir); + if (mkdir(dir, mode) == -1) + errExit("mkdir"); + if (chmod(dir, mode) == -1) + errExit("chmod"); + if (chown(dir, 0, 0) == -1) + errExit("chown"); + ASSERT_PERMS(dir, 0, 0, mode); + } +} + +void create_empty_file_as_root(const char *fname, mode_t mode) { + assert(fname); + struct stat s; + + if (stat(fname, &s)) { + if (arg_debug) + printf("Creating empty %s file\n", fname); + + FILE *fp = fopen(fname, "w"); + if (!fp) + errExit("fopen"); + SET_PERMS_STREAM(fp, 0, 0, S_IRUSR); + fclose(fp); + if (chmod(fname, mode) == -1) + errExit("chmod"); + } +} + diff --git a/src/firejail/x11.c b/src/firejail/x11.c index d40d349e1..c79f1a74e 100644 --- a/src/firejail/x11.c +++ b/src/firejail/x11.c @@ -314,7 +314,7 @@ void x11_start_xephyr(int argc, char **argv) { execvp(server_argv[0], server_argv); perror("execvp"); - exit(1); + _exit(1); } if (arg_debug) @@ -355,7 +355,7 @@ void x11_start_xephyr(int argc, char **argv) { execvp(jail_argv[0], jail_argv); perror("execvp"); - exit(1); + _exit(1); } // cleanup @@ -434,7 +434,7 @@ void x11_start_xpra(int argc, char **argv) { execvp(server_argv[0], server_argv); perror("execvp"); - exit(1); + _exit(1); } // check X11 socket @@ -480,7 +480,7 @@ void x11_start_xpra(int argc, char **argv) { execvp(attach_argv[0], attach_argv); perror("execvp"); - exit(1); + _exit(1); } setenv("DISPLAY", display_str, 1); @@ -536,7 +536,7 @@ void x11_start_xpra(int argc, char **argv) { } execvp(stop_argv[0], stop_argv); perror("execvp"); - exit(1); + _exit(1); } // wait for xpra server to stop, 10 seconds limit @@ -672,7 +672,7 @@ void x11_xorg(void) { execlp("/usr/bin/xauth", "/usr/bin/xauth", "-f", RUN_XAUTHORITY_SEC_FILE, "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL); - exit(0); + _exit(0); } // wait for the child to finish waitpid(child, NULL, 0); diff --git a/src/firemon/interface.c b/src/firemon/interface.c index 5a89e1491..bceed93d3 100644 --- a/src/firemon/interface.c +++ b/src/firemon/interface.c @@ -146,7 +146,7 @@ static void print_sandbox(pid_t pid) { return; net_ifprint(); printf("\n"); - exit(0); + _exit(0); } // wait for the child to finish diff --git a/src/firemon/procevent.c b/src/firemon/procevent.c index 188c10183..78a3a4fb2 100644 --- a/src/firemon/procevent.c +++ b/src/firemon/procevent.c @@ -28,6 +28,8 @@ #include #include #include +#include + #define PIDS_BUFLEN 4096 #define SERVER_PORT 889 // 889-899 is left unassigned by IANA diff --git a/src/fnet/Makefile.in b/src/fnet/Makefile.in new file mode 100644 index 000000000..b515d2333 --- /dev/null +++ b/src/fnet/Makefile.in @@ -0,0 +1,43 @@ +all: fnet + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sysconfdir=@sysconfdir@ + +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ +HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ +HAVE_SECCOMP=@HAVE_SECCOMP@ +HAVE_CHROOT=@HAVE_CHROOT@ +HAVE_BIND=@HAVE_BIND@ +HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ +HAVE_NETWORK=@HAVE_NETWORK@ +HAVE_USERNS=@HAVE_USERNS@ +HAVE_X11=@HAVE_X11@ +HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ +HAVE_WHITELIST=@HAVE_WHITELIST@ +HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ +HAVE_APPARMOR=@HAVE_APPARMOR@ +HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ +HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ +EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ + +H_FILE_LIST = $(sort $(wildcard *.[h])) +C_FILE_LIST = $(sort $(wildcard *.c)) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread + +%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/libnetlink.h + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +fnet: $(OBJS) ../lib/libnetlink.o ../lib/common.o + $(CC) $(LDFLAGS) -o $@ $(OBJS) ../lib/libnetlink.o $(LIBS) $(EXTRA_LDFLAGS) + +clean:; rm -f *.o fnet + +distclean: clean + rm -fr Makefile + diff --git a/src/fnet/arp.c b/src/fnet/arp.c new file mode 100644 index 000000000..96684fdf9 --- /dev/null +++ b/src/fnet/arp.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fnet.h" +#include +#include +#include //TCP/IP Protocol Suite for Linux +#include +#include +#include +#include +#include +#include + +typedef struct arp_hdr_t { + uint16_t htype; + uint16_t ptype; + uint8_t hlen; + uint8_t plen; + uint16_t opcode; + uint8_t sender_mac[6]; + uint8_t sender_ip[4]; + uint8_t target_mac[6]; + uint8_t target_ip[4]; +} ArpHdr; + + +// scan interface (--scan option) +void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask) { + assert(dev); + assert(ifip); + +// printf("Scanning interface %s (%d.%d.%d.%d/%d)\n", +// dev, PRINT_IP(ifip & ifmask), mask2bits(ifmask)); + + if (strlen(dev) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", dev); + exit(1); + } + + // find interface mac address + int sock; + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + errExit("socket"); + struct ifreq ifr; + memset(&ifr, 0, sizeof (ifr)); + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) + errExit("ioctl"); + close(sock); + uint8_t mac[6]; + memcpy (mac, ifr.ifr_hwaddr.sa_data, 6); + + // open layer2 socket + if ((sock = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) + errExit("socket"); + + // try all possible ip addresses in ascending order + uint32_t range = ~ifmask + 1; // the number of potential addresses + // this software is not supported for /31 networks + if (range < 4) { + fprintf(stderr, "Warning: this option is not supported for /31 networks\n"); + close(sock); + return; + } + + uint32_t dest = (ifip & ifmask) + 1; + uint32_t last = dest + range - 1; + uint32_t src = htonl(ifip); + + // wait not more than one second for an answer + int header_printed = 0; + uint32_t last_ip = 0; + struct timeval ts; + ts.tv_sec = 2; // 2 seconds receive timeout + ts.tv_usec = 0; + + while (1) { + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + fd_set wfds; + FD_ZERO(&wfds); + FD_SET(sock, &wfds); + int maxfd = sock; + + uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc + memset(frame, 0, ETH_FRAME_LEN); + + int nready; + if (dest < last) + nready = select(maxfd + 1, &rfds, &wfds, (fd_set *) 0, NULL); + else + nready = select(maxfd + 1, &rfds, (fd_set *) 0, (fd_set *) 0, &ts); + + if (nready < 0) + errExit("select"); + + if (nready == 0) { // timeout + break; + } + + if (FD_ISSET(sock, &wfds) && dest < last) { + // configure layer2 socket address information + struct sockaddr_ll addr; + memset(&addr, 0, sizeof(addr)); + if ((addr.sll_ifindex = if_nametoindex(dev)) == 0) + errExit("if_nametoindex"); + addr.sll_family = AF_PACKET; + memcpy (addr.sll_addr, mac, 6); + addr.sll_halen = htons(6); + + // build the arp packet header + ArpHdr hdr; + memset(&hdr, 0, sizeof(hdr)); + hdr.htype = htons(1); + hdr.ptype = htons(ETH_P_IP); + hdr.hlen = 6; + hdr.plen = 4; + hdr.opcode = htons(1); //ARPOP_REQUEST + memcpy(hdr.sender_mac, mac, 6); + memcpy(hdr.sender_ip, (uint8_t *)&src, 4); + uint32_t dst = htonl(dest); + memcpy(hdr.target_ip, (uint8_t *)&dst, 4); + + // build ethernet frame + uint8_t frame[ETH_FRAME_LEN]; // includes eht header, vlan, and crc + memset(frame, 0, sizeof(frame)); + frame[0] = frame[1] = frame[2] = frame[3] = frame[4] = frame[5] = 0xff; + memcpy(frame + 6, mac, 6); + frame[12] = ETH_P_ARP / 256; + frame[13] = ETH_P_ARP % 256; + memcpy (frame + 14, &hdr, sizeof(hdr)); + + // send packet + int len; + if ((len = sendto (sock, frame, 14 + sizeof(ArpHdr), 0, (struct sockaddr *) &addr, sizeof (addr))) <= 0) + errExit("send"); +//printf("send %d bytes to %d.%d.%d.%d\n", len, PRINT_IP(dest)); + fflush(0); + dest++; + } + + if (FD_ISSET(sock, &rfds)) { + // read the incoming packet + int len = recvfrom(sock, frame, ETH_FRAME_LEN, 0, NULL, NULL); + if (len < 0) { + perror("recvfrom"); + } + + // parse the incoming packet + if ((unsigned int) len < 14 + sizeof(ArpHdr)) + continue; + + // look only at ARP packets + if (frame[12] != (ETH_P_ARP / 256) || frame[13] != (ETH_P_ARP % 256)) + continue; + + ArpHdr hdr; + memcpy(&hdr, frame + 14, sizeof(ArpHdr)); + + if (hdr.opcode == htons(2)) { + // check my mac and my address + if (memcmp(mac, hdr.target_mac, 6) != 0) + continue; + uint32_t ip; + memcpy(&ip, hdr.target_ip, 4); + if (ip != src) + continue; + memcpy(&ip, hdr.sender_ip, 4); + ip = ntohl(ip); + + if (ip == last_ip) // filter duplicates + continue; + last_ip = ip; + + // printing + if (header_printed == 0) { + printf(" Network scan:\n"); + header_printed = 1; + } + printf(" %02x:%02x:%02x:%02x:%02x:%02x\t%d.%d.%d.%d\n", + PRINT_MAC(hdr.sender_mac), PRINT_IP(ip)); + } + } + } + + close(sock); +} + + + diff --git a/src/fnet/fnet.h b/src/fnet/fnet.h new file mode 100644 index 000000000..0c5e5baef --- /dev/null +++ b/src/fnet/fnet.h @@ -0,0 +1,49 @@ + /* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef FNET_H +#define FNET_H + +#include +#include +#include +#include +#include "../include/common.h" + +// veth.c +int net_create_veth(const char *dev, const char *nsdev, unsigned pid); +int net_create_macvlan(const char *dev, const char *parent, unsigned pid); +int net_move_interface(const char *dev, unsigned pid); + +// interface.c +void net_bridge_add_interface(const char *bridge, const char *dev); +void net_if_up(const char *ifname); +int net_get_mtu(const char *ifname); +void net_set_mtu(const char *ifname, int mtu); +void net_ifprint(int scan); +int net_get_mac(const char *ifname, unsigned char mac[6]); +void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu); +int net_if_mac(const char *ifname, const unsigned char mac[6]); +void net_if_ip6(const char *ifname, const char *addr6); + + +// arp.c +void arp_scan(const char *dev, uint32_t ifip, uint32_t ifmask); + +#endif diff --git a/src/fnet/interface.c b/src/fnet/interface.c new file mode 100644 index 000000000..67af062bf --- /dev/null +++ b/src/fnet/interface.c @@ -0,0 +1,395 @@ + /* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "fnet.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// add a veth device to a bridge +void net_bridge_add_interface(const char *bridge, const char *dev) { + if (strlen(bridge) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", bridge); + exit(1); + } + + // somehow adding the interface to the bridge resets MTU on bridge device!!! + // workaround: restore MTU on the bridge device + // todo: put a real fix in + int mtu1 = net_get_mtu(bridge); + + struct ifreq ifr; + int err; + int ifindex = if_nametoindex(dev); + + if (ifindex <= 0) + errExit("if_nametoindex"); + + int sock; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, bridge, IFNAMSIZ); +#ifdef SIOCBRADDIF + ifr.ifr_ifindex = ifindex; + err = ioctl(sock, SIOCBRADDIF, &ifr); + if (err < 0) +#endif + { + unsigned long args[4] = { BRCTL_ADD_IF, ifindex, 0, 0 }; + + ifr.ifr_data = (char *) args; + err = ioctl(sock, SIOCDEVPRIVATE, &ifr); + } + (void) err; + close(sock); + + int mtu2 = net_get_mtu(bridge); + if (mtu1 != mtu2) { + net_set_mtu(bridge, mtu1); + } +} + + +// bring interface up +void net_if_up(const char *ifname) { + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); + exit(1); + } + + int sock = socket(AF_INET,SOCK_DGRAM,0); + if (sock < 0) + errExit("socket"); + + // get the existing interface flags + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + + ifr.ifr_flags |= IFF_UP; + + // set the new flags + if (ioctl( sock, SIOCSIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + + // checking + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + + // wait not more than 500ms for the interface to come up + int cnt = 0; + while (cnt < 50) { + usleep(10000); // sleep 10ms + + // read the existing flags + if (ioctl(sock, SIOCGIFFLAGS, &ifr ) < 0) { + close(sock); + printf("Error fnet: cannot bring up interface %s\n", ifname); + errExit("ioctl"); + } + if (ifr.ifr_flags & IFF_RUNNING) + break; + cnt++; + } + + close(sock); +} + +int net_get_mtu(const char *ifname) { + int mtu = 0; + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); + exit(1); + } + + int s; + struct ifreq ifr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == 0) + mtu = ifr.ifr_mtu; + close(s); + + + return mtu; +} + +void net_set_mtu(const char *ifname, int mtu) { + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error fnet: invalid network device name %s\n", ifname); + exit(1); + } + + int s; + struct ifreq ifr; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_mtu = mtu; + if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) != 0) + fprintf(stderr, "Warning fnet: cannot set mtu for interface %s\n", ifname); + close(s); +} + +// scan interfaces in current namespace and print IP address/mask for each interface +void net_ifprint(int scan) { + uint32_t ip; + uint32_t mask; + struct ifaddrs *ifaddr, *ifa; + + if (getifaddrs(&ifaddr) == -1) + errExit("getifaddrs"); + + printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n", + "Interface", "MAC", "IP", "Mask", "Status"); + // walk through the linked list + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL) + continue; + + if (ifa->ifa_addr->sa_family == AF_INET) { + struct sockaddr_in *si = (struct sockaddr_in *) ifa->ifa_netmask; + mask = ntohl(si->sin_addr.s_addr); + si = (struct sockaddr_in *) ifa->ifa_addr; + ip = ntohl(si->sin_addr.s_addr); + + // interface status + char *status; + if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) + status = "UP"; + else + status = "DOWN"; + + // ip address and mask + char ipstr[30]; + sprintf(ipstr, "%d.%d.%d.%d", PRINT_IP(ip)); + char maskstr[30]; + sprintf(maskstr, "%d.%d.%d.%d", PRINT_IP(mask)); + + // mac address + unsigned char mac[6]; + net_get_mac(ifa->ifa_name, mac); + char macstr[30]; + if (strcmp(ifa->ifa_name, "lo") == 0) + macstr[0] = '\0'; + else + sprintf(macstr, "%02x:%02x:%02x:%02x:%02x:%02x", PRINT_MAC(mac)); + + // print + printf("%-17.17s%-19.19s%-17.17s%-17.17s%-6.6s\n", + ifa->ifa_name, macstr, ipstr, maskstr, status); + + // network scanning + if (!scan) // scanning disabled + continue; + if (strcmp(ifa->ifa_name, "lo") == 0) // no loopbabck scanning + continue; + if (mask2bits(mask) < 16) // not scanning large networks + continue; + if (!ip) // if not configured + continue; + // only if the interface is up and running + if (ifa->ifa_flags & IFF_RUNNING && ifa->ifa_flags & IFF_UP) + arp_scan(ifa->ifa_name, ip, mask); + } + } + freeifaddrs(ifaddr); +} + +int net_get_mac(const char *ifname, unsigned char mac[6]) { + + struct ifreq ifr; + int sock; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + + if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) + errExit("ioctl"); + memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); + + close(sock); + return 0; +} + +// configure interface ipv4 address +void net_if_ip(const char *ifname, uint32_t ip, uint32_t mask, int mtu) { + if (strlen(ifname) > IFNAMSIZ) { + fprintf(stderr, "Error: invalid network device name %s\n", ifname); + exit(1); + } + + int sock = socket(AF_INET,SOCK_DGRAM,0); + if (sock < 0) + errExit("socket"); + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(ip); + if (ioctl( sock, SIOCSIFADDR, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + + if (ip != 0) { + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr = htonl(mask); + if (ioctl( sock, SIOCSIFNETMASK, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + } + + // configure mtu + if (mtu > 0) { + ifr.ifr_mtu = mtu; + if (ioctl( sock, SIOCSIFMTU, &ifr ) < 0) { + close(sock); + errExit("ioctl"); + } + } + + close(sock); + usleep(10000); // sleep 10ms +} + +int net_if_mac(const char *ifname, const unsigned char mac[6]) { + struct ifreq ifr; + int sock; + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + errExit("socket"); + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; + memcpy(ifr.ifr_hwaddr.sa_data, mac, 6); + + if (ioctl(sock, SIOCSIFHWADDR, &ifr) == -1) + errExit("ioctl"); + close(sock); + return 0; +} + +// configure interface ipv6 address +// ex: firejail --net=eth0 --ip6=2001:0db8:0:f101::1/64 +struct ifreq6 { + struct in6_addr ifr6_addr; + uint32_t ifr6_prefixlen; + unsigned int ifr6_ifindex; +}; +void net_if_ip6(const char *ifname, const char *addr6) { + if (strchr(addr6, ':') == NULL) { + fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6); + exit(1); + } + + // extract prefix + unsigned long prefix; + char *ptr; + if ((ptr = strchr(addr6, '/'))) { + prefix = atol(ptr + 1); + if (prefix > 128) { + fprintf(stderr, "Error fnet: invalid prefix for IPv6 address %s\n", addr6); + exit(1); + } + *ptr = '\0'; // mark the end of the address + } + else + prefix = 128; + + // extract address + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + int rv = inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr); + if (rv <= 0) { + fprintf(stderr, "Error fnet: invalid IPv6 address %s\n", addr6); + exit(1); + } + + // open socket + int sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); + if (sock < 0) { + fprintf(stderr, "Error fnet: IPv6 is not supported on this system\n"); + exit(1); + } + + // find interface index + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + if (ioctl(sock, SIOGIFINDEX, &ifr) < 0) { + perror("ioctl SIOGIFINDEX"); + exit(1); + } + + // configure address + struct ifreq6 ifr6; + memset(&ifr6, 0, sizeof(ifr6)); + ifr6.ifr6_prefixlen = prefix; + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + memcpy((char *) &ifr6.ifr6_addr, (char *) &sin6.sin6_addr, sizeof(struct in6_addr)); + if (ioctl(sock, SIOCSIFADDR, &ifr6) < 0) { + perror("ioctl SIOCSIFADDR"); + exit(1); + } + + close(sock); +} diff --git a/src/fnet/main.c b/src/fnet/main.c new file mode 100644 index 000000000..4ae9eb6e3 --- /dev/null +++ b/src/fnet/main.c @@ -0,0 +1,103 @@ + /* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fnet.h" + +static void usage(void) { + printf("Usage:\n"); + printf("\tfnet create veth dev1 dev2 bridge child\n"); + printf("\tfnet create macvlan dev parent child\n"); + printf("\tfnet moveif dev proc\n"); + printf("\tfnet printif\n"); + printf("\tfnet printif scan\n"); + printf("\tfnet config interface dev ip mask mtu\n"); + printf("\tfnet config mac addr\n"); + printf("\tfnet config ipv6 dev ipn"); + printf("\tfmet ifup dev\n"); +} + +int main(int argc, char **argv) { +#if 0 +{ +//system("cat /proc/self/status"); +int i; +for (i = 0; i < argc; i++) + printf("*%s* ", argv[i]); +printf("\n"); +} +#endif + if (argc < 2) + return 1; + + + + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { + usage(); + return 0; + } + else if (argc == 3 && strcmp(argv[1], "ifup") == 0) { + net_if_up(argv[2]); + } + else if (argc == 2 && strcmp(argv[1], "printif") == 0) { + net_ifprint(0); + } + else if (argc == 3 && strcmp(argv[1], "printif") == 0 && strcmp(argv[2], "scan") == 0) { + net_ifprint(1); + } + else if (argc == 7 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "veth") == 0) { + // create veth pair and move one end in the the namespace + net_create_veth(argv[3], argv[4], atoi(argv[6])); + // connect the ohter veth end to the bridge ... + net_bridge_add_interface(argv[5], argv[3]); + // ... and bring it up + net_if_up(argv[3]); + } + else if (argc == 6 && strcmp(argv[1], "create") == 0 && strcmp(argv[2], "macvlan") == 0) { + net_create_macvlan(argv[3], argv[4], atoi(argv[5])); + } + else if (argc == 7 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "interface") == 0) { + char *dev = argv[3]; + uint32_t ip = (uint32_t) atoll(argv[4]); + uint32_t mask = (uint32_t) atoll(argv[5]); + int mtu = atoi(argv[6]); + // configure interface + net_if_ip(dev, ip, mask, mtu); + // ... and bring it up + net_if_up(dev); + } + else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "mac") == 0) { + unsigned char mac[6]; + if (atomac(argv[4], mac)) { + fprintf(stderr, "Error fnet: invalid mac address %s\n", argv[4]); + } + net_if_mac(argv[3], mac); + } + else if (argc == 4 && strcmp(argv[1], "moveif") == 0) { + net_move_interface(argv[2], atoi(argv[3])); + } + else if (argc == 5 && strcmp(argv[1], "config") == 0 && strcmp(argv[2], "ipv6") == 0) { + net_if_ip6(argv[3], argv[4]); + } + else { + fprintf(stderr, "Error fnet: invalid arguments\n"); + return 1; + } + + return 0; +} diff --git a/src/firejail/veth.c b/src/fnet/veth.c similarity index 96% rename from src/firejail/veth.c rename to src/fnet/veth.c index df3c1d1f9..d06bc9256 100644 --- a/src/firejail/veth.c +++ b/src/fnet/veth.c @@ -45,7 +45,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include "firejail.h" +#include "fnet.h" #include "../include/libnetlink.h" #include #include @@ -63,8 +63,6 @@ int net_create_veth(const char *dev, const char *nsdev, unsigned pid) { int len; struct iplink_req req; - if (arg_debug) - printf("create veth %s/%s/%u\n", dev, nsdev, pid); assert(dev); assert(nsdev); assert(pid); @@ -120,8 +118,6 @@ int net_create_veth(const char *dev, const char *nsdev, unsigned pid) { int net_create_macvlan(const char *dev, const char *parent, unsigned pid) { int len; struct iplink_req req; - if (arg_debug) - printf("create macvlan %s, parent %s\n", dev, parent); assert(dev); assert(parent); @@ -184,8 +180,6 @@ int net_create_macvlan(const char *dev, const char *parent, unsigned pid) { // when the interface is moved, netlink does not preserve interface configuration int net_move_interface(const char *dev, unsigned pid) { struct iplink_req req; - if (arg_debug) - printf("move device %s inside the namespace\n", dev); assert(dev); if (rtnl_open(&rth, 0) < 0) { diff --git a/src/fseccomp/Makefile.in b/src/fseccomp/Makefile.in new file mode 100644 index 000000000..110d2c95f --- /dev/null +++ b/src/fseccomp/Makefile.in @@ -0,0 +1,43 @@ +all: fseccomp + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sysconfdir=@sysconfdir@ + +VERSION=@PACKAGE_VERSION@ +NAME=@PACKAGE_NAME@ +HAVE_SECCOMP_H=@HAVE_SECCOMP_H@ +HAVE_SECCOMP=@HAVE_SECCOMP@ +HAVE_CHROOT=@HAVE_CHROOT@ +HAVE_BIND=@HAVE_BIND@ +HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@ +HAVE_NETWORK=@HAVE_NETWORK@ +HAVE_USERNS=@HAVE_USERNS@ +HAVE_X11=@HAVE_X11@ +HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@ +HAVE_WHITELIST=@HAVE_WHITELIST@ +HAVE_GLOBALCFG=@HAVE_GLOBALCFG@ +HAVE_APPARMOR=@HAVE_APPARMOR@ +HAVE_OVERLAYFS=@HAVE_OVERLAYFS@ +HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@ +EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@ + +H_FILE_LIST = $(sort $(wildcard *.[h])) +C_FILE_LIST = $(sort $(wildcard *.c)) +OBJS = $(C_FILE_LIST:.c=.o) +BINOBJS = $(foreach file, $(OBJS), $file) +CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security +LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread + +%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h + $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ + +fseccomp: $(OBJS) ../lib/libnetlink.o ../lib/common.o + $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS) + +clean:; rm -f *.o fseccomp + +distclean: clean + rm -fr Makefile + diff --git a/src/fseccomp/errno.c b/src/fseccomp/errno.c new file mode 100644 index 000000000..dbee916d4 --- /dev/null +++ b/src/fseccomp/errno.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fseccomp.h" + +#include +//#include + +typedef struct { + char *name; + int nr; +} ErrnoEntry; + +static ErrnoEntry errnolist[] = { +// +// code generated using tools/extract-errnos +// + {"EPERM", EPERM}, + {"ENOENT", ENOENT}, + {"ESRCH", ESRCH}, + {"EINTR", EINTR}, + {"EIO", EIO}, + {"ENXIO", ENXIO}, + {"E2BIG", E2BIG}, + {"ENOEXEC", ENOEXEC}, + {"EBADF", EBADF}, + {"ECHILD", ECHILD}, + {"EAGAIN", EAGAIN}, + {"ENOMEM", ENOMEM}, + {"EACCES", EACCES}, + {"EFAULT", EFAULT}, + {"ENOTBLK", ENOTBLK}, + {"EBUSY", EBUSY}, + {"EEXIST", EEXIST}, + {"EXDEV", EXDEV}, + {"ENODEV", ENODEV}, + {"ENOTDIR", ENOTDIR}, + {"EISDIR", EISDIR}, + {"EINVAL", EINVAL}, + {"ENFILE", ENFILE}, + {"EMFILE", EMFILE}, + {"ENOTTY", ENOTTY}, + {"ETXTBSY", ETXTBSY}, + {"EFBIG", EFBIG}, + {"ENOSPC", ENOSPC}, + {"ESPIPE", ESPIPE}, + {"EROFS", EROFS}, + {"EMLINK", EMLINK}, + {"EPIPE", EPIPE}, + {"EDOM", EDOM}, + {"ERANGE", ERANGE}, + {"EDEADLK", EDEADLK}, + {"ENAMETOOLONG", ENAMETOOLONG}, + {"ENOLCK", ENOLCK}, + {"ENOSYS", ENOSYS}, + {"ENOTEMPTY", ENOTEMPTY}, + {"ELOOP", ELOOP}, + {"EWOULDBLOCK", EWOULDBLOCK}, + {"ENOMSG", ENOMSG}, + {"EIDRM", EIDRM}, + {"ECHRNG", ECHRNG}, + {"EL2NSYNC", EL2NSYNC}, + {"EL3HLT", EL3HLT}, + {"EL3RST", EL3RST}, + {"ELNRNG", ELNRNG}, + {"EUNATCH", EUNATCH}, + {"ENOCSI", ENOCSI}, + {"EL2HLT", EL2HLT}, + {"EBADE", EBADE}, + {"EBADR", EBADR}, + {"EXFULL", EXFULL}, + {"ENOANO", ENOANO}, + {"EBADRQC", EBADRQC}, + {"EBADSLT", EBADSLT}, + {"EDEADLOCK", EDEADLOCK}, + {"EBFONT", EBFONT}, + {"ENOSTR", ENOSTR}, + {"ENODATA", ENODATA}, + {"ETIME", ETIME}, + {"ENOSR", ENOSR}, + {"ENONET", ENONET}, + {"ENOPKG", ENOPKG}, + {"EREMOTE", EREMOTE}, + {"ENOLINK", ENOLINK}, + {"EADV", EADV}, + {"ESRMNT", ESRMNT}, + {"ECOMM", ECOMM}, + {"EPROTO", EPROTO}, + {"EMULTIHOP", EMULTIHOP}, + {"EDOTDOT", EDOTDOT}, + {"EBADMSG", EBADMSG}, + {"EOVERFLOW", EOVERFLOW}, + {"ENOTUNIQ", ENOTUNIQ}, + {"EBADFD", EBADFD}, + {"EREMCHG", EREMCHG}, + {"ELIBACC", ELIBACC}, + {"ELIBBAD", ELIBBAD}, + {"ELIBSCN", ELIBSCN}, + {"ELIBMAX", ELIBMAX}, + {"ELIBEXEC", ELIBEXEC}, + {"EILSEQ", EILSEQ}, + {"ERESTART", ERESTART}, + {"ESTRPIPE", ESTRPIPE}, + {"EUSERS", EUSERS}, + {"ENOTSOCK", ENOTSOCK}, + {"EDESTADDRREQ", EDESTADDRREQ}, + {"EMSGSIZE", EMSGSIZE}, + {"EPROTOTYPE", EPROTOTYPE}, + {"ENOPROTOOPT", ENOPROTOOPT}, + {"EPROTONOSUPPORT", EPROTONOSUPPORT}, + {"ESOCKTNOSUPPORT", ESOCKTNOSUPPORT}, + {"EOPNOTSUPP", EOPNOTSUPP}, + {"EPFNOSUPPORT", EPFNOSUPPORT}, + {"EAFNOSUPPORT", EAFNOSUPPORT}, + {"EADDRINUSE", EADDRINUSE}, + {"EADDRNOTAVAIL", EADDRNOTAVAIL}, + {"ENETDOWN", ENETDOWN}, + {"ENETUNREACH", ENETUNREACH}, + {"ENETRESET", ENETRESET}, + {"ECONNABORTED", ECONNABORTED}, + {"ECONNRESET", ECONNRESET}, + {"ENOBUFS", ENOBUFS}, + {"EISCONN", EISCONN}, + {"ENOTCONN", ENOTCONN}, + {"ESHUTDOWN", ESHUTDOWN}, + {"ETOOMANYREFS", ETOOMANYREFS}, + {"ETIMEDOUT", ETIMEDOUT}, + {"ECONNREFUSED", ECONNREFUSED}, + {"EHOSTDOWN", EHOSTDOWN}, + {"EHOSTUNREACH", EHOSTUNREACH}, + {"EALREADY", EALREADY}, + {"EINPROGRESS", EINPROGRESS}, + {"ESTALE", ESTALE}, + {"EUCLEAN", EUCLEAN}, + {"ENOTNAM", ENOTNAM}, + {"ENAVAIL", ENAVAIL}, + {"EISNAM", EISNAM}, + {"EREMOTEIO", EREMOTEIO}, + {"EDQUOT", EDQUOT}, + {"ENOMEDIUM", ENOMEDIUM}, + {"EMEDIUMTYPE", EMEDIUMTYPE}, + {"ECANCELED", ECANCELED}, + {"ENOKEY", ENOKEY}, + {"EKEYEXPIRED", EKEYEXPIRED}, + {"EKEYREVOKED", EKEYREVOKED}, + {"EKEYREJECTED", EKEYREJECTED}, + {"EOWNERDEAD", EOWNERDEAD}, + {"ENOTRECOVERABLE", ENOTRECOVERABLE}, + {"ERFKILL", ERFKILL}, + {"EHWPOISON", EHWPOISON}, + {"ENOTSUP", ENOTSUP}, +#ifdef ENOATTR + {"ENOATTR", ENOATTR}, +#endif +}; + +int errno_find_name(const char *name) { + int i; + int elems = sizeof(errnolist) / sizeof(errnolist[0]); + for (i = 0; i < elems; i++) { + if (strcasecmp(name, errnolist[i].name) == 0) + return errnolist[i].nr; + } + + return -1; +} + +char *errno_find_nr(int nr) { + int i; + int elems = sizeof(errnolist) / sizeof(errnolist[0]); + for (i = 0; i < elems; i++) { + if (nr == errnolist[i].nr) + return errnolist[i].name; + } + + return "unknown"; +} + + + +void errno_print(void) { + int i; + int elems = sizeof(errnolist) / sizeof(errnolist[0]); + for (i = 0; i < elems; i++) { + printf("%d\t- %s\n", errnolist[i].nr, errnolist[i].name); + } + printf("\n"); +} diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h new file mode 100644 index 000000000..504f1c23f --- /dev/null +++ b/src/fseccomp/fseccomp.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#ifndef FSECCOMP_H +#define FSECCOMP_H +#include +#include +#include +#include +#include "../include/common.h" + +// syscall.c +void syscall_print(void); +int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg); +int syscall_find_name(const char *name); +char *syscall_find_nr(int nr); + +// errno.c +void errno_print(void); +int errno_find_name(const char *name); +char *errno_find_nr(int nr); + +// protocol.c +void protocol_print(void); +void protocol_build_filter(const char *prlist, const char *fname); + +// seccomp_secondary.c +void seccomp_secondary_64(const char *fname); +void seccomp_secondary_32(const char *fname); + +// seccomp_file.c +void filter_init(int fd); +void filter_add_whitelist(int fd, int syscall, int arg); +void filter_add_blacklist(int fd, int syscall, int arg); +void filter_add_errno(int fd, int syscall, int arg); +void filter_end_blacklist(int fd); +void filter_end_whitelist(int fd); + +// seccomp.c +// default list +void seccomp_default(const char *fname, int allow_debuggers); +// drop list +void seccomp_drop(const char *fname, char *list, int allow_debuggers); +// default+drop list +void seccomp_default_drop(const char *fname, char *list, int allow_debuggers); +// whitelisted filter +void seccomp_keep(const char *fname, char *list); + +// seccomp_print +void filter_print(const char *fname); + +#endif diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c new file mode 100644 index 000000000..22b13bcd9 --- /dev/null +++ b/src/fseccomp/main.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fseccomp.h" + +static void usage(void) { + printf("Usage:\n"); + printf("\tfseccomp debug-syscalls\n"); + printf("\tfseccomp debug-errnos\n"); + printf("\tfseccomp debug-protocols\n"); + printf("\tfseccomp protocol build list file\n"); + printf("\tfseccomp secondary 64 file\n"); + printf("\tfseccomp secondary 32 file\n"); + printf("\tfseccomp default file\n"); + printf("\tfseccomp default file allow-debuggers\n"); + printf("\tfseccomp drop file list\n"); + printf("\tfseccomp drop file list allow-debuggers\n"); + printf("\tfseccomp default drop file list\n"); + printf("\tfseccomp default drop file list allow-debuggers\n"); + printf("\tfseccomp keep file list\n"); + printf("\tfseccomp print file\n"); +} + +int main(int argc, char **argv) { +#if 0 +{ +system("cat /proc/self/status"); +int i; +for (i = 0; i < argc; i++) + printf("*%s* ", argv[i]); +printf("\n"); +} +#endif + if (argc < 2) + return 1; + + if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { + usage(); + return 0; + } + else if (argc == 2 && strcmp(argv[1], "debug-syscalls") == 0) + syscall_print(); + else if (argc == 2 && strcmp(argv[1], "debug-errnos") == 0) + errno_print(); + else if (argc == 2 && strcmp(argv[1], "debug-protocols") == 0) + protocol_print(); + else if (argc == 5 && strcmp(argv[1], "protocol") == 0 && strcmp(argv[2], "build") == 0) + protocol_build_filter(argv[3], argv[4]); + else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "64") == 0) + seccomp_secondary_64(argv[3]); + else if (argc == 4 && strcmp(argv[1], "secondary") == 0 && strcmp(argv[2], "32") == 0) + seccomp_secondary_32(argv[3]); + else if (argc == 3 && strcmp(argv[1], "default") == 0) + seccomp_default(argv[2], 0); + else if (argc == 4 && strcmp(argv[1], "default") == 0 && strcmp(argv[3], "allow-debuggers") == 0) + seccomp_default(argv[2], 1); + else if (argc == 4 && strcmp(argv[1], "drop") == 0) + seccomp_drop(argv[2], argv[3], 0); + else if (argc == 5 && strcmp(argv[1], "drop") == 0 && strcmp(argv[4], "allow-debuggers") == 0) + seccomp_drop(argv[2], argv[3], 1); + else if (argc == 5 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0) + seccomp_default_drop(argv[3], argv[4], 0); + else if (argc == 6 && strcmp(argv[1], "default") == 0 && strcmp(argv[2], "drop") == 0 && strcmp(argv[5], "allow-debuggers") == 0) + seccomp_default_drop(argv[3], argv[4], 1); + else if (argc == 4 && strcmp(argv[1], "keep") == 0) + seccomp_keep(argv[2], argv[3]); + else if (argc == 3 && strcmp(argv[1], "print") == 0) + filter_print(argv[2]); + else { + fprintf(stderr, "Error fseccomp: invalid arguments\n"); + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/src/fseccomp/protocol.c b/src/fseccomp/protocol.c new file mode 100644 index 000000000..38c5f9d88 --- /dev/null +++ b/src/fseccomp/protocol.c @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +/* + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL, + ONLY(SYS_socket), + EXAMINE_ARGUMENT(0), // allow only AF_INET and AF_INET6, drop everything else + WHITELIST(AF_INET), + WHITELIST(AF_INET6), + WHITELIST(AF_PACKET), + RETURN_ERRNO(ENOTSUP) + }; + struct sock_fprog prog = { + .len = (unsigned short)(sizeof(filter) / sizeof(filter[0])), + .filter = filter, + }; + + + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { + perror("prctl(NO_NEW_PRIVS)"); + return 1; + } + if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { + perror("prctl"); + return 1; + } +*/ + +#include "fseccomp.h" +#include "../include/seccomp.h" +#include +#include +#include + +static char *protocol[] = { + "unix", + "inet", + "inet6", + "netlink", + "packet", + NULL +}; + +static struct sock_filter protocol_filter_command[] = { + WHITELIST(AF_UNIX), + WHITELIST(AF_INET), + WHITELIST(AF_INET6), + WHITELIST(AF_NETLINK), + WHITELIST(AF_PACKET) +}; +// Note: protocol[] and protocol_filter_command are synchronized + +// command length +struct sock_filter whitelist[] = { + WHITELIST(AF_UNIX) +}; +unsigned whitelist_len = sizeof(whitelist) / sizeof(struct sock_filter); + +static struct sock_filter *find_protocol_domain(const char *p) { + int i = 0; + while (protocol[i] != NULL) { + if (strcmp(protocol[i], p) == 0) + return &protocol_filter_command[i * whitelist_len]; + i++; + } + + return NULL; +} + + +void protocol_print(void) { +#ifndef SYS_socket + fprintf(stderr, "Warning fseccomp: firejail --protocol not supported on this platform\n"); + return; +#endif + + int i = 0; + while (protocol[i] != NULL) { + printf("%s, ", protocol[i]); + i++; + } + printf("\n"); +} + +// install protocol filter +void protocol_build_filter(const char *prlist, const char *fname) { + assert(prlist); + assert(fname); + +#ifndef SYS_socket + fprintf(stderr, "Warning: --protocol not supported on this platform\n"); + return; +#else + // build the filter + struct sock_filter filter[32]; // big enough + memset(&filter[0], 0, sizeof(filter)); + uint8_t *ptr = (uint8_t *) &filter[0]; + + // header + struct sock_filter filter_start[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL, + ONLY(SYS_socket), + EXAMINE_ARGUMENT(0) + }; + memcpy(ptr, &filter_start[0], sizeof(filter_start)); + ptr += sizeof(filter_start); + +#if 0 +printf("entries %u\n", (unsigned) (sizeof(filter_start) / sizeof(struct sock_filter))); +{ + unsigned j; + unsigned char *ptr2 = (unsigned char *) &filter[0]; + for (j = 0; j < sizeof(filter); j++, ptr2++) { + if ((j % (sizeof(struct sock_filter))) == 0) + printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter)))); + printf("%02x, ", (*ptr2) & 0xff); + } + printf("\n"); +} +printf("whitelist_len %u, struct sock_filter len %u\n", whitelist_len, (unsigned) sizeof(struct sock_filter)); +#endif + + + // parse list and add commands + char *tmplist = strdup(prlist); + if (!tmplist) + errExit("strdup"); + char *token = strtok(tmplist, ","); + if (!token) + errExit("strtok"); + + while (token) { + struct sock_filter *domain = find_protocol_domain(token); + if (domain == NULL) { + fprintf(stderr, "Error fseccomp: %s is not a valid protocol\n", token); + exit(1); + } + memcpy(ptr, domain, whitelist_len * sizeof(struct sock_filter)); + ptr += whitelist_len * sizeof(struct sock_filter); + token = strtok(NULL, ","); + +#if 0 +printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter)); +{ + unsigned j; + unsigned char *ptr2 = (unsigned char *) &filter[0]; + for (j = 0; j < sizeof(filter); j++, ptr2++) { + if ((j % (sizeof(struct sock_filter))) == 0) + printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter)))); + printf("%02x, ", (*ptr2) & 0xff); + } + printf("\n"); +} +#endif + + + } + free(tmplist); + + // add end of filter + struct sock_filter filter_end[] = { + RETURN_ERRNO(ENOTSUP) + }; + memcpy(ptr, &filter_end[0], sizeof(filter_end)); + ptr += sizeof(filter_end); + +#if 0 +printf("entries %u\n", (unsigned) ((uint64_t) ptr - (uint64_t) (filter)) / (unsigned) sizeof(struct sock_filter)); +{ + unsigned j; + unsigned char *ptr2 = (unsigned char *) &filter[0]; + for (j = 0; j < sizeof(filter); j++, ptr2++) { + if ((j % (sizeof(struct sock_filter))) == 0) + printf("\n%u: ", 1 + (unsigned) (j / (sizeof(struct sock_filter)))); + printf("%02x, ", (*ptr2) & 0xff); + } + printf("\n"); +} +#endif + // save filter to file + int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (dst < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + int size = (int) ((uintptr_t) ptr - (uintptr_t) (filter)); + int written = 0; + while (written < size) { + int rv = write(dst, (unsigned char *) filter + written, size - written); + if (rv == -1) { + fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); + exit(1); + } + written += rv; + } + close(dst); +#endif // SYS_socket +} diff --git a/src/fseccomp/seccomp.c b/src/fseccomp/seccomp.c new file mode 100644 index 000000000..cc6edc8ca --- /dev/null +++ b/src/fseccomp/seccomp.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fseccomp.h" +#include "../include/seccomp.h" +#include + +static void add_default_list(int fd, int allow_debuggers) { +#ifdef SYS_mount + filter_add_blacklist(fd, SYS_mount, 0); +#endif +#ifdef SYS_umount2 + filter_add_blacklist(fd, SYS_umount2, 0); +#endif + + if (!allow_debuggers) { +#ifdef SYS_ptrace + filter_add_blacklist(fd, SYS_ptrace, 0); +#endif + } + +#ifdef SYS_kexec_load + filter_add_blacklist(fd, SYS_kexec_load, 0); +#endif +#ifdef SYS_kexec_file_load + filter_add_blacklist(fd, SYS_kexec_file_load, 0); +#endif +#ifdef SYS_open_by_handle_at + filter_add_blacklist(fd, SYS_open_by_handle_at, 0); +#endif +#ifdef SYS_name_to_handle_at + filter_add_blacklist(fd, SYS_name_to_handle_at, 0); +#endif +#ifdef SYS_init_module + filter_add_blacklist(fd, SYS_init_module, 0); +#endif +#ifdef SYS_finit_module + filter_add_blacklist(fd, SYS_finit_module, 0); +#endif +#ifdef SYS_create_module + filter_add_blacklist(fd, SYS_create_module, 0); +#endif +#ifdef SYS_delete_module + filter_add_blacklist(fd, SYS_delete_module, 0); +#endif +#ifdef SYS_iopl + filter_add_blacklist(fd, SYS_iopl, 0); +#endif +#ifdef SYS_ioperm + filter_add_blacklist(fd, SYS_ioperm, 0); +#endif +#ifdef SYS_ioprio_set + filter_add_blacklist(fd, SYS_ioprio_set, 0); +#endif +#ifdef SYS_ni_syscall + filter_add_blacklist(fd, SYS_ni_syscall, 0); +#endif +#ifdef SYS_swapon + filter_add_blacklist(fd, SYS_swapon, 0); +#endif +#ifdef SYS_swapoff + filter_add_blacklist(fd, SYS_swapoff, 0); +#endif +#ifdef SYS_syslog + filter_add_blacklist(fd, SYS_syslog, 0); +#endif + + if (!allow_debuggers) { +#ifdef SYS_process_vm_readv + filter_add_blacklist(fd, SYS_process_vm_readv, 0); +#endif + } + +#ifdef SYS_process_vm_writev + filter_add_blacklist(fd, SYS_process_vm_writev, 0); +#endif + + // mknod removed in 0.9.29 - it brakes Zotero extension + //#ifdef SYS_mknod + // filter_add_blacklist(SYS_mknod, 0); + //#endif + +#ifdef SYS_sysfs + filter_add_blacklist(fd, SYS_sysfs, 0); +#endif +#ifdef SYS__sysctl + filter_add_blacklist(fd, SYS__sysctl, 0); +#endif +#ifdef SYS_adjtimex + filter_add_blacklist(fd, SYS_adjtimex, 0); +#endif +#ifdef SYS_clock_adjtime + filter_add_blacklist(fd, SYS_clock_adjtime, 0); +#endif +#ifdef SYS_lookup_dcookie + filter_add_blacklist(fd, SYS_lookup_dcookie, 0); +#endif +#ifdef SYS_perf_event_open + filter_add_blacklist(fd, SYS_perf_event_open, 0); +#endif +#ifdef SYS_fanotify_init + filter_add_blacklist(fd, SYS_fanotify_init, 0); +#endif +#ifdef SYS_kcmp + filter_add_blacklist(fd, SYS_kcmp, 0); +#endif +#ifdef SYS_add_key + filter_add_blacklist(fd, SYS_add_key, 0); +#endif +#ifdef SYS_request_key + filter_add_blacklist(fd, SYS_request_key, 0); +#endif +#ifdef SYS_keyctl + filter_add_blacklist(fd, SYS_keyctl, 0); +#endif +#ifdef SYS_uselib + filter_add_blacklist(fd, SYS_uselib, 0); +#endif +#ifdef SYS_acct + filter_add_blacklist(fd, SYS_acct, 0); +#endif +#ifdef SYS_modify_ldt + filter_add_blacklist(fd, SYS_modify_ldt, 0); +#endif +#ifdef SYS_pivot_root + filter_add_blacklist(fd, SYS_pivot_root, 0); +#endif +#ifdef SYS_io_setup + filter_add_blacklist(fd, SYS_io_setup, 0); +#endif +#ifdef SYS_io_destroy + filter_add_blacklist(fd, SYS_io_destroy, 0); +#endif +#ifdef SYS_io_getevents + filter_add_blacklist(fd, SYS_io_getevents, 0); +#endif +#ifdef SYS_io_submit + filter_add_blacklist(fd, SYS_io_submit, 0); +#endif +#ifdef SYS_io_cancel + filter_add_blacklist(fd, SYS_io_cancel, 0); +#endif +#ifdef SYS_remap_file_pages + filter_add_blacklist(fd, SYS_remap_file_pages, 0); +#endif +#ifdef SYS_mbind + filter_add_blacklist(fd, SYS_mbind, 0); +#endif +#ifdef SYS_get_mempolicy + filter_add_blacklist(fd, SYS_get_mempolicy, 0); +#endif +#ifdef SYS_set_mempolicy + filter_add_blacklist(fd, SYS_set_mempolicy, 0); +#endif +#ifdef SYS_migrate_pages + filter_add_blacklist(fd, SYS_migrate_pages, 0); +#endif +#ifdef SYS_move_pages + filter_add_blacklist(fd, SYS_move_pages, 0); +#endif +#ifdef SYS_vmsplice + filter_add_blacklist(fd, SYS_vmsplice, 0); +#endif +#ifdef SYS_chroot + filter_add_blacklist(fd, SYS_chroot, 0); +#endif +#ifdef SYS_tuxcall + filter_add_blacklist(fd, SYS_tuxcall, 0); +#endif +#ifdef SYS_reboot + filter_add_blacklist(fd, SYS_reboot, 0); +#endif +#ifdef SYS_nfsservctl + filter_add_blacklist(fd, SYS_nfsservctl, 0); +#endif +#ifdef SYS_get_kernel_syms + filter_add_blacklist(fd, SYS_get_kernel_syms, 0); +#endif +} + +// default list +void seccomp_default(const char *fname, int allow_debuggers) { + assert(fname); + + // open file + int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + // build filter + filter_init(fd); + add_default_list(fd, allow_debuggers); + filter_end_blacklist(fd); + + // close file + close(fd); +} + +// drop list +void seccomp_drop(const char *fname, char *list, int allow_debuggers) { + assert(fname); + (void) allow_debuggers; // todo: to implemnet it + + // open file + int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + // build filter + filter_init(fd); + if (syscall_check_list(list, filter_add_blacklist, fd, 0)) { + fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); + exit(1); + } + filter_end_blacklist(fd); + + // close file + close(fd); +} + +// default+drop +void seccomp_default_drop(const char *fname, char *list, int allow_debuggers) { + assert(fname); + + // open file + int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + // build filter + filter_init(fd); + add_default_list(fd, allow_debuggers); + if (syscall_check_list(list, filter_add_blacklist, fd, 0)) { + fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); + exit(1); + } + filter_end_blacklist(fd); + + // close file + close(fd); +} + +void seccomp_keep(const char *fname, char *list) { + // open file + int fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + // build filter + filter_init(fd); + // these 4 syscalls are used by firejail after the seccomp filter is initialized + filter_add_whitelist(fd, SYS_setuid, 0); + filter_add_whitelist(fd, SYS_setgid, 0); + filter_add_whitelist(fd, SYS_setgroups, 0); + filter_add_whitelist(fd, SYS_dup, 0); + filter_add_whitelist(fd, SYS_prctl, 0); + + if (syscall_check_list(list, filter_add_whitelist, fd, 0)) { + fprintf(stderr, "Error fseccomp: cannot build seccomp filter\n"); + exit(1); + } + + filter_end_whitelist(fd); + + // close file + close(fd); +} + diff --git a/src/fseccomp/seccomp_file.c b/src/fseccomp/seccomp_file.c new file mode 100644 index 000000000..10ef9dd31 --- /dev/null +++ b/src/fseccomp/seccomp_file.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fseccomp.h" +#include "../include/seccomp.h" +#include + +static void write_to_file(int fd, void *data, int size) { + assert(data); + assert(size); + + int written = 0; + while (written < size) { + int rv = write(fd, (unsigned char *) data + written, size - written); + if (rv == -1) { + fprintf(stderr, "Error fseccomp: cannot write seccomp file\n"); + exit(1); + } + written += rv; + } +} + +void filter_init(int fd) { +#if defined(__x86_64__) +#define X32_SYSCALL_BIT 0x40000000 + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL, + // handle X32 ABI + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, X32_SYSCALL_BIT, 1, 0), + BPF_JUMP(BPF_JMP+BPF_JGE+BPF_K, 0, 1, 0), + RETURN_ERRNO(EPERM) + }; +#else + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL + }; +#endif + +#if 0 +{ + int i; + unsigned char *ptr = (unsigned char *) &filter[0]; + for (i = 0; i < sizeof(filter); i++, ptr++) + printf("%x, ", (*ptr) & 0xff); + printf("\n"); +} +#endif + + write_to_file(fd, filter, sizeof(filter)); +} + +void filter_add_whitelist(int fd, int syscall, int arg) { + (void) arg; + + struct sock_filter filter[] = { + WHITELIST(syscall) + }; + write_to_file(fd, filter, sizeof(filter)); +} + +void filter_add_blacklist(int fd, int syscall, int arg) { + (void) arg; + + struct sock_filter filter[] = { + BLACKLIST(syscall) + }; + write_to_file(fd, filter, sizeof(filter)); +} + +void filter_add_errno(int fd, int syscall, int arg) { + struct sock_filter filter[] = { + BLACKLIST_ERRNO(syscall, arg) + }; + write_to_file(fd, filter, sizeof(filter)); +} + +void filter_end_blacklist(int fd) { + struct sock_filter filter[] = { + RETURN_ALLOW + }; + write_to_file(fd, filter, sizeof(filter)); +} + +void filter_end_whitelist(int fd) { + struct sock_filter filter[] = { + KILL_PROCESS + }; + write_to_file(fd, filter, sizeof(filter)); +} + diff --git a/src/fseccomp/seccomp_print.c b/src/fseccomp/seccomp_print.c new file mode 100644 index 000000000..7dc983b12 --- /dev/null +++ b/src/fseccomp/seccomp_print.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fseccomp.h" +#include "../include/seccomp.h" +#include + +static struct sock_filter *filter = NULL; +static int filter_cnt = 0; + +static void load_seccomp(const char *fname) { + assert(fname); + + // check file + struct stat s; + if (stat(fname, &s) == -1) { + fprintf(stderr, "Error fseccomp: cannot read protocol filter file\n"); + exit(1); + } + int size = s.st_size; + unsigned short entries = (unsigned short) size / (unsigned short) sizeof(struct sock_filter); + filter_cnt = entries; +//printf("size %d, entries %d\n", s.st_size, entries); + + filter = malloc(sizeof(struct sock_filter) * entries); + if (!filter) + errExit("malloc"); + + // read filter + memset(filter, 0, sizeof(struct sock_filter) * entries); + int src = open(fname, O_RDONLY); + int rd = 0; + while (rd < size) { + int rv = read(src, (unsigned char *) filter + rd, size - rd); + if (rv == -1) { + fprintf(stderr, "Error fseccomp: cannot read %s file\n", fname); + exit(1); + } + rd += rv; + } + close(src); +} + +// debug filter +void filter_print(const char *fname) { + assert(fname); + load_seccomp(fname); + + // start filter + struct sock_filter start[] = { + VALIDATE_ARCHITECTURE, + EXAMINE_SYSCALL + }; + + // print sizes + printf("SECCOMP Filter:\n"); + + // test the start of the filter + if (memcmp(&start[0], filter, sizeof(start)) == 0) { + printf(" VALIDATE_ARCHITECTURE\n"); + printf(" EXAMINE_SYSCAL\n"); + } + else { + printf("Invalid seccomp filter %s\n", fname); + return; + } + + // loop trough blacklists + int i = 4; + while (i < filter_cnt) { + // minimal parsing! + unsigned char *ptr = (unsigned char *) &filter[i]; + int *nr = (int *) (ptr + 4); + if (*ptr == 0x15 && *(ptr +14) == 0xff && *(ptr + 15) == 0x7f ) { + printf(" WHITELIST %d %s\n", *nr, syscall_find_nr(*nr)); + i += 2; + } + else if (*ptr == 0x15 && *(ptr +14) == 0 && *(ptr + 15) == 0) { + printf(" BLACKLIST %d %s\n", *nr, syscall_find_nr(*nr)); + i += 2; + } + else if (*ptr == 0x15 && *(ptr +14) == 0x5 && *(ptr + 15) == 0) { + int err = *(ptr + 13) << 8 | *(ptr + 12); + printf(" ERRNO %d %s %d %s\n", *nr, syscall_find_nr(*nr), err, errno_find_nr(err)); + i += 2; + } + else if (*ptr == 0x06 && *(ptr +6) == 0 && *(ptr + 7) == 0 ) { + printf(" KILL_PROCESS\n"); + i++; + } + else if (*ptr == 0x06 && *(ptr +6) == 0xff && *(ptr + 7) == 0x7f ) { + printf(" RETURN_ALLOW\n"); + i++; + } + else { + printf(" UNKNOWN ENTRY!!!\n"); + i++; + } + } +} diff --git a/src/fseccomp/seccomp_secondary.c b/src/fseccomp/seccomp_secondary.c new file mode 100644 index 000000000..a856e5aef --- /dev/null +++ b/src/fseccomp/seccomp_secondary.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2014-2016 Firejail Authors + * + * This file is part of firejail project + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include "fseccomp.h" +#include "../include/seccomp.h" +#include + +void seccomp_secondary_64(const char *fname) { + // hardcoded syscall values + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE_64, + EXAMINE_SYSCALL, + BLACKLIST(165), // mount + BLACKLIST(166), // umount2 +// todo: implement --allow-debuggers + BLACKLIST(101), // ptrace + BLACKLIST(246), // kexec_load + BLACKLIST(304), // open_by_handle_at + BLACKLIST(303), // name_to_handle_at + BLACKLIST(174), // create_module + BLACKLIST(175), // init_module + BLACKLIST(313), // finit_module + BLACKLIST(176), // delete_module + BLACKLIST(172), // iopl + BLACKLIST(173), // ioperm + BLACKLIST(251), // ioprio_set + BLACKLIST(167), // swapon + BLACKLIST(168), // swapoff + BLACKLIST(103), // syslog + BLACKLIST(310), // process_vm_readv + BLACKLIST(311), // process_vm_writev + BLACKLIST(139), // sysfs + BLACKLIST(156), // _sysctl + BLACKLIST(159), // adjtimex + BLACKLIST(305), // clock_adjtime + BLACKLIST(212), // lookup_dcookie + BLACKLIST(298), // perf_event_open + BLACKLIST(300), // fanotify_init + BLACKLIST(312), // kcmp + BLACKLIST(248), // add_key + BLACKLIST(249), // request_key + BLACKLIST(250), // keyctl + BLACKLIST(134), // uselib + BLACKLIST(163), // acct + BLACKLIST(154), // modify_ldt + BLACKLIST(155), // pivot_root + BLACKLIST(206), // io_setup + BLACKLIST(207), // io_destroy + BLACKLIST(208), // io_getevents + BLACKLIST(209), // io_submit + BLACKLIST(210), // io_cancel + BLACKLIST(216), // remap_file_pages + BLACKLIST(237), // mbind + BLACKLIST(239), // get_mempolicy + BLACKLIST(238), // set_mempolicy + BLACKLIST(256), // migrate_pages + BLACKLIST(279), // move_pages + BLACKLIST(278), // vmsplice + BLACKLIST(161), // chroot + BLACKLIST(184), // tuxcall + BLACKLIST(169), // reboot + BLACKLIST(180), // nfsservctl + BLACKLIST(177), // get_kernel_syms + + RETURN_ALLOW + }; + + // save filter to file + int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (dst < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + int size = (int) sizeof(filter); + int written = 0; + while (written < size) { + int rv = write(dst, (unsigned char *) filter + written, size - written); + if (rv == -1) { + fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); + exit(1); + } + written += rv; + } + close(dst); +} + +// i386 filter installed on amd64 architectures +void seccomp_secondary_32(const char *fname) { + // hardcoded syscall values + struct sock_filter filter[] = { + VALIDATE_ARCHITECTURE_32, + EXAMINE_SYSCALL, + BLACKLIST(21), // mount + BLACKLIST(52), // umount2 +// todo: implement --allow-debuggers + BLACKLIST(26), // ptrace + BLACKLIST(283), // kexec_load + BLACKLIST(341), // name_to_handle_at + BLACKLIST(342), // open_by_handle_at + BLACKLIST(127), // create_module + BLACKLIST(128), // init_module + BLACKLIST(350), // finit_module + BLACKLIST(129), // delete_module + BLACKLIST(110), // iopl + BLACKLIST(101), // ioperm + BLACKLIST(289), // ioprio_set + BLACKLIST(87), // swapon + BLACKLIST(115), // swapoff + BLACKLIST(103), // syslog + BLACKLIST(347), // process_vm_readv + BLACKLIST(348), // process_vm_writev + BLACKLIST(135), // sysfs + BLACKLIST(149), // _sysctl + BLACKLIST(124), // adjtimex + BLACKLIST(343), // clock_adjtime + BLACKLIST(253), // lookup_dcookie + BLACKLIST(336), // perf_event_open + BLACKLIST(338), // fanotify_init + BLACKLIST(349), // kcmp + BLACKLIST(286), // add_key + BLACKLIST(287), // request_key + BLACKLIST(288), // keyctl + BLACKLIST(86), // uselib + BLACKLIST(51), // acct + BLACKLIST(123), // modify_ldt + BLACKLIST(217), // pivot_root + BLACKLIST(245), // io_setup + BLACKLIST(246), // io_destroy + BLACKLIST(247), // io_getevents + BLACKLIST(248), // io_submit + BLACKLIST(249), // io_cancel + BLACKLIST(257), // remap_file_pages + BLACKLIST(274), // mbind + BLACKLIST(275), // get_mempolicy + BLACKLIST(276), // set_mempolicy + BLACKLIST(294), // migrate_pages + BLACKLIST(317), // move_pages + BLACKLIST(316), // vmsplice + BLACKLIST(61), // chroot + BLACKLIST(88), // reboot + BLACKLIST(169), // nfsservctl + BLACKLIST(130), // get_kernel_syms + + RETURN_ALLOW + }; + + // save filter to file + int dst = open(fname, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (dst < 0) { + fprintf(stderr, "Error fseccomp: cannot open %s file\n", fname); + exit(1); + } + + int size = (int) sizeof(filter); + int written = 0; + while (written < size) { + int rv = write(dst, (unsigned char *) filter + written, size - written); + if (rv == -1) { + fprintf(stderr, "Error fseccomp: cannot write %s file\n", fname); + exit(1); + } + written += rv; + } + close(dst); +} + diff --git a/src/firejail/syscall.c b/src/fseccomp/syscall.c similarity index 88% rename from src/firejail/syscall.c rename to src/fseccomp/syscall.c index 985cc8bb8..e2052efde 100644 --- a/src/firejail/syscall.c +++ b/src/fseccomp/syscall.c @@ -17,9 +17,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#ifdef HAVE_SECCOMP -#include "firejail.h" +#include "fseccomp.h" #include typedef struct { @@ -31,25 +29,14 @@ static SyscallEntry syslist[] = { // // code generated using tools/extract-syscall // -#include "syscall.h" +#include "../include/syscall.h" // // end of generated code // }; // end of syslist -const char *syscall_find_nr(int nr) { - int i; - int elems = sizeof(syslist) / sizeof(syslist[0]); - for (i = 0; i < elems; i++) { - if (nr == syslist[i].nr) - return syslist[i].name; - } - - return "unknown"; -} - // return -1 if error, or syscall number -static int syscall_find_name(const char *name) { +int syscall_find_name(const char *name) { int i; int elems = sizeof(syslist) / sizeof(syslist[0]); for (i = 0; i < elems; i++) { @@ -60,8 +47,28 @@ static int syscall_find_name(const char *name) { return -1; } +char *syscall_find_nr(int nr) { + int i; + int elems = sizeof(syslist) / sizeof(syslist[0]); + for (i = 0; i < elems; i++) { + if (nr == syslist[i].nr) + return syslist[i].name; + } + + return "unknown"; +} + +void syscall_print(void) { + int i; + int elems = sizeof(syslist) / sizeof(syslist[0]); + for (i = 0; i < elems; i++) { + printf("%d\t- %s\n", syslist[i].nr, syslist[i].name); + } + printf("\n"); +} + // return 1 if error, 0 if OK -int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg), int arg) { +int syscall_check_list(const char *slist, void (*callback)(int fd, int syscall, int arg), int fd, int arg) { // don't allow empty lists if (slist == NULL || *slist == '\0') { fprintf(stderr, "Error: empty syscall lists are not allowed\n"); @@ -84,7 +91,7 @@ int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg) if (nr == -1) fprintf(stderr, "Warning: syscall %s not found\n", start); else if (callback != NULL) - callback(nr, arg); + callback(fd, nr, arg); start = ptr + 1; } @@ -95,22 +102,9 @@ int syscall_check_list(const char *slist, void (*callback)(int syscall, int arg) if (nr == -1) fprintf(stderr, "Warning: syscall %s not found\n", start); else if (callback != NULL) - callback(nr, arg); + callback(fd, nr, arg); } free(str); return 0; } - -void syscall_print(void) { - EUID_ASSERT(); - - int i; - int elems = sizeof(syslist) / sizeof(syslist[0]); - for (i = 0; i < elems; i++) { - printf("%d\t- %s\n", syslist[i].nr, syslist[i].name); - } - printf("\n"); -} - -#endif // HAVE_SECCOMP diff --git a/src/include/common.h b/src/include/common.h index e28870807..f7c8ea725 100644 --- a/src/include/common.h +++ b/src/include/common.h @@ -113,5 +113,5 @@ int join_namespace(pid_t pid, char *type); int name2pid(const char *name, pid_t *pid); char *pid_proc_comm(const pid_t pid); char *pid_proc_cmdline(const pid_t pid); -int pid_proc_cmdline_x11(const pid_t pid); +int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid); #endif diff --git a/src/firejail/seccomp.h b/src/include/seccomp.h similarity index 100% rename from src/firejail/seccomp.h rename to src/include/seccomp.h diff --git a/src/firejail/syscall.h b/src/include/syscall.h similarity index 99% rename from src/firejail/syscall.h rename to src/include/syscall.h index 68d4b5736..9a29779c9 100644 --- a/src/firejail/syscall.h +++ b/src/include/syscall.h @@ -20,7 +20,6 @@ // content extracted from /bits/syscall.h file form glibc 2.22 // using ../tools/extract_syscall tool - #if !defined __x86_64__ #ifdef SYS__llseek #ifdef __NR__llseek diff --git a/src/lib/common.c b/src/lib/common.c index acb6bd3b4..fc4c167ba 100644 --- a/src/lib/common.c +++ b/src/lib/common.c @@ -201,7 +201,7 @@ char *pid_proc_cmdline(const pid_t pid) { } // return 1 if firejail --x11 on command line -int pid_proc_cmdline_x11(const pid_t pid) { +int pid_proc_cmdline_x11_xpra_xephyr(const pid_t pid) { // if comm is not firejail return 0 char *comm = pid_proc_comm(pid); if (strcmp(comm, "firejail") != 0) { @@ -248,8 +248,11 @@ int pid_proc_cmdline_x11(const pid_t pid) { break; if (strncmp(arg, "--", 2) != 0) break; - - // check x11 + + if (strcmp(arg, "--x11=xorg") == 0) + return 0; + + // check x11 xpra or xephyr if (strncmp(arg, "--x11", 5) == 0) return 1; i += strlen(arg); diff --git a/src/lib/pid.c b/src/lib/pid.c index bbb123b81..ef1a428fb 100644 --- a/src/lib/pid.c +++ b/src/lib/pid.c @@ -341,7 +341,7 @@ void pid_read(pid_t mon_pid) { } if ((strncmp(ptr, "firejail", 8) == 0) && (mon_pid == 0 || mon_pid == pid)) { - if (pid_proc_cmdline_x11(pid)) + if (pid_proc_cmdline_x11_xpra_xephyr(pid)) pids[pid].level = -1; else pids[pid].level = 1; diff --git a/src/man/firejail-login.txt b/src/man/firejail-login.txt index 691217253..796179d0b 100644 --- a/src/man/firejail-login.txt +++ b/src/man/firejail-login.txt @@ -13,6 +13,10 @@ Example: netblue:--net=none --protocol=unix +Wildcard patterns are accepted in the user name field: + + user*: --private + .SH RESTRICTED SHELL To configure a restricted shell, replace /bin/bash with /usr/bin/firejail in /etc/passwd file for each user that needs to be restricted. Alternatively, diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index d420fab7a..09dc46bbc 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt @@ -218,7 +218,7 @@ Blacklist violations logged to syslog. Whitelist directory or file. A temporary file system is mounted on the top directory, and the whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, everything else is discarded when the sandbox is closed. The top directory could be -user home, /dev, /media, /mnt, /opt, /var, and /tmp. +user home, /dev, /media, /mnt, /opt, /srv, /var, and /tmp. .br .br diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 4aebb71e8..666a6a8ef 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt @@ -1622,7 +1622,7 @@ $ firejail \-\-net=br0 --veth-name=if0 Whitelist directory or file. A temporary file system is mounted on the top directory, and the whitelisted files are mount-binded inside. Modifications to whitelisted files are persistent, everything else is discarded when the sandbox is closed. The top directory could be -user home, /dev, /media, /mnt, /opt, /var, and /tmp. +user home, /dev, /media, /mnt, /opt, /srv, /var, and /tmp. .br .br diff --git a/test/apps-x11-xorg/apps-x11-xorg.sh b/test/apps-x11-xorg/apps-x11-xorg.sh new file mode 100755 index 000000000..b05914b52 --- /dev/null +++ b/test/apps-x11-xorg/apps-x11-xorg.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +export MALLOC_CHECK_=3 +export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) + +which firefox +if [ "$?" -eq 0 ]; +then + echo "TESTING: firefox x11 xorg" + ./firefox.exp +else + echo "TESTING SKIP: firefox not found" +fi + +which transmission-gtk +if [ "$?" -eq 0 ]; +then + echo "TESTING: transmission-gtk x11 xorg" + ./transmission-gtk.exp +else + echo "TESTING SKIP: transmission-gtk not found" +fi + +which icedove +if [ "$?" -eq 0 ]; +then + echo "TESTING: icedove x11 xorg" + ./icedove.exp +else + echo "TESTING SKIP: icedove not found" +fi + diff --git a/test/apps-x11-xorg/firefox.exp b/test/apps-x11-xorg/firefox.exp new file mode 100755 index 000000000..5231bf8ed --- /dev/null +++ b/test/apps-x11-xorg/firefox.exp @@ -0,0 +1,90 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=test --x11=xorg firefox -no-remote www.gentoo.org\r" +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "firefox" {puts "firefox detected\n";} + "iceweasel" {puts "iceweasel detected\n";} +} +expect { + timeout {puts "TESTING ERROR 3.2\n";exit} + "no-remote" +} +sleep 1 +# grsecurity exit +send -- "file /proc/sys/kernel/grsecurity\r" +expect { + timeout {puts "TESTING ERROR - grsecurity detection\n";exit} + "grsecurity: directory" {puts "grsecurity present, exiting...\n";exit} + "cannot open" {puts "grsecurity not present\n"} +} +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + " firefox" {puts "firefox detected\n";} + " iceweasel" {puts "iceweasel detected\n";} +} +expect { + timeout {puts "TESTING ERROR 5.0\n";exit} + "no-remote" +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + " firefox" {puts "firefox detected\n";} + " iceweasel" {puts "iceweasel detected\n";} +} +expect { + timeout {puts "TESTING ERROR 6.0\n";exit} + "no-remote" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd:" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firejail --shutdown=test\r" +sleep 3 + +puts "\nall done\n" + diff --git a/test/apps-x11-xorg/icedove.exp b/test/apps-x11-xorg/icedove.exp new file mode 100755 index 000000000..f676264ed --- /dev/null +++ b/test/apps-x11-xorg/icedove.exp @@ -0,0 +1,85 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=test --x11=xorg icedove\r" +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "icedove" +} +sleep 1 + +# grsecurity exit +send -- "file /proc/sys/kernel/grsecurity\r" +expect { + timeout {puts "TESTING ERROR - grsecurity detection\n";exit} + "grsecurity: directory" {puts "grsecurity present, exiting...\n";exit} + "cannot open" {puts "grsecurity not present\n"} +} + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 5.0\n";exit} + "icedove" +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 2 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 6.0\n";exit} + "icedove" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firejail --shutdown=test\r" +sleep 3 + +puts "\nall done\n" + diff --git a/test/apps-x11-xorg/transmission-gtk.exp b/test/apps-x11-xorg/transmission-gtk.exp new file mode 100755 index 000000000..a91a1be08 --- /dev/null +++ b/test/apps-x11-xorg/transmission-gtk.exp @@ -0,0 +1,85 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail --name=test --x11=xorg transmission-gtk\r" +sleep 10 + +spawn $env(SHELL) +send -- "firejail --list\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 3.1\n";exit} + "transmission-gtk" +} +sleep 1 + +# grsecurity exit +send -- "file /proc/sys/kernel/grsecurity\r" +expect { + timeout {puts "TESTING ERROR - grsecurity detection\n";exit} + "grsecurity: directory" {puts "grsecurity present, exiting...\n";exit} + "cannot open" {puts "grsecurity not present\n"} +} + +send -- "firejail --name=blablabla\r" +expect { + timeout {puts "TESTING ERROR 4\n";exit} + "Child process initialized" +} +sleep 2 + +spawn $env(SHELL) +send -- "firemon --seccomp\r" +expect { + timeout {puts "TESTING ERROR 5\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 5.0\n";exit} + "transmission-gtk" +} +expect { + timeout {puts "TESTING ERROR 5.1 (seccomp)\n";exit} + "Seccomp: 2" +} +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firemon --caps\r" +expect { + timeout {puts "TESTING ERROR 6\n";exit} + ":firejail" +} +expect { + timeout {puts "TESTING ERROR 6.0\n";exit} + "transmission-gtk" +} +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "CapBnd" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "0000000000000000" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "name=blablabla" +} +sleep 1 +send -- "firejail --shutdown=test\r" +sleep 3 + +puts "\nall done\n" + diff --git a/test/environment/allow-debuggers.exp b/test/environment/allow-debuggers.exp index dde9c4cc1..8a404decb 100755 --- a/test/environment/allow-debuggers.exp +++ b/test/environment/allow-debuggers.exp @@ -11,19 +11,27 @@ expect { "Child process initialized" } expect { - timeout {puts "TESTING ERROR 1\n";exit} - "exited with 0" + timeout {puts "TESTING ERROR 1\n";exit} + "ioctl" +} +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "exit_group" } after 100 send -- "firejail --allow-debuggers --profile=/etc/firejail/firefox.profile strace ls\r" expect { - timeout {puts "TESTING ERROR 2\n";exit} + timeout {puts "TESTING ERROR 3\n";exit} "Child process initialized" } expect { - timeout {puts "TESTING ERROR 3\n";exit} - "exited with 0" + timeout {puts "TESTING ERROR 4\n";exit} + "ioctl" +} +expect { + timeout {puts "TESTING ERROR 5\n";exit} + "exit_group" } after 100 diff --git a/test/filters/filters.sh b/test/filters/filters.sh index 5093c8614..5c7c98b3e 100755 --- a/test/filters/filters.sh +++ b/test/filters/filters.sh @@ -12,11 +12,21 @@ echo "TESTING: noroot (test/filters/noroot.exp)" echo "TESTING: capabilities (test/filters/caps.exp)" ./caps.exp +rm -f seccomp-test-file +if [ "$(uname -m)" = "x86_64" ]; then + echo "TESTING: fseccomp (test/filters/fseccomp.exp)" + ./fseccomp.exp +else + echo "TESTING SKIP: fseccomp test implemented only for x86_64" +fi +rm -f seccomp-test-file + + if [ "$(uname -m)" = "x86_64" ]; then echo "TESTING: protocol (test/filters/protocol.exp)" ./protocol.exp else - echo "TESTING SKIP: protocol, not running on x86_64" + echo "TESTING SKIP: protocol, running only on x86_64" fi echo "TESTING: seccomp bad empty (test/filters/seccomp-bad-empty.exp)" @@ -50,9 +60,6 @@ echo "TESTING: seccomp chmod profile - seccomp lists (test/filters/seccomp-chmod echo "TESTING: seccomp empty (test/filters/seccomp-empty.exp)" ./seccomp-empty.exp -echo "TESTING: seccomp bad empty (test/filters/seccomp-bad-empty.exp)" -./seccomp-bad-empty.exp - if [ "$(uname -m)" = "x86_64" ]; then echo "TESTING: seccomp dual filter (test/filters/seccomp-dualfilter.exp)" ./seccomp-dualfilter.exp diff --git a/test/filters/fseccomp.exp b/test/filters/fseccomp.exp new file mode 100755 index 000000000..8a9a8f9dc --- /dev/null +++ b/test/filters/fseccomp.exp @@ -0,0 +1,138 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +after 100 +send -- "/usr/lib/firejail/fseccomp debug-syscalls\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "1 - write" +} + +after 100 +send -- "/usr/lib/firejail/fseccomp debug-errnos\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "1 - EPERM" +} + +after 100 +send -- "/usr/lib/firejail/fseccomp debug-protocols\r" +expect { + timeout {puts "TESTING ERROR 3\n";exit} + "unix, inet, inet6, netlink, packet," +} + +after 100 +send -- "/usr/lib/firejail/fseccomp protocol build unix,inet seccomp-test-file\r" +after 100 +send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" +expect { + timeout {puts "TESTING ERROR 4.1\n";exit} + "WHITELIST 41 socket" +} + +after 100 +send -- "/usr/lib/firejail/fseccomp secondary 64 seccomp-test-file\r" +after 100 +send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" +expect { + timeout {puts "TESTING ERROR 5.1\n";exit} + "BLACKLIST 165 mount" +} +expect { + timeout {puts "TESTING ERROR 5.2\n";exit} + "BLACKLIST 166 umount2" +} +expect { + timeout {puts "TESTING ERROR 5.3\n";exit} + "RETURN_ALLOW" +} + +after 100 +send -- "/usr/lib/firejail/fseccomp default seccomp-test-file\r" +after 100 +send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" +expect { + timeout {puts "TESTING ERROR 6.1\n";exit} + "BLACKLIST 165 mount" +} +expect { + timeout {puts "TESTING ERROR 6.2\n";exit} + "BLACKLIST 166 umount2" +} +expect { + timeout {puts "TESTING ERROR 6.3\n";exit} + "RETURN_ALLOW" +} + +after 100 +send -- "/usr/lib/firejail/fseccomp drop seccomp-test-file chmod,chown\r" +after 100 +send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" +expect { + timeout {puts "TESTING ERROR 7.1\n";exit} + "BLACKLIST 165 mount" {puts "TESTING ERROR 7.2\n";exit} + "BLACKLIST 166 umount2" {puts "TESTING ERROR 7.3\n";exit} + "BLACKLIST 90 chmod" +} +expect { + timeout {puts "TESTING ERROR 7.4\n";exit} + "BLACKLIST 92 chown" +} +expect { + timeout {puts "TESTING ERROR 7.5\n";exit} + "RETURN_ALLOW" +} + +after 100 +send -- "/usr/lib/firejail/fseccomp default drop seccomp-test-file chmod,chown\r" +after 100 +send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" +expect { + timeout {puts "TESTING ERROR 8.1\n";exit} + "BLACKLIST 165 mount" +} +expect { + timeout {puts "TESTING ERROR 8.2\n";exit} + "BLACKLIST 166 umount2" +} +expect { + timeout {puts "TESTING ERROR 8.3\n";exit} + "BLACKLIST 90 chmod" +} +expect { + timeout {puts "TESTING ERROR 8.4\n";exit} + "BLACKLIST 92 chown" +} +expect { + timeout {puts "TESTING ERROR 8.5\n";exit} + "RETURN_ALLOW" +} +after 100 +send -- "/usr/lib/firejail/fseccomp keep seccomp-test-file chmod,chown\r" +after 100 +send -- "/usr/lib/firejail/fseccomp print seccomp-test-file\r" +expect { + timeout {puts "TESTING ERROR 9.1\n";exit} + "WHITELIST 90 chmod" +} +expect { + timeout {puts "TESTING ERROR 9.2\n";exit} + "WHITELIST 92 chown" +} +expect { + timeout {puts "TESTING ERROR 9.3\n";exit} + "KILL_PROCESS" +} + + + +after 100 +puts "\nall done\n" + diff --git a/test/filters/noroot.exp b/test/filters/noroot.exp index 2a7cb7975..b011f2bf9 100755 --- a/test/filters/noroot.exp +++ b/test/filters/noroot.exp @@ -46,20 +46,20 @@ expect { } send -- "sudo -s\r" expect { - timeout {puts "TESTING ERROR 8\n";exit} + timeout {puts "TESTING ERROR 7\n";exit} "effective uid is not 0, is sudo installed setuid root?" { puts "OK\n";} "sudo must be owned by uid 0 and have the setuid bit set" { puts "OK\n";} "Bad system call" { puts "OK\n";} } send -- "cat /proc/self/uid_map | wc -l\r" expect { - timeout {puts "TESTING ERROR 7\n";exit} + timeout {puts "TESTING ERROR 8\n";exit} "1" } send -- "cat /proc/self/gid_map | wc -l\r" expect { - timeout {puts "TESTING ERROR 8\n";exit} - "3" + timeout {puts "TESTING ERROR 9\n";exit} + "5" } puts "\n" @@ -70,59 +70,59 @@ sleep 2 send -- "firejail --name=test --noroot --noprofile\r" expect { - timeout {puts "TESTING ERROR 9\n";exit} + timeout {puts "TESTING ERROR 10\n";exit} "Child process initialized" } sleep 1 send -- "cat /proc/self/status\r" expect { - timeout {puts "TESTING ERROR 10\n";exit} + timeout {puts "TESTING ERROR 11\n";exit} "CapBnd:" } expect { - timeout {puts "TESTING ERROR 11\n";exit} + timeout {puts "TESTING ERROR 12\n";exit} "ffffffff" } expect { - timeout {puts "TESTING ERROR 12\n";exit} + timeout {puts "TESTING ERROR 13\n";exit} "Seccomp:" } expect { - timeout {puts "TESTING ERROR 13\n";exit} + timeout {puts "TESTING ERROR 14\n";exit} "0" } expect { - timeout {puts "TESTING ERROR 14\n";exit} + timeout {puts "TESTING ERROR 15\n";exit} "Cpus_allowed:" } puts "\n" send -- "whoami\r" expect { - timeout {puts "TESTING ERROR 15\n";exit} + timeout {puts "TESTING ERROR 16\n";exit} $env(USER) } send -- "sudo -s\r" expect { - timeout {puts "TESTING ERROR 16\n";exit} + timeout {puts "TESTING ERROR 17\n";exit} "effective uid is not 0, is sudo installed setuid root?" { puts "OK\n";} "sudo must be owned by uid 0 and have the setuid bit set" { puts "OK\n";} } send -- "ping 0\r" expect { - timeout {puts "TESTING ERROR 17\n";exit} + timeout {puts "TESTING ERROR 18\n";exit} "Operation not permitted" } send -- "cat /proc/self/uid_map | wc -l\r" expect { - timeout {puts "TESTING ERROR 18\n";exit} + timeout {puts "TESTING ERROR 19\n";exit} "1" } send -- "cat /proc/self/gid_map | wc -l\r" expect { - timeout {puts "TESTING ERROR 19\n";exit} - "3" + timeout {puts "TESTING ERROR 20\n";exit} + "5" } @@ -130,31 +130,31 @@ expect { spawn $env(SHELL) send -- "firejail --debug --join=test\r" expect { - timeout {puts "TESTING ERROR 20\n";exit} + timeout {puts "TESTING ERROR 21\n";exit} "User namespace detected" } expect { - timeout {puts "TESTING ERROR 21\n";exit} + timeout {puts "TESTING ERROR 22\n";exit} "Joining user namespace" } sleep 1 send -- "sudo -s\r" expect { - timeout {puts "TESTING ERROR 22\n";exit} + timeout {puts "TESTING ERROR 23\n";exit} "effective uid is not 0, is sudo installed setuid root?" { puts "OK\n";} "sudo must be owned by uid 0 and have the setuid bit set" { puts "OK\n";} "Permission denied" { puts "OK\n";} } send -- "cat /proc/self/uid_map | wc -l\r" expect { - timeout {puts "TESTING ERROR 23\n";exit} + timeout {puts "TESTING ERROR 24\n";exit} "1" } send -- "cat /proc/self/gid_map | wc -l\r" expect { - timeout {puts "TESTING ERROR 24\n";exit} - "3" + timeout {puts "TESTING ERROR 25\n";exit} + "5" } after 100 puts "\nall done\n" diff --git a/test/fs/fs.sh b/test/fs/fs.sh index d45ef48bd..3139b8eae 100755 --- a/test/fs/fs.sh +++ b/test/fs/fs.sh @@ -6,6 +6,9 @@ export MALLOC_CHECK_=3 export MALLOC_PERTURB_=$(($RANDOM % 255 + 1)) +echo "TESTING: /sys/fs access (test/fs/sys_fs.exp)" +./sys_fs.exp + echo "TESTING: kmsg access (test/fs/kmsg.exp)" ./kmsg.exp diff --git a/test/fs/sys_fs.exp b/test/fs/sys_fs.exp new file mode 100755 index 000000000..f512776d9 --- /dev/null +++ b/test/fs/sys_fs.exp @@ -0,0 +1,44 @@ +#!/usr/bin/expect -f +# This file is part of Firejail project +# Copyright (C) 2014-2016 Firejail Authors +# License GPL v2 + +set timeout 10 +spawn $env(SHELL) +match_max 100000 + +send -- "firejail\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls /sys/fs\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "Permission denied" +} +after 100 + +send -- "exit\r" +sleep 1 + +send -- "firejail --noblacklist=/sys/fs\r" +expect { + timeout {puts "TESTING ERROR 1\n";exit} + "Child process initialized" +} +sleep 1 + +send -- "ls /sys/fs\r" +expect { + timeout {puts "TESTING ERROR 2\n";exit} + "cgroup" +} +after 100 +send -- "exit\r" +after 100 + +puts "\nall done\n" +