#!/bin/sh
set -eux
if [ $(id -u) != 0 ]; then
echo "use sudo"
exit 1
fi
echo "OUTER: $(readlink /proc/self/ns/mnt)"
mkdir -p /old-root
ROOTFS=$(mktemp -d /tmp/hackery.XXXXXX)
# Unshare the mount namespace with "shared" propagation.
# We need shared propagation to have any chance of exerting
# influence on the parent namespace.
#
# The strace helps us understand what is happening in the terms
# of the essential system calls.
ROOTFS="$ROOTFS" \
strace -qq -f \
-e signal= \
-e trace=unshare,setns,mount,umount2,umount \
unshare -m --propagation shared sh -c "
set -eux
# Bind mount the temporary directory for rootfs over itself so that it is a
# mount point. This is done so that it can become unbindable in the next line.
mount --bind $ROOTFS $ROOTFS
# Make the temporary directory for rootfs unbindable. This is required as
# otherwise we'd have an infinite cycle since $ROOTFS/$ROOTFS would be / again
# and the cycle would have no limit.
mount --make-unbindable $ROOTFS
# Bind mount / over $ROOTFS, this lets us have a distinctly mapped root
# directory that starts out as the genuine root directory of the host. In real
# version of snap-confine this would be the core snap instead of the root
# filesystem.
mount --rbind / $ROOTFS
# Make the temporary rootfs recursively private so that all the mount
# operations there cannot leak to the parent namespace (which we are sharing
# initially after unshare --propagation shared). This is the essential part of
# confinement that lets processes roam free but still without any chance to
# affect the outer namespace.
# LOOPHOLE: can this be undone with --make-rshared after that or will that be
both private and shared (private for the master, shared for any additional
namespaces)
mount --make-rprivate $ROOTFS
# Recursively bind mount /media into the temporary rootfs's version of /media.
# This essentially lets us see anything that is mounted there *and*
# mount/unmount anything that we want in a way that is visible outside.
# TODO: check what is the initial sharing of this in the kernel docs (there's a
# nice table in shared-subtrees.txt). This affects the next call.
mount --rbind /media $ROOTFS/media
# Make the /media directory in the temporary rootfs recursively shared. This
# lets us change anything there and have the events propagate all the way up.
mount --make-rshared $ROOTFS/media
# Pivot root so that the temporary root directory becomes the real root directory
# and that the old root directory is moved to $ROOTFS/old-root.
pivot_root $ROOTFS $ROOTFS/old-root
# Make this old-root rprivate so that the next MNT_DETACH unmount not hose the
# parent.
mount --make-rprivate /old-root
umount -l /old-root
echo \"INNER: \$(readlink /proc/self/ns/mnt)\"
# Let's play :-)
exec bash
"