Skip to content

Commit

Permalink
WIP: Implement rootless execution
Browse files Browse the repository at this point in the history
  • Loading branch information
progandy committed Apr 25, 2020
1 parent 3e318e6 commit 9cb93f7
Showing 1 changed file with 90 additions and 18 deletions.
108 changes: 90 additions & 18 deletions repro.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,44 @@ orig_argv=("$0" "$@")
src_owner=${SUDO_USER:-$USER}
function check_root() {
(( EUID == 0 )) && return
if type -P sudo >/dev/null; then
if ((rootless_userns)); then
exec become-root unshare --mount "${orig_argv[@]}"
elif type -P sudo >/dev/null; then
exec sudo -- "${orig_argv[@]}"
else
exec su root -c "$(printf ' %q' "${orig_argv[@]}")"
fi
}

function require_userns_tools() {
if command -v become-root >/dev/null \
&& command -v nsjail >/dev/null \
&& command -v fuse-overlayfs >/dev/null
then
return 0
fi
warning "nsjail, fuse-overlayfs and become-root are necessary for rootless operation"
warning "https://github.com/giuseppe/become-root"
warning "https://github.com/containers/fuse-overlayfs"
warning "https://github.com/google/nsjail"
return 1
}

function mountoverlay() {
if ((rootless_userns)); then
fuse-overlayfs "$@"
else
mount -t overlayfs overlayfs "$@"
fi
}
function umountoverlay() {
if ((rootless_userns)); then
fusermount -u "$@"
else
umount "$@"
fi
}

# Use a private gpg keyring
function gpg() {
command gpg --homedir="$BUILDDIRECTORY/gnupg" "$@"
Expand Down Expand Up @@ -103,6 +134,42 @@ function exec_nspawn(){
-D "$BUILDDIRECTORY/$container" "${@:2}"
}


# Desc: Executes an command inside a given nsjail container
# 1: Container name
# 2: Optional: one --bind=... bindmount option
# 2/3: Command to execute
function exec_nsjail(){
local container=$1
local args=( -Mo --quiet
--disable_clone_newuser
--disable_clone_newnet
--disable_rlimits
--keep_caps
--tmpfsmount /tmp
--bindmount_ro /dev
-E "PATH=/usr/local/sbin:/usr/local/bin:/usr/bin"
--chroot "$BUILDDIRECTORY/$container" --rw
)
## use a no-op forking unshare as pid1
if [[ $2 == --bind=* ]] ; then
nsjail "${args[@]}" --bindmount "${2#--bind=}" -- /usr/bin/unshare -f "${@:3}"
else
nsjail "${args[@]}" -- /usr/bin/unshare -f "${@:2}"
fi
}

function exec_container(){
if ((rootless_userns)); then
exec_nsjail "$@"
else
exec_nspawn "$@"
fi
}




# Desc: Removes the root container
function cleanup_root_volume(){
warning "Removing root container..."
Expand All @@ -114,7 +181,7 @@ function cleanup_root_volume(){
function remove_snapshot (){
local build=$1
msg2 "Delete snapshot for $build..."
umount "$BUILDDIRECTORY/$build" || true
umountoverlay "$BUILDDIRECTORY/$build" || true
rm -rf "${BUILDDIRECTORY:?}/${build}"
rm -rf "${BUILDDIRECTORY:?}/${build}_upperdir"
rm -rf "${BUILDDIRECTORY:?}/${build}_workdir"
Expand All @@ -131,7 +198,7 @@ function create_snapshot (){
msg2 "Create snapshot for $build..."
mkdir -p "$BUILDDIRECTORY/"{"${build}","${build}_upperdir","${build}_workdir"}
# shellcheck disable=SC2140
mount -t overlay overlay \
mountoverlay \
-o lowerdir="$BUILDDIRECTORY/root",upperdir="$BUILDDIRECTORY/${build}_upperdir",workdir="$BUILDDIRECTORY/${build}_workdir" \
"$BUILDDIRECTORY/${build}"
touch "$BUILDDIRECTORY/$build"
Expand All @@ -143,7 +210,7 @@ function create_snapshot (){
function build_package(){
local build=$1
local builddir=${2:-"/startdir"}
exec_nspawn "$build" \
exec_container "$build" \
--bind="$PWD:/srcdest" \
bash <<-__END__
set -e
Expand Down Expand Up @@ -180,23 +247,23 @@ function init_chroot(){
printf '%s.UTF-8 UTF-8\n' en_US de_DE > "$BUILDDIRECTORY"/root/etc/locale.gen
printf 'LANG=en_US.UTF-8\n' > "$BUILDDIRECTORY"/root/etc/locale.conf

systemd-machine-id-setup --root="$BUILDDIRECTORY"/root
exec_container root systemd-machine-id-setup
msg2 "Setting up keyring, this might take a while..."
exec_nspawn root pacman-key --init &> /dev/null
exec_nspawn root pacman-key --populate archlinux &> /dev/null
exec_container root pacman-key --init &> /dev/null
exec_container root pacman-key --populate archlinux &> /dev/null

msg2 "Updating and installing base & base-devel"
exec_nspawn root pacman -Syu base-devel --noconfirm
exec_nspawn root pacman -R arch-install-scripts --noconfirm
exec_nspawn root locale-gen
exec_container root pacman -Syu base-devel --noconfirm
exec_container root pacman -R arch-install-scripts --noconfirm
exec_container root locale-gen

printf 'builduser ALL = NOPASSWD: /usr/bin/pacman\n' > "$BUILDDIRECTORY"/root/etc/sudoers.d/builduser-pacman
exec_nspawn root useradd -m -G wheel -s /bin/bash -d /build builduser
exec_container root useradd -m -G wheel -s /bin/bash -d /build builduser
echo "keyserver-options auto-key-retrieve" | install -Dm644 /dev/stdin "$BUILDDIRECTORY/root"/build/.gnupg/gpg.conf
exec_nspawn root chown -R builduser /build/.gnupg
exec_container root chown -R builduser /build/.gnupg
else
printf 'Server = %s\n' "$HOSTMIRROR" > "$BUILDDIRECTORY"/root/etc/pacman.d/mirrorlist
exec_nspawn root pacman -Syu --noconfirm
exec_container root pacman -Syu --noconfirm
fi

trap - ERR INT
Expand Down Expand Up @@ -247,7 +314,7 @@ function cmd_check(){
} >> "$BUILDDIRECTORY/$build/etc/makepkg.conf"

# Father I have sinned
exec_nspawn "build" \
exec_container "build" \
bash <<-__END__
shopt -s globstar
install -d -o builduser -g builduser /startdir
Expand All @@ -273,16 +340,16 @@ __END__
msg2 "Finished preparing packages"
msg "Installing packages"
# shellcheck disable=SC2086
exec_nspawn build --bind="$(readlink -e ${cachedir}):/cache" bash -c \
exec_container build --bind="$(readlink -e ${cachedir}):/cache" bash -c \
'yes y | pacman -Udd --overwrite "*" -- "$@"' -bash "${packages[@]}"

read -r -a buildinfo_packages <<< "$(buildinfo -f installed "${pkg}")"
uninstall=$(comm -13 \
<(printf '%s\n' "${buildinfo_packages[@]}" | rev | cut -d- -f4- | rev | sort) \
<(exec_nspawn build --bind="$(readlink -e ${cachedir}):/cache" pacman -Qq | sort))
<(exec_container build --bind="$(readlink -e ${cachedir}):/cache" pacman -Qq | sort))

if [ -n "$uninstall" ]; then
exec_nspawn build pacman -Rdd --noconfirm -- $uninstall
exec_container build pacman -Rdd --noconfirm -- $uninstall
fi

build_package "build" "$builddir"
Expand Down Expand Up @@ -346,10 +413,15 @@ elif [[ -r "$HOME/.repro.conf" ]]; then
fi


while getopts :hdoC:P:M: arg; do
while getopts :hdorC:P:M: arg; do
case $arg in
h) print_help; exit 0;;
d) run_diffoscope=1;;
r) rootless_userns=1;
require_userns_tools || exit 1
# TODO: better detection for valid writable build directory
[[ $BUILDDIRECTORY == /var/lib/repro ]] && BUILDDIRECTORY="${XDG_CACHE_HOME:-$HOME/.cache}/archlinux-repro"
;;
*) ;;
esac
done
Expand Down

0 comments on commit 9cb93f7

Please sign in to comment.