From b18849caac521a6b71f6836eea7cd5311dc2a721 Mon Sep 17 00:00:00 2001 From: Johannes Schauer Marin Rodrigues Date: Fri, 10 Feb 2023 13:01:37 +0100 Subject: [PATCH] Assume that we can always run unshare With mount --rbind we can bind-mount /proc in a privileged docker container as it is used by salsaci. --- coverage.py | 7 +------ coverage.sh | 5 +---- coverage.txt | 5 +++-- tests/as-debootstrap-unshare-wrapper | 27 ++++++++++++++++++++++++++- tests/dev-ptmx | 3 ++- tests/dist-using-codename | 8 +++++--- tests/pivot_root | 27 +++++++++++++-------------- tests/unshare-include-deb | 3 +-- 8 files changed, 52 insertions(+), 33 deletions(-) diff --git a/coverage.py b/coverage.py index 1a8126a..3202004 100755 --- a/coverage.py +++ b/coverage.py @@ -13,14 +13,13 @@ from collections import defaultdict from itertools import product have_qemu = os.getenv("HAVE_QEMU", "yes") == "yes" -have_unshare = os.getenv("HAVE_UNSHARE", "yes") == "yes" have_binfmt = os.getenv("HAVE_BINFMT", "yes") == "yes" run_ma_same_tests = os.getenv("RUN_MA_SAME_TESTS", "yes") == "yes" cmd = os.getenv("CMD", "./mmdebstrap") default_dist = os.getenv("DEFAULT_DIST", "unstable") all_dists = ["oldstable", "stable", "testing", "unstable"] -default_mode = "auto" if have_unshare else "root" +default_mode = "auto" all_modes = ["auto", "root", "unshare", "fakechroot", "chrootless"] default_variant = "apt" all_variants = [ @@ -271,12 +270,8 @@ def main(): tt = "qemu" elif test.get("Needs-QEMU", "false") == "true": tt = ("skip", "test needs QEMU") - elif mode == "unshare" and not have_unshare: - tt = ("skip", "test needs unshare") elif test.get("Needs-Root", "false") == "true": tt = "sudo" - elif mode == "auto" and not have_unshare: - tt = "sudo" elif mode == "root": tt = "sudo" else: diff --git a/coverage.sh b/coverage.sh index 2d11ffa..2a0f6f7 100755 --- a/coverage.sh +++ b/coverage.sh @@ -73,7 +73,6 @@ SOURCE_DATE_EPOCH=$(date --date="$(grep-dctrl -s Date -n '' "$mirrordir/dists/$D # for traditional sort order that uses native byte values export LC_ALL=C.UTF-8 -: "${HAVE_UNSHARE:=yes}" : "${HAVE_BINFMT:=yes}" # by default, use the mmdebstrap executable in the current directory together @@ -81,7 +80,7 @@ export LC_ALL=C.UTF-8 : "${CMD:=perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap}" mirror="http://127.0.0.1/debian" -export HAVE_QEMU HAVE_UNSHARE HAVE_BINFMT RUN_MA_SAME_TESTS DEFAULT_DIST SOURCE_DATE_EPOCH CMD mirror +export HAVE_QEMU HAVE_BINFMT RUN_MA_SAME_TESTS DEFAULT_DIST SOURCE_DATE_EPOCH CMD mirror ./coverage.py @@ -99,8 +98,6 @@ cover -delete cover_db >&2 END if [ "$HAVE_QEMU" = "yes" ]; then ./run_qemu.sh - elif [ "$HAVE_UNSHARE" != "yes" ]; then - ./run_null.sh SUDO else ./run_null.sh fi diff --git a/coverage.txt b/coverage.txt index 6efbb9d..a064daa 100644 --- a/coverage.txt +++ b/coverage.txt @@ -5,6 +5,7 @@ Needs-Root: true Test: as-debootstrap-unshare-wrapper Modes: unshare +Needs-Root: true Test: help @@ -277,13 +278,14 @@ Skip-If: variant == "important" and dist == "oldstable" # /var/lib/systemd/catalog/database differs Test: create-directory-dry-run +Modes: root Test: create-tarball-dry-run Variants: any Modes: any Test: unpack-doc-debian -Modes: any +Modes: root fakechroot Variants: extract Test: install-doc-debian @@ -354,7 +356,6 @@ Modes: unshare Test: pivot_root Modes: root unshare -Skip-If: not have_unshare Test: jessie-or-older Needs-Root: true diff --git a/tests/as-debootstrap-unshare-wrapper b/tests/as-debootstrap-unshare-wrapper index e46d682..1eec03d 100644 --- a/tests/as-debootstrap-unshare-wrapper +++ b/tests/as-debootstrap-unshare-wrapper @@ -15,7 +15,32 @@ if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto prefix="runuser -u ${SUDO_USER:-user} --" fi -$prefix {{ CMD }} --variant=custom --mode={{ MODE }} --setup-hook='env container=lxc debootstrap unstable "$1" {{ MIRROR }}' - /tmp/debian-mm.tar {{ MIRROR }} +# debootstrap uses apt-config to figure out whether the system running it has +# any proxies configured and then runs the binary to set the http_proxy +# environment variable. This will fail if debootstrap is run in a linux user +# namespace because auto-apt-proxy will see /tmp/.auto-apt-proxy-0 as being +# owned by the user "nobody" and group "nogroup" and fail with: +# insecure cache dir /tmp/.auto-apt-proxy-0. Must be owned by UID 0 and have permissions 700 +# We cannot overwrite a configuration item using the APT_CONFIG environment +# variable, so instead we use it to set the Dir configuration option +# to /dev/null to force all apt settings to their defaults. +# There is currently no better way to disable this behavior. See also: +# https://bugs.debian.org/1031105 +# https://salsa.debian.org/installer-team/debootstrap/-/merge_requests/90 +AUTOPROXY= +eval "$(apt-config shell AUTOPROXY Acquire::http::Proxy-Auto-Detect)" +if [ -n "$AUTOPROXY" ] && [ -x "$AUTOPROXY" ] && [ -e /tmp/.auto-apt-proxy-0 ]; then + TMP_APT_CONFIG=$(mktemp) + echo "Dir \"/dev/null\";" > "$TMP_APT_CONFIG" + chmod 644 "$TMP_APT_CONFIG" +fi + +$prefix {{ CMD }} --variant=custom --mode={{ MODE }} \ + --setup-hook='env '"${AUTOPROXY:+APT_CONFIG='$TMP_APT_CONFIG'}"' container=lxc debootstrap unstable "$1" {{ MIRROR }}' \ + - /tmp/debian-mm.tar {{ MIRROR }} +if [ -n "$AUTOPROXY" ] && [ -x "$AUTOPROXY" ] && [ -e /tmp/.auto-apt-proxy-0 ]; then + rm "$TMP_APT_CONFIG" +fi mkdir /tmp/debian-mm tar --xattrs --xattrs-include='*' -C /tmp/debian-mm -xf /tmp/debian-mm.tar diff --git a/tests/dev-ptmx b/tests/dev-ptmx index a17655b..5eb7bd0 100644 --- a/tests/dev-ptmx +++ b/tests/dev-ptmx @@ -125,12 +125,13 @@ script -qfec "$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \ --customize-hook='chroot \"\$1\" runuser -u user -- python3 -c \"import pty; print(pty.openpty())\"' \ --customize-hook='chroot \"\$1\" script -c \"echo foobar\"' \ --customize-hook='chroot \"\$1\" runuser -u user -- env --chdir=/home/user script -c \"echo foobar\"' \ - --customize-hook='chroot \"\$1\" apt-get install --yes doc-debian 2>&1 | tee /tmp/log' \ + --customize-hook='chroot \"\$1\" apt-get install --yes doc-debian 2>&1 | tee \"\$1\"/tmp/log' \ --customize-hook=\"copy-in /tmp/test.c /tmp\" \ --customize-hook='chroot \"\$1\" gcc /tmp/test.c -o /tmp/test' \ --customize-hook='chroot \"\$1\" /tmp/test' \ --customize-hook='chroot \"\$1\" runuser -u user -- /tmp/test' \ --customize-hook='rm \"\$1\"/tmp/test \"\$1\"/tmp/test.c' \ + --customize-hook=\"copy-out /tmp/log /tmp\" \ {{ DIST }} /dev/null {{ MIRROR }}" /dev/null fail=0 diff --git a/tests/dist-using-codename b/tests/dist-using-codename index eb8079f..2cf7d89 100644 --- a/tests/dist-using-codename +++ b/tests/dist-using-codename @@ -4,8 +4,10 @@ set -eu export LC_ALL=C.UTF-8 -trap "rm -f Release; rm -rf /tmp/debian-chroot" EXIT INT TERM +trap "rm -f Release; rm -rf /tmp/debian-chroot.tar /tmp/expected" EXIT INT TERM /usr/lib/apt/apt-helper download-file "{{ MIRROR }}/dists/{{ DIST }}/Release" Release codename=$(awk '/^Codename: / { print $2; }' Release) -{{ CMD }} --mode={{ MODE }} --variant=apt "$codename" /tmp/debian-chroot {{ MIRROR }} -echo "deb {{ MIRROR }} $codename main" | diff -u - /tmp/debian-chroot/etc/apt/sources.list +{{ CMD }} --mode={{ MODE }} --variant=apt "$codename" /tmp/debian-chroot.tar {{ MIRROR }} +echo "deb {{ MIRROR }} $codename main" > /tmp/expected +tar --to-stdout --extract --file /tmp/debian-chroot.tar ./etc/apt/sources.list \ + | diff -u /tmp/expected - diff --git a/tests/pivot_root b/tests/pivot_root index a708924..860c41b 100644 --- a/tests/pivot_root +++ b/tests/pivot_root @@ -16,10 +16,6 @@ if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto prefix="runuser -u ${SUDO_USER:-user} --" fi -MMDEBSTRAP= -[ -e /usr/bin/mmdebstrap ] && MMDEBSTRAP=/usr/bin/mmdebstrap -[ -e ./mmdebstrap ] && MMDEBSTRAP=./mmdebstrap - $prefix {{ CMD }} --mode={{ MODE }} --variant=apt \ --include=mount \ {{ DIST }} /tmp/chroot1.tar {{ MIRROR }} @@ -28,14 +24,16 @@ if [ {{ MODE }} = "unshare" ]; then # calling pivot_root in root mode does not work for mysterious reasons: # pivot_root: failed to change root from `.' to `mnt': Invalid argument $prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include=mount \ - --customize-hook="upload $MMDEBSTRAP /$MMDEBSTRAP" \ - --customize-hook='chmod +x "$1"/'"$MMDEBSTRAP" \ - --customize-hook='mount -o rbind "$1" /mnt && cd /mnt && /sbin/pivot_root . mnt' \ + --customize-hook='mkdir -p "$1/mnt" "$1/oldroot"' \ + --customize-hook='[ ! -e /usr/bin/mmdebstrap ] || cp -aT /usr/bin/mmdebstrap "$1/usr/bin/mmdebstrap"' \ + --customize-hook='[ ! -e ./mmdebstrap ] || cp -aT ./mmdebstrap "$1/mnt/mmdebstrap"' \ + --customize-hook='mount -o rbind "$1" /mnt && cd /mnt && /sbin/pivot_root . oldroot' \ --customize-hook='unshare -U echo nested unprivileged unshare' \ - --customize-hook="/$MMDEBSTRAP"' --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \ + --customize-hook='env --chdir=/mnt {{ CMD }} --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \ --customize-hook='copy-out /tmp/chroot3.tar /tmp' \ - --customize-hook='rm "$1/'"$MMDEBSTRAP"'"' \ - --customize-hook='umount -l mnt sys' \ + --customize-hook='rm -f "/usr/bin/mmdebstrap" "/mnt/mmdebstrap"' \ + --customize-hook='umount -l oldroot sys' \ + --customize-hook='rmdir /oldroot' \ {{ DIST }} /tmp/chroot2.tar {{ MIRROR }} cmp /tmp/chroot1.tar /tmp/chroot2.tar || diffoscope /tmp/chroot1.tar /tmp/chroot2.tar @@ -44,11 +42,12 @@ if [ {{ MODE }} = "unshare" ]; then fi $prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include=mount \ - --customize-hook="upload $MMDEBSTRAP /$MMDEBSTRAP" \ - --customize-hook='chmod +x "$1"/'"$MMDEBSTRAP" \ - --chrooted-customize-hook="/$MMDEBSTRAP"' --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \ + --customize-hook='mkdir -p "$1/mnt"' \ + --customize-hook='[ ! -e /usr/bin/mmdebstrap ] || cp -aT /usr/bin/mmdebstrap "$1/usr/bin/mmdebstrap"' \ + --customize-hook='[ ! -e ./mmdebstrap ] || cp -aT ./mmdebstrap "$1/mnt/mmdebstrap"' \ + --chrooted-customize-hook='env --chdir=/mnt {{ CMD }} --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \ --customize-hook='copy-out /tmp/chroot3.tar /tmp' \ - --customize-hook='rm "$1/'"$MMDEBSTRAP"'"' \ + --customize-hook='rm -f "$1/usr/bin/mmdebstrap" "$1/mnt/mmdebstrap"' \ {{ DIST }} /tmp/chroot2.tar {{ MIRROR }} cmp /tmp/chroot1.tar /tmp/chroot2.tar || diffoscope /tmp/chroot1.tar /tmp/chroot2.tar diff --git a/tests/unshare-include-deb b/tests/unshare-include-deb index 06373bf..e421d39 100644 --- a/tests/unshare-include-deb +++ b/tests/unshare-include-deb @@ -34,9 +34,8 @@ Description: dummypkg END dpkg-deb --build "/tmp/dummypkg" "/tmp/dummypkg.deb" -# make the .deb only redable by user which will exclude the unshared user +# make the .deb only redable by its owner which will exclude the unshared user chmod 600 /tmp/dummypkg.deb -chown user /tmp/dummypkg.deb ret=0 $prefix {{ CMD }} --variant=apt --mode={{ MODE }} --include="/tmp/dummypkg.deb" \