allow running root mode inside unshare mode
This commit is contained in:
parent
a6186e8485
commit
70b081d299
2 changed files with 108 additions and 29 deletions
45
coverage.sh
45
coverage.sh
|
@ -127,7 +127,7 @@ if [ ! -e shared/hooks/eatmydata/customize.sh ] || [ hooks/eatmydata/customize.s
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
starttime=
|
starttime=
|
||||||
total=182
|
total=183
|
||||||
skipped=0
|
skipped=0
|
||||||
runtests=0
|
runtests=0
|
||||||
i=1
|
i=1
|
||||||
|
@ -712,7 +712,48 @@ else
|
||||||
runtests=$((runtests+1))
|
runtests=$((runtests+1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
print_header "mode=unshare,variant=apt: root without cap_sys_admin"
|
# Same as above but this time we run mmdebstrap in root mode from inside
|
||||||
|
# an unshare chroot.
|
||||||
|
print_header "mode=root,variant=apt: root mode inside unshare chroot"
|
||||||
|
cat << END > shared/test.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
if [ ! -e /mmdebstrap-testenv ]; then
|
||||||
|
echo "this test modifies the system and should only be run inside a container" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
[ "\$(whoami)" = "root" ]
|
||||||
|
adduser --gecos user --disabled-password user
|
||||||
|
sysctl -w kernel.unprivileged_userns_clone=1
|
||||||
|
cat << 'SCRIPT' > script.sh
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
rootfs="\$1"
|
||||||
|
mkdir -p "\$rootfs/mnt"
|
||||||
|
[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "\$rootfs/usr/bin/mmdebstrap"
|
||||||
|
[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "\$rootfs/mnt/mmdebstrap"
|
||||||
|
chroot "\$rootfs" env --chdir=/mnt \
|
||||||
|
$CMD --mode=root --variant=apt \
|
||||||
|
$DEFAULT_DIST /tmp/debian-chroot.tar $mirror
|
||||||
|
SCRIPT
|
||||||
|
chmod +x script.sh
|
||||||
|
runuser -u user -- $CMD --mode=unshare --variant=apt --include=perl,mount \
|
||||||
|
--customize-hook=./script.sh \
|
||||||
|
--customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \
|
||||||
|
$DEFAULT_DIST /dev/null $mirror
|
||||||
|
tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt -
|
||||||
|
rm /tmp/debian-chroot.tar script.sh
|
||||||
|
END
|
||||||
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
|
./run_qemu.sh
|
||||||
|
runtests=$((runtests+1))
|
||||||
|
else
|
||||||
|
echo "HAVE_QEMU != yes -- Skipping test..." >&2
|
||||||
|
skipped=$((skipped+1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_header "mode=root,variant=apt: root without cap_sys_admin"
|
||||||
cat << END > shared/test.sh
|
cat << END > shared/test.sh
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -eu
|
set -eu
|
||||||
|
|
54
mmdebstrap
54
mmdebstrap
|
@ -1181,15 +1181,35 @@ sub run_chroot {
|
||||||
warning("skipping bind-mounting /sys because"
|
warning("skipping bind-mounting /sys because"
|
||||||
. " /sys on the outside is not a directory");
|
. " /sys on the outside is not a directory");
|
||||||
} elsif ($options->{mode} eq 'root') {
|
} elsif ($options->{mode} eq 'root') {
|
||||||
|
# we don't know whether we run in root mode inside an unshared
|
||||||
|
# user namespace or as real root so we first try the real mount and
|
||||||
|
# then fall back to mounting in a way that works in unshared mode
|
||||||
|
if (
|
||||||
|
0 == system(
|
||||||
|
'mount', '-t',
|
||||||
|
'sysfs', '-o',
|
||||||
|
'ro,nosuid,nodev,noexec', 'sys',
|
||||||
|
"$options->{root}/sys"
|
||||||
|
)
|
||||||
|
) {
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
0 == system('umount', "$options->{root}/sys")
|
0 == system('umount', "$options->{root}/sys")
|
||||||
or warn "umount /sys failed: $?";
|
or warn "umount /sys failed: $?";
|
||||||
};
|
};
|
||||||
|
} elsif (
|
||||||
|
0 == system('mount', '-o', 'rbind', '/sys',
|
||||||
|
"$options->{root}/sys")) {
|
||||||
|
push @cleanup_tasks, sub {
|
||||||
|
# since we cannot write to /etc/mtab we need --no-mtab
|
||||||
|
# unmounting /sys only seems to be successful with --lazy
|
||||||
0 == system(
|
0 == system(
|
||||||
'mount', '-t', 'sysfs',
|
'umount', '--no-mtab',
|
||||||
'-o', 'ro,nosuid,nodev,noexec', 'sys',
|
'--lazy', "$options->{root}/sys"
|
||||||
"$options->{root}/sys"
|
) or warn "umount /sys failed: $?";
|
||||||
) or error "mount /sys failed: $?";
|
};
|
||||||
|
} else {
|
||||||
|
error "mount /sys failed: $?";
|
||||||
|
}
|
||||||
} elsif ($options->{mode} eq 'unshare') {
|
} elsif ($options->{mode} eq 'unshare') {
|
||||||
# naturally we have to clean up after ourselves in sudo mode where
|
# naturally we have to clean up after ourselves in sudo mode where
|
||||||
# we do a real mount. But we also need to unmount in unshare mode
|
# we do a real mount. But we also need to unmount in unshare mode
|
||||||
|
@ -1236,6 +1256,15 @@ sub run_chroot {
|
||||||
warning("skipping bind-mounting /proc because"
|
warning("skipping bind-mounting /proc because"
|
||||||
. " /proc on the outside is not a directory");
|
. " /proc on the outside is not a directory");
|
||||||
} elsif ($options->{mode} eq 'root') {
|
} elsif ($options->{mode} eq 'root') {
|
||||||
|
# we don't know whether we run in root mode inside an unshared
|
||||||
|
# user namespace or as real root so we first try the real mount and
|
||||||
|
# then fall back to mounting in a way that works in unshared
|
||||||
|
if (
|
||||||
|
0 == system(
|
||||||
|
'mount', '-t', 'proc', '-o', 'ro', 'proc',
|
||||||
|
"$options->{root}/proc"
|
||||||
|
)
|
||||||
|
) {
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
# some maintainer scripts mount additional stuff into /proc
|
# some maintainer scripts mount additional stuff into /proc
|
||||||
# which we need to unmount beforehand
|
# which we need to unmount beforehand
|
||||||
|
@ -1246,14 +1275,23 @@ sub run_chroot {
|
||||||
) {
|
) {
|
||||||
0 == system('umount',
|
0 == system('umount',
|
||||||
"$options->{root}/proc/sys/fs/binfmt_misc")
|
"$options->{root}/proc/sys/fs/binfmt_misc")
|
||||||
or error "umount /proc/sys/fs/binfmt_misc failed: $?";
|
or error
|
||||||
|
"umount /proc/sys/fs/binfmt_misc failed: $?";
|
||||||
}
|
}
|
||||||
0 == system('umount', "$options->{root}/proc")
|
0 == system('umount', "$options->{root}/proc")
|
||||||
or error "umount /proc failed: $?";
|
or error "umount /proc failed: $?";
|
||||||
};
|
};
|
||||||
0 == system('mount', '-t', 'proc', '-o', 'ro', 'proc',
|
} elsif (
|
||||||
"$options->{root}/proc")
|
0 == system('mount', '-t', 'proc', 'proc',
|
||||||
or error "mount /proc failed: $?";
|
"$options->{root}/proc")) {
|
||||||
|
push @cleanup_tasks, sub {
|
||||||
|
# since we cannot write to /etc/mtab we need --no-mtab
|
||||||
|
0 == system('umount', '--no-mtab', "$options->{root}/proc")
|
||||||
|
or error "umount /proc failed: $?";
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
error "mount /proc failed: $?";
|
||||||
|
}
|
||||||
} elsif ($options->{mode} eq 'unshare') {
|
} elsif ($options->{mode} eq 'unshare') {
|
||||||
# naturally we have to clean up after ourselves in sudo mode where
|
# naturally we have to clean up after ourselves in sudo mode where
|
||||||
# we do a real mount. But we also need to unmount in unshare mode
|
# we do a real mount. But we also need to unmount in unshare mode
|
||||||
|
|
Loading…
Reference in a new issue