Просмотр исходного кода

Add a bubblewrap jail that allows to create a sandboxed environment (#4687)

* Add a bubblewrap jail that allows to create a sandboxed environment

* Rebase and format

---------

Co-authored-by: Jaap Marcus <9754650+jaapmarcus@users.noreply.github.com>
Robert-Jan de Dreu 1 год назад
Родитель
Сommit
0a3eeb8e5f

+ 19 - 0
bin/v-add-sys-ssh-jail

@@ -29,6 +29,11 @@ if [ ! -x /sbin/jk_init ]; then
 	exit
 fi
 
+# Checking if bubblewrap is installed
+if [ ! -x /bin/bwrap ]; then
+	exit
+fi
+
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
 
@@ -36,6 +41,20 @@ check_hestia_demo_mode
 #                       Action                             #
 #----------------------------------------------------------#
 
+# Move jailbash to /usr/sbin
+if [ ! -x /usr/sbin/jailbash ]; then
+	cp -f $HESTIA_COMMON_DIR/bubblewrap/jailbash /usr/sbin/jailbash
+	cp -f $HESTIA_COMMON_DIR/bubblewrap/bwrap-userns-restrict /etc/apparmor.d/bwrap-userns-restrict
+	chmod +x /usr/sbin/jailbash
+
+	service apparmor reload > /dev/null 2>&1
+fi
+
+# Register /usr/sbin/jailbash
+if [ -z "$(grep ^/usr/sbin/jailbash /etc/shells)" ]; then
+	echo "/usr/sbin/jailbash" >> /etc/shells
+fi
+
 # Checking sshd directives
 config='/etc/ssh/sshd_config'
 ssh_i=$(grep -n "^# Hestia SSH Chroot" $config)

+ 11 - 0
bin/v-delete-sys-ssh-jail

@@ -29,6 +29,17 @@ check_hestia_demo_mode
 #                       Action                             #
 #----------------------------------------------------------#
 
+# Unregister /usr/sbin/jailbash
+sed -i "/\/usr\/sbin\/jailbash/d" /etc/shells
+
+# Remove jailbash from /usr/sbin
+if [ -x /usr/sbin/jailbash ]; then
+	rm -f /usr/sbin/jailbash
+	rm -f /etc/apparmor.d/bwrap-userns-restrict
+
+	service apparmor reload > /dev/null 2>&1
+fi
+
 # Checking sshd directives
 config='/etc/ssh/sshd_config'
 ssh_i=$(grep -n "^# Hestia SSH Chroot" $config)

+ 85 - 0
install/common/bubblewrap/bwrap-userns-restrict

@@ -0,0 +1,85 @@
+# This profile allows almost everything and only exists to allow bwrap
+# to work on a system with user namespace restrictions being enforced.
+# bwrap is allowed access to user namespaces and capabilities within
+# the user namespace, but its children do not have capabilities,
+# blocking bwrap from being able to be used to arbitrarily by-pass the
+# user namespace restrictions.
+
+# Note: the bwrap child is stacked against the bwrap profile due to
+# bwraps use of no-new-privs.
+
+abi <abi/4.0>,
+
+include <tunables/global>
+
+profile bwrap /usr/bin/bwrap flags=(attach_disconnected,mediate_deleted) {
+  allow capability,
+  # not allow all, to allow for pix stack on systems that don't support
+  # rule priority.
+  #
+  # sadly we have to allow 'm' every where to allow children to work under
+  # profile stacking atm.
+  allow file rwlkm /{**,},
+  allow network,
+  allow unix,
+  allow ptrace,
+  allow signal,
+  allow mqueue,
+  allow io_uring,
+  allow userns,
+  allow mount,
+  allow umount,
+  allow pivot_root,
+  allow dbus,
+
+  # stacked like this due to no-new-privs restriction
+  # this will stack a target profile against bwrap and unpriv_bwrap
+  # Ideally
+  # - there would be a transition at userns creation first. This would allow
+  #   for the bwrap profile to be tighter, and looser within the user
+  #   ns. bwrap will still have to fairly loose until a transition at
+  #   namespacing in general (not just user ns) is available.
+  # - there would be an independent second target as fallback
+  #   This would allow for select target profiles to be used, and not
+  #   necessarily stack the unpriv_bwrap in cases where this is desired
+  #
+  # the ix works here because stack will apply to ix fallback
+  # Ideally we would sanitize the environment across a privilege boundry
+  # (leaving bwarp into application) but flatpak etc use environment glibc
+  # sanitized environment variables as part of the sandbox setup.
+  allow pix /** -> &bwrap//&unpriv_bwrap,
+
+  # the local include should not be used without understanding the userns
+  # restriction.
+  # Site-specific additions and overrides. See local/README for details.
+  include if exists <local/bwrap-userns-restrict>
+}
+
+# The unpriv_bwrap profile is used to strip capabilities within the userns
+profile unpriv_bwrap flags=(attach_disconnected,mediate_deleted) {
+  # not allow all, to allow for pix stack
+  allow file rwlkm /{**,},
+  allow network,
+  allow unix,
+  allow ptrace,
+  allow signal,
+  allow mqueue,
+  allow io_uring,
+  allow userns,
+  allow mount,
+  allow umount,
+  allow pivot_root,
+  allow dbus,
+
+  # bwrap profile does stacking against itself this will keep the target
+  # profile from having elevated privileges in the container.
+  # If done recursively the stack will remove any duplicate
+  allow pix /** -> &unpriv_bwrap,
+
+  audit deny capability,
+
+  # the local include should not be used without understanding the userns
+  # restriction.
+  # Site-specific additions and overrides. See local/README for details.
+  include if exists <local/unpriv_bwrap>
+}

+ 43 - 0
install/common/bubblewrap/jailbash

@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Use bubblewrap to run /bin/bash reusing the host OS binaries (/usr), but with
+# separate /tmp, /home, /var, /run, and /etc. For /etc we just inherit the
+# host's resolv.conf, and set up "stub" passwd/group files.
+
+set -euo pipefail
+(exec -a jailbash bwrap --ro-bind /usr /usr \
+	--ro-bind /lib /lib \
+	--ro-bind-try /lib64 /lib64 \
+	--tmpfs /usr/lib/modules \
+	--tmpfs /usr/lib/systemd \
+	--ro-bind /bin /bin \
+	--ro-bind /sbin /sbin \
+	--dir /var \
+	--dir /tmp \
+	--symlink ../tmp var/tmp \
+	--proc /proc \
+	--dev /dev \
+	--bind ${HOME} ${HOME} \
+	--ro-bind-try /etc/profile /etc/profile \
+	--ro-bind-try /etc/alternatives /etc/alternatives \
+	--ro-bind-try /etc/localtime /etc/localtime \
+	--ro-bind-try /etc/ld.so.cache /etc/ld.so.cache \
+	--ro-bind-try /etc/resolv.conf /etc/resolv.conf \
+	--ro-bind-try /etc/hosts /etc/hosts \
+	--ro-bind-try /etc/nsswitch.conf /etc/nsswitch.conf \
+	--ro-bind-try /etc/ssl /etc/ssl \
+	--ro-bind-try /etc/pki /etc/pki \
+	--ro-bind-try /etc/manpath.config /etc/manpath.config \
+	--bind-try /run/mysqld/mysqld.sock /run/mysqld/mysqld.sock \
+	--chdir ${HOME} \
+	--unshare-all \
+	--share-net \
+	--die-with-parent \
+	--dir /run/user/$(id -u) \
+	--setenv XDG_RUNTIME_DIR "/run/user/$(id -u)" \
+	--setenv PS1 "$(id -nu)$ " \
+	--file 11 /etc/passwd \
+	--file 12 /etc/group \
+	/bin/bash -l "$@") \
+	11< <(getent passwd $UID 65534) \
+	12< <(getent group $(id -g) 65534)

+ 1 - 1
install/hst-install-debian.sh

@@ -52,7 +52,7 @@ software="acl apache2 apache2-suexec-custom apache2-suexec-pristine apache2-util
   php$fpm_v php$fpm_v-apcu php$fpm_v-bz2 php$fpm_v-cgi php$fpm_v-cli php$fpm_v-common php$fpm_v-curl php$fpm_v-gd
   php$fpm_v-imagick php$fpm_v-imap php$fpm_v-intl php$fpm_v-ldap php$fpm_v-mbstring php$fpm_v-mysql php$fpm_v-opcache
   php$fpm_v-pgsql php$fpm_v-pspell php$fpm_v-readline php$fpm_v-xml php$fpm_v-zip postgresql postgresql-contrib
-  proftpd-basic quota rrdtool rsyslog spamd sysstat unrar-free unzip util-linux vim-common vsftpd xxd whois zip zstd jailkit restic"
+  proftpd-basic quota rrdtool rsyslog spamd sysstat unrar-free unzip util-linux vim-common vsftpd xxd whois zip zstd jailkit bubblewrap restic"
 
 installer_dependencies="apt-transport-https ca-certificates curl dirmngr gnupg openssl wget sudo"
 

+ 1 - 1
install/hst-install-ubuntu.sh

@@ -53,7 +53,7 @@ software="acl apache2 apache2.2-common apache2-suexec-custom apache2-utils appar
   php$fpm_v-imagick php$fpm_v-imap php$fpm_v-intl php$fpm_v-ldap php$fpm_v-mbstring php$fpm_v-mysql php$fpm_v-opcache
   php$fpm_v-pgsql php$fpm_v-pspell php$fpm_v-readline php$fpm_v-xml php$fpm_v-zip postgresql postgresql-contrib
   proftpd-basic quota rrdtool rsyslog util-linux spamassassin
-  sysstat unzip vim-common vsftpd whois zip zstd jailkit restic"
+  sysstat unzip vim-common vsftpd whois zip zstd jailkit bubblewrap restic"
 
 installer_dependencies="apt-transport-https ca-certificates curl dirmngr gnupg openssl software-properties-common wget sudo"
 

+ 1 - 1
src/deb/hestia/control

@@ -6,7 +6,7 @@ Section: admin
 Maintainer: HestiaCP <info@hestiacp.com>
 Homepage: https://www.hestiacp.com
 Architecture: amd64
-Depends: bash, awk, sed, acl, sysstat, setpriv | util-linux (>= 2.33), zstd, lsb-release, idn2, jq, jailkit
+Depends: bash, awk, sed, acl, sysstat, setpriv | util-linux (>= 2.33), zstd, lsb-release, idn2, jq, jailkit, bubblewrap
 Description: hestia
  hestia is an open source hosting control panel.
  hestia has a clean and focused interface without the clutter.

+ 1 - 1
src/rpm/hestia/hestia.spec

@@ -12,7 +12,7 @@ Source0:        hestia-%{version}.tar.gz
 Source1:        hestia.service
 Vendor:         hestiacp.com
 Requires:       redhat-release >= 8
-Requires:       bash, chkconfig, gawk, sed, acl, sysstat, (setpriv or util-linux), zstd, jq, jailkit
+Requires:       bash, chkconfig, gawk, sed, acl, sysstat, (setpriv or util-linux), zstd, jq, jailkit, bubblewrap
 Conflicts:      vesta
 Provides:       hestia = %{version}
 BuildRequires:  systemd

+ 11 - 0
test/test.bats

@@ -449,6 +449,17 @@ function check_ip_not_banned(){
 		assert_file_exist /etc/systemd/system/$mount_file
 }
 
+@test "User: Change user bash with bubblewrap jail" {
+    run v-change-user-shell $user jailbash no
+    assert_success
+    refute_output
+
+    run stat -c '%U' /home/$user
+    assert_output --partial "$user"
+		mount_file=$(systemd-escape -p --suffix=mount "/srv/jail/$user/home")
+		assert_file_not_exist /etc/systemd/system/$mount_file
+}
+
 @test "User: Change user default ns" {
     run v-change-user-ns $user ns0.com ns1.com ns2.com ns3.com
     assert_success