185 lines
9.0 KiB
Bash
185 lines
9.0 KiB
Bash
#!/usr/bin/env bats
|
|
|
|
load helpers
|
|
|
|
@test "chroot mount flags" {
|
|
skip_if_no_unshare
|
|
if ! test -e /etc/subuid ; then
|
|
skip "we can't bind mount over /etc/subuid during the test if there is no /etc/subuid file"
|
|
fi
|
|
if ! test -e /etc/subgid ; then
|
|
skip "we can't bind mount over /etc/subgid during the test if there is no /etc/subgid file"
|
|
fi
|
|
# whom should we map to root in a nested namespace?
|
|
if is_rootless ; then
|
|
subid=128
|
|
rangesize=1024
|
|
else
|
|
subid=1048576
|
|
rangesize=16384
|
|
fi
|
|
# we're going to have to prefetch into storage used by someone else image
|
|
# chosen because its rootfs doesn't have any uid/gid ownership above
|
|
# $rangesize, because the nested namespace needs to be able to represent all
|
|
# of them
|
|
baseimage=registry.access.redhat.com/ubi9-micro:latest
|
|
_prefetch $baseimage
|
|
baseimagef=$(tr -c a-zA-Z0-9.- - <<< "$baseimage")
|
|
# create the directories that we need
|
|
tmpfs=${TEST_SCRATCH_DIR}/tmpfs
|
|
mkdir $tmpfs
|
|
context=${TEST_SCRATCH_DIR}/context
|
|
mkdir $context
|
|
storagedir=${TEST_SCRATCH_DIR}/storage
|
|
mkdir $storagedir
|
|
rootdir=${storagedir}/rootdir
|
|
mkdir $rootdir
|
|
runrootdir=${storagedir}/runrootdir
|
|
mkdir $runrootdir
|
|
xdgruntimedir=${storagedir}/xdgruntime
|
|
mkdir $xdgruntimedir
|
|
xdgconfighome=${storagedir}/xdgconfighome
|
|
mkdir $xdgconfighome
|
|
xdgdatahome=${storagedir}/xdgdatahome
|
|
mkdir $xdgdatahome
|
|
storageopts="--storage-driver vfs --root $rootdir --runroot $runrootdir"
|
|
# our temporary parent directory might not be world-searchable, which will
|
|
# cause someone in the nested user namespace to hit permissions issues even
|
|
# looking for $storagedir, so tweak perms to let them do at least that much
|
|
fixupdir=$storagedir
|
|
while test $(stat -c %d:%i $fixupdir) != $(stat -c %d:%i /) ; do
|
|
# walk up to root, or the first parent that we don't own
|
|
if test $(stat -c %u $fixupdir) -ne $(id -u) ; then
|
|
break
|
|
fi
|
|
chmod +x $fixupdir
|
|
fixupdir=$fixupdir/..
|
|
done
|
|
# start writing the script to run in the nested user namespace
|
|
cp -v ${TEST_SOURCES}/containers.conf ${TEST_SCRATCH_DIR}/containers.conf
|
|
chmod ugo+r ${TEST_SCRATCH_DIR}/containers.conf
|
|
echo set -e > ${TEST_SCRATCH_DIR}/script.sh
|
|
echo export XDG_RUNTIME_DIR=$xdgruntimedir >> ${TEST_SCRATCH_DIR}/script.sh
|
|
echo export XDG_CONFIG_HOME=$xdgconfighome >> ${TEST_SCRATCH_DIR}/script.sh
|
|
echo export XDG_DATA_HOME=$xdgdatahome >> ${TEST_SCRATCH_DIR}/script.sh
|
|
echo export CONTAINERS_CONF=${TEST_SCRATCH_DIR}/containers.conf >> ${TEST_SCRATCH_DIR}/script.sh
|
|
# give our would-be user ownership of that directory
|
|
echo chown --recursive ${subid}:${subid} ${storagedir} >> ${TEST_SCRATCH_DIR}/script.sh
|
|
# make newuidmap/newgidmap, invoked by unshare even for uid=0, happy
|
|
echo root:0:4294967295 > ${TEST_SCRATCH_DIR}/subid
|
|
echo mount --bind -r ${TEST_SCRATCH_DIR}/subid /etc/subuid >> ${TEST_SCRATCH_DIR}/script.sh
|
|
echo mount --bind -r ${TEST_SCRATCH_DIR}/subid /etc/subgid >> ${TEST_SCRATCH_DIR}/script.sh
|
|
# don't get tripped up by ${TEST_SCRATCH_DIR} potentially being on a filesystem with non-default mount flags
|
|
echo mount -t tmpfs -o size=256K tmpfs $tmpfs >> ${TEST_SCRATCH_DIR}/script.sh
|
|
# mount a small tmpfs with every mount flag combination that concerns us, and
|
|
# be ready to tell buildah to mount everything conservatively, to mirror the
|
|
# TransientMounts API being used to nodev/noexec/nosuid/ro bind in a source
|
|
# that doesn't necessarily have those flags already set on it
|
|
for d in dev nodev ; do
|
|
for e in exec noexec ; do
|
|
for s in suid nosuid ; do
|
|
for r in ro rw ; do
|
|
subdir=$tmpfs/d-$d-$e-$s-$r
|
|
echo mkdir ${subdir} >> ${TEST_SCRATCH_DIR}/script.sh
|
|
echo mount -t tmpfs -o size=256K,$d,$e,$s,$r tmpfs ${subdir} >> ${TEST_SCRATCH_DIR}/script.sh
|
|
mounts="${mounts:+${mounts} }--volume ${subdir}:/mounts/d-$d-$e-$s-$r:nodev,noexec,nosuid,ro"
|
|
done
|
|
done
|
|
done
|
|
done
|
|
# copy binaries to a location where parent directory permissions are less
|
|
# likely to interfere with running them from a different UID
|
|
cp ${COPY_BINARY} ${TEST_SCRATCH_DIR}/copy
|
|
cp ${BUILDAH_BINARY} ${TEST_SCRATCH_DIR}/buildah
|
|
# make sure that RUN doesn't just break when we try to use volume mounts with
|
|
# flags set that we're not allowed to modify
|
|
echo FROM $baseimage > $context/Dockerfile
|
|
echo RUN cat /proc/mounts >> $context/Dockerfile
|
|
# copy in the prefetched image
|
|
# unshare from util-linux 2.39 also accepts INNER:OUTER:SIZE for --map-users
|
|
# and --map-groups, but fedora 37's is too old, so the older OUTER,INNER,SIZE
|
|
# (using commas instead of colons as field separators) will have to do
|
|
echo "env | sort" >> ${TEST_SCRATCH_DIR}/script.sh
|
|
echo "env _CONTAINERS_USERNS_CONFIGURED=done unshare -Umpf --mount-proc --setuid 0 --setgid 0 --map-users=${subid},0,${rangesize} --map-groups=${subid},0,${rangesize} ${TEST_SCRATCH_DIR}/copy ${storageopts} dir:$_BUILDAH_IMAGE_CACHEDIR/$baseimagef containers-storage:$baseimage" >> ${TEST_SCRATCH_DIR}/script.sh
|
|
# try to do a build with all of the volume mounts
|
|
echo "env _CONTAINERS_USERNS_CONFIGURED=done unshare -Umpf --mount-proc --setuid 0 --setgid 0 --map-users=${subid},0,${rangesize} --map-groups=${subid},0,${rangesize} ${TEST_SCRATCH_DIR}/buildah ${BUILDAH_REGISTRY_OPTS} ${storageopts} build --isolation chroot --pull=never $mounts $context" >> ${TEST_SCRATCH_DIR}/script.sh
|
|
# run that whole script in a nested mount namespace with no $XDG_...
|
|
# variables leaked into it
|
|
if is_rootless ; then
|
|
run_buildah unshare env -i bash -x ${TEST_SCRATCH_DIR}/script.sh
|
|
else
|
|
unshare -mpf --mount-proc env -i bash -x ${TEST_SCRATCH_DIR}/script.sh
|
|
fi
|
|
}
|
|
|
|
@test "chroot with overlay root" {
|
|
if test `uname` != Linux ; then
|
|
skip "not meaningful except on Linux"
|
|
fi
|
|
skip_if_no_unshare
|
|
if [ "$(id -u)" -ne 0 ]; then
|
|
skip "expects to already be root"
|
|
fi
|
|
_prefetch docker.io/library/busybox
|
|
cp -v ${TEST_SOURCES}/containers.conf ${TEST_SCRATCH_DIR}/containers.conf
|
|
chmod ugo+r ${TEST_SCRATCH_DIR}/containers.conf
|
|
mkdir -p ${TEST_SCRATCH_DIR}/chroot
|
|
chown -R 1:1 ${TEST_SCRATCH_DIR}/root ${TEST_SCRATCH_DIR}/runroot ${TEST_SCRATCH_DIR}/chroot
|
|
cat > ${TEST_SCRATCH_DIR}/script1 <<- EOF
|
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin${PATH:+:$PATH}
|
|
set -e
|
|
set -x
|
|
mkdir -p ${TEST_SCRATCH_DIR}/chroot/workdir
|
|
mkdir -p ${TEST_SCRATCH_DIR}/chroot/upperdir
|
|
mkdir -p ${TEST_SCRATCH_DIR}/chroot/merged
|
|
mount -t overlay overlay -o upperdir=${TEST_SCRATCH_DIR}/chroot/upperdir,workdir=${TEST_SCRATCH_DIR}/chroot/workdir,lowerdir=/ ${TEST_SCRATCH_DIR}/chroot/merged
|
|
mount -t proc proc ${TEST_SCRATCH_DIR}/chroot/merged/proc
|
|
mount -t sysfs sysfs ${TEST_SCRATCH_DIR}/chroot/merged/sys
|
|
mount --bind /dev ${TEST_SCRATCH_DIR}/chroot/merged/dev
|
|
mount --bind /etc ${TEST_SCRATCH_DIR}/chroot/merged/etc
|
|
echo build > ${TEST_SCRATCH_DIR}/chroot/hostname
|
|
chmod 644 ${TEST_SCRATCH_DIR}/chroot/hostname
|
|
mount --bind ${TEST_SCRATCH_DIR}/chroot/hostname ${TEST_SCRATCH_DIR}/chroot/merged/etc/hostname
|
|
touch ${TEST_SCRATCH_DIR}/chroot/hosts
|
|
chmod 644 ${TEST_SCRATCH_DIR}/chroot/hosts
|
|
mount --bind ${TEST_SCRATCH_DIR}/chroot/hosts ${TEST_SCRATCH_DIR}/chroot/merged/etc/hosts
|
|
touch ${TEST_SCRATCH_DIR}/chroot/resolv.conf
|
|
chmod 644 ${TEST_SCRATCH_DIR}/chroot/resolv.conf
|
|
mount --bind ${TEST_SCRATCH_DIR}/chroot/resolv.conf ${TEST_SCRATCH_DIR}/chroot/merged/etc/resolv.conf
|
|
mount --bind /tmp ${TEST_SCRATCH_DIR}/chroot/merged/tmp
|
|
mkdir -p ${TEST_SCRATCH_DIR}/chroot/merged/var/tmp
|
|
chmod 1777 ${TEST_SCRATCH_DIR}/chroot/merged/var/tmp
|
|
if test -d /var/tmp; then
|
|
mount --bind /var/tmp ${TEST_SCRATCH_DIR}/chroot/merged/var/tmp
|
|
fi
|
|
mount --bind ${TEST_SCRATCH_DIR} ${TEST_SCRATCH_DIR}/chroot/merged/${TEST_SCRATCH_DIR}
|
|
mkdir -p ${TEST_SCRATCH_DIR}/chroot/merged/usr/local/bin
|
|
touch ${TEST_SCRATCH_DIR}/chroot/merged/usr/local/bin/buildah
|
|
mount --bind ${BUILDAH_BINARY:-$TEST_SOURCES/../bin/buildah} ${TEST_SCRATCH_DIR}/chroot/merged/usr/local/bin/buildah
|
|
cd ${TEST_SCRATCH_DIR}/chroot/merged
|
|
pivot_root . tmp
|
|
mount --make-rslave tmp
|
|
umount -f -l tmp
|
|
mount -o remount,ro --make-rshared /
|
|
grep ' / / ' /proc/self/mountinfo
|
|
# unshare from util-linux 2.39 also accepts INNER:OUTER:SIZE for --map-users
|
|
# and --map-groups, but fedora 37's is too old, so the older OUTER,INNER,SIZE
|
|
# (using commas instead of colons as field separators) will have to do
|
|
unshare --setuid 0 --setgid 0 --map-users=1,0,1024 --map-groups=1,0,1024 -UinCfpm bash ${TEST_SCRATCH_DIR}/script2
|
|
EOF
|
|
cat > ${TEST_SCRATCH_DIR}/script2 <<- EOF
|
|
set -e
|
|
set -x
|
|
export _CONTAINERS_USERNS_CONFIGURED=done
|
|
export CONTAINERS_CONF=${TEST_SCRATCH_DIR}/containers.conf
|
|
cat /proc/self/uid_map
|
|
cat /proc/self/gid_map
|
|
mount --make-shared /
|
|
/usr/local/bin/buildah ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} from --name ctrid --pull=never --quiet docker.io/library/busybox
|
|
/usr/local/bin/buildah ${BUILDAH_REGISTRY_OPTS} ${ROOTDIR_OPTS} run --isolation=chroot ctrid pwd
|
|
EOF
|
|
chmod +x ${TEST_SCRATCH_DIR}
|
|
chmod +rx ${TEST_SCRATCH_DIR}/script1 ${TEST_SCRATCH_DIR}/script2
|
|
env -i unshare -inCfpm bash ${TEST_SCRATCH_DIR}/script1
|
|
}
|