-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sandboxing hardening suggestions (/mnt
, /media
, PKGBUILD directory)
#206
Comments
Grrr, for (1), I tried making the directory containing the PKGBUILD read-only, but it broke a few things:
A good option would be to mount a writable overlay over the directory containing the PKGBUILD, but unfortunately this is not yet available in bubblewrap (link, link). |
FWIW I ended up with the following standalone script ("makepkg replacement") for my builds. It have successfully tested it with ~30 packages. It depends on the not-yet-merged PR for bubblewrap mounts I linked above. #!/usr/bin/env sh
set -eu
# A makepkg wrapper which runs the build process inside a sandbox
# The goals of this wrapper are:
# 1- Improve security by sandboxing the build process
# 2- Cleaner and more predictable builds but without needing a chroot
# 3- Avoiding dirty builds leaving files on home dirs, etc. to be cleaned up
# A major inspiration is RUA's bwrap sandbox:
# https://github.com/vn971/rua/blob/c7bded62535105f9214290900a7267d7339d2f45/res/wrapper/security-wrapper.sh
# Compared to RUA's sandbox:
# - For simplifity we don't use seccomp rules
# (I don't think they are *theoretically* required to get unescapable sandboxing)
# - We explicitly list directories on the root to avoid mounting /media, /mnt, etc.
# - We don't mount the directory containing the PKGBUILD as a (persistent) overlayfs to make
# social engineering attacks like "self-modifying" PKGBUILDs, Git hooks, etc. more difficult
# Set makepkg destination directories to directories inside a sandbox which we will bind-mount
# We do this (instead of just the overlay below) so that built packages can be easily read from outside the sandbox
[ -z "${PKGDEST+x}" ] && mkdir -p sandbox/pkg && PKGDEST="$PWD/sandbox/pkg"
[ -z "${SRCDEST+x}" ] && mkdir -p sandbox/src && SRCDEST="$PWD/sandbox/src"
[ -z "${SRCPKGDEST+x}" ] && mkdir -p sandbox/srcpkg && SRCPKGDEST="$PWD/sandbox/srcpkg"
[ -z "${LOGDEST+x}" ] && mkdir -p sandbox/log && LOGDEST="$PWD/sandbox/log"
[ -z "${BUILDDIR+x}" ] && mkdir -p sandbox/build && BUILDDIR="$PWD/sandbox/build"
# Even with the previous setup, we still need a writable overlayFS for the root directory, as makepkg
# needs it sometimes (e.g. to update pkgver for Git packages, to update pre-downloaded source repositories, etc.)
mkdir -p sandbox/ovfs_rw sandbox/ovfs_work
# Clean up empty sandbox directories on exit (so commands like --printsrcinfo don't leave a mess behind)
trap 'trap - INT TERM EXIT; [ -z "$(unshare -Ur find sandbox -not -type d | head -n 1)" ] && rm -rf sandbox' INT TERM EXIT
RESOLV_CONF="$(realpath /etc/resolv.conf)"
bwrap \
--die-with-parent \
--new-session \
--unshare-all \
--share-net \
`# Common rootfs mounts` \
--ro-bind /usr /usr \
--ro-bind /opt /opt \
--ro-bind /etc /etc \
--ro-bind /boot /boot \
--ro-bind /var /var \
--perms 000 --dir /root \
--dir /mnt \
--dir /media \
--dir /srv \
--symlink usr/bin /bin \
--symlink usr/bin /sbin \
--symlink usr/lib /lib \
--symlink usr/lib /lib64 \
--dev /dev \
--proc /proc \
--ro-bind /sys /sys \
--tmpfs /tmp \
--tmpfs /run \
--tmpfs /var/run \
--tmpfs /var/tmp \
--perms 0700 --tmpfs "$XDG_RUNTIME_DIR" \
--tmpfs "$HOME" \
`# Deal with systemd-resolved symlinked /etc/resolv.conf` \
--ro-bind "$RESOLV_CONF" "$RESOLV_CONF" \
`# Bind GnuPG keyring to check PKGBUILD validpgpkeys` \
--ro-bind-try "${GNUPGHOME:-$HOME/.gnupg}/pubring.kbx" "${GNUPGHOME:-$HOME/.gnupg}/pubring.kbx" \
--ro-bind-try "${GNUPGHOME:-$HOME/.gnupg}/pubring.gpg" "${GNUPGHOME:-$HOME/.gnupg}/pubring.gpg" \
`# CUSTOMPKGDIR can be optionally used to mount a common script / library` \
--ro-bind-try "${CUSTOMPKGDIR:-/does/not/exist}" "${CUSTOMPKGDIR:-/does/not/exist}" \
`# Clean up most environment variables, otherwise some tests may try to e.g. start GUI applications and fail` \
`# Should also help with making builds more predictable` \
--clearenv \
--setenv XDG_RUNTIME_DIR "$XDG_RUNTIME_DIR" \
--setenv PATH "$PATH" \
--setenv USER "$USER" \
--setenv LOGNAME "$LOGNAME" \
--setenv TERM "$TERM" \
--setenv HOME "$HOME" \
--setenv GNUPGHOME "${GNUPGHOME:-$HOME/.gnupg}" \
--setenv LANG "$LANG" \
`# Setup sandboxed build environment` \
--overlay-src "$PWD" --overlay "$PWD"/sandbox/ovfs_rw "$PWD"/sandbox/ovfs_work "$PWD" \
--bind "$PKGDEST" "$PKGDEST" --setenv PKGDEST "$PKGDEST" \
--bind "$SRCDEST" "$SRCDEST" --setenv SRCDEST "$SRCDEST" \
--bind "$SRCPKGDEST" "$SRCPKGDEST" --setenv SRCPKGDEST "$SRCPKGDEST" \
--bind "$LOGDEST" "$LOGDEST" --setenv LOGDEST "$LOGDEST" \
--bind "$BUILDDIR" "$BUILDDIR" --setenv BUILDDIR "$BUILDDIR" \
`# FAKEROOTDONTTRYCHOWN is needed to build some packages like linux-mainline due to an interaction` \
`# between bubblewrap and chroot, see: https://github.com/containers/bubblewrap/issues/395` \
`# More detailed explanation: https://patchwork.ozlabs.org/project/buildroot/patch/[email protected]/` \
`# RUA builddir also does it: https://github.com/vn971/rua/commit/a7a1e2ed2da1b2fdb7ea33666f08faa8422dd681` \
--setenv FAKEROOTDONTTRYCHOWN 1 \
"${ZEALCHARM_MAKEPKG_ENTRYPOINT:-makepkg}" "$@" If I can find some time I'll make a PR for something along this line. |
Description
I was taking a look into how RUA build sandbox works, and I noticed the following:
The directory containing the
PKGBUILD
is mounted as bound as a writeable directory..This opens the door to the build process modifying things inside the
PKGBUILD
directory to set up a "hook" that hopefully the user accidentally runs later outside the RUA sandbox.For example, the build process could modify the
PKGBUILD
so that runningmakepkg --printsrcinfo
after the build runs code outside the sandbox.Or it could be more sneaky and inject itself to Git's fsmonitor so that the code is executed when running
git status
(and no changed source files are reported).Technically speaking, this doesn't break the RUA sandbox itself, but I think most users expect that e.g. running
rua builddir
thengit status
can't result in unsandboxed code execution.The entire root directory is bind-mounted, including paths such as
/media
and/mnt
.This means that if the user running the build has access to some personal/sensitive data inside those directories (which probably isn't ideal, but also not entirely unexpected), and the build is not done offline (which may not be practical in some cases), this data can be ex-filtrated to some external server during the build.
In both cases, the code could be hidden deep in the build, e.g. inside some downloaded NPM/Go/Rust/etc. package, so examining the PKGBUILD and related files doesn't reveal anything wrong.
Impact
Likely pretty low in practice since packages are often going to be immediately installed in the same machine and run unsandboxed, but it could increase risk for things like build/CI machines or software that itself runs inside a sandbox.
Possible fixes
Mount the PKGBUILD directory read-only, and create a writeable directory for
PKGDEST
/SRCDEST
/SRCPKGDEST
/LOGDEST
/BUILDDIR
instead.Be more selective, don't mount all of
/
but only presumed-safe directories like/usr
,/opt
,/etc
, etc.Sample
The text was updated successfully, but these errors were encountered: