Skip to content

Commit

Permalink
Use mount namespace instead of chroot
Browse files Browse the repository at this point in the history
This allow to not worry about mounts done within the namespace.  We
can now bind mount files into the sysroot instead of copying them.
  • Loading branch information
valentindavid committed Jun 30, 2022
1 parent dbac067 commit 1b84617
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 20 deletions.
14 changes: 3 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,22 @@ install:
fi
rm -rf $(DESTDIR)
cp -aT $(CRAFT_STAGE)/base $(DESTDIR)
# ensure resolving works inside the chroot
cat /etc/resolv.conf > $(DESTDIR)/etc/resolv.conf
# copy-in launchpad's build archive
if grep -q ftpmaster.internal /etc/apt/sources.list; then \
cp /etc/apt/sources.list $(DESTDIR)/etc/apt/sources.list; \
cp /etc/apt/trusted.gpg $(DESTDIR)/etc/apt/ || true; \
cp -r /etc/apt/trusted.gpg.d $(DESTDIR)/etc/apt/ || true; \
fi
# since recently we're also missing some /dev files that might be
# useful during build - make sure they're there
[ -e $(DESTDIR)/dev/null ] || mknod -m 666 $(DESTDIR)/dev/null c 1 3
[ -e $(DESTDIR)/dev/zero ] || mknod -m 666 $(DESTDIR)/dev/zero c 1 5
[ -e $(DESTDIR)/dev/random ] || mknod -m 666 $(DESTDIR)/dev/random c 1 8
[ -e $(DESTDIR)/dev/urandom ] || \
mknod -m 666 $(DESTDIR)/dev/urandom c 1 9
# copy static files verbatim
/bin/cp -a static/* $(DESTDIR)
mkdir -p $(DESTDIR)/install-data
/bin/cp -r $(CRAFT_STAGE)/local-debs $(DESTDIR)/install-data/local-debs
# customize
set -eux; for f in ./hooks/[0-9]*.chroot; do \
base="$$(basename "$${f}")"; \
cp -a "$${f}" $(DESTDIR)/install-data/; \
chroot $(DESTDIR) "/install-data/$${base}"; \
./mount-ns.sh spawn $(DESTDIR) \
--ro-bind $$f "/install-data/$${base}" \
-- "/install-data/$${base}"; \
rm "$(DESTDIR)/install-data/$${base}"; \
done
rm -rf $(DESTDIR)/install-data
Expand Down
4 changes: 0 additions & 4 deletions hooks/001-extra-packages.chroot
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ export DEBIAN_FRONTEND=noninteractive
rm -f /etc/apt/sources.list.d/proposed.list


# ensure we have /proc or systemd will fail
mount -t proc proc /proc
trap 'umount /proc' EXIT

# systemd postinst needs this
mkdir -p /var/log/journal

Expand Down
5 changes: 0 additions & 5 deletions hooks/999-clean-resolv-conf.chroot

This file was deleted.

105 changes: 105 additions & 0 deletions mount-ns.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/bash

set -eu

# FIXME: This should be replace by a mount of devtmpfs when
# it is supported in user namespaces
bind_dev() {
dev="${1}/dev"

for device in null zero full random urandom tty; do
touch "${dev}/${device}"
mount --bind "/dev/${device}" "${dev}/${device}"
done
}

# Because systemd debian package post-install script is not very
# robust, we have to create a symlink and bind mount resolv.conf
# there.
bind_resolv() {
sysroot="${1}"

resolv_real_path="${sysroot}/run/fake-resolv.conf"
create_symlink=yes
if [ -L "${sysroot}/etc/resolv.conf" ]; then
resolv="$(readlink "${sysroot}/etc/resolv.conf")"
if [ "${resolv}" = "../run/systemd/resolve/stub-resolv.conf" ]; then
resolv_real_path="${sysroot}/run/systemd/resolve/stub-resolv.conf"
create_symlink=no
fi
fi
mkdir -p "$(dirname "${resolv_real_path}")"
touch "${resolv_real_path}"
mount --bind -o ro /etc/resolv.conf "${resolv_real_path}"
if [ "${create_symlink}" = yes ]; then
ln -srf "${resolv_real_path}" "${sysroot}/etc/resolv.conf"
fi
}

if [ $# -lt 3 ]; then
echo "Expected at least 3 arguments" 1>&2
exit 1
fi

command="${1}"
sysroot="${2}"
shift 2

case "${command}" in
spawn)
cleanup() {
umount "${sysroot}/dev" || true
umount "${sysroot}/tmp" || true
umount "${sysroot}/run" || true
}
mount -t tmpfs -o mode=0755 tmpfs "${sysroot}/dev"
mount -t tmpfs -o mode=1777 tmpfs "${sysroot}/tmp"
mount -t tmpfs -o mode=0755 tmpfs "${sysroot}/run"
trap cleanup EXIT
unshare --pid --fork --mount -- "${0}" init "${sysroot}" "${@}"
;;
init)
mount -t proc proc "${sysroot}/proc"
bind_dev "${sysroot}"
bind_resolv "${sysroot}"
while [ $# -gt 1 ]; do
case "${1}" in
--)
shift
break
;;
--bind|--ro-bind)
if [ -d "$2" ]; then
if ! [ -d "${sysroot}/$3" ]; then
mkdir -p "${sysroot}/$3"
fi
else
if ! [ -e "${sysroot}/$3" ]; then
dir="$(dirname "${sysroot}/$3")"
if ! [ -d "${dir}" ]; then
mkdir -p "${dir}"
fi
touch "${sysroot}/$3"
fi
fi
extra_args=()
case "$1" in
--ro-bind)
extra_args=("-o" "ro")
;;
esac
mount --bind "${extra_args[@]}" "$2" "${sysroot}/$3"
shift 3
;;
*)
break
;;
esac
done
exec unshare --mount --root="${sysroot}" -- "${@}"
;;
*)
echo "Unknown command" 1>&2
exit 1
;;
esac

0 comments on commit 1b84617

Please sign in to comment.