bunpen: expose the bare / tmpfs at /unbacked, to allow for debugging ramdisk usage
This commit is contained in:
@@ -24,7 +24,6 @@ install:
|
||||
|
||||
test:
|
||||
hare test
|
||||
# N.B.: integration_test relies on bashisms, not just `sh`.
|
||||
PATH=$(PWD):$(PATH) bash ./integration_test
|
||||
PATH=$(PWD):$(PATH) ./integration_test
|
||||
|
||||
.PHONY: all install test
|
||||
|
@@ -1,8 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
# vim: set shiftwidth=2 :
|
||||
# XXX: `bash` shebang because this relies on bashisms, not just `sh`!
|
||||
|
||||
set -o pipefail
|
||||
set -eu
|
||||
|
||||
SELF=$(realpath $0)
|
||||
|
||||
# we can't rely on /usr/bin/env existing in the nix build environment
|
||||
env=$(which env)
|
||||
test=$(which test)
|
||||
@@ -19,7 +23,7 @@ captureExitStatus() {
|
||||
}
|
||||
|
||||
test_01_invoke_01_trivial() {
|
||||
bunpen --bunpen-path / "$env" true
|
||||
bunpen --bunpen-debug=4 --bunpen-path / "$env" true
|
||||
}
|
||||
|
||||
test_01_invoke_02_by_path() {
|
||||
@@ -202,33 +206,108 @@ test_09_reap_children() {
|
||||
ps x | grep -E 'Zs +[0-9]+:[0-9]+ \[true\] <defunct>' && return 1 || return 0
|
||||
}
|
||||
|
||||
test_10_tmpfs_root_is_introspectable() {
|
||||
echo from_parent > test_file0
|
||||
bunpen --bunpen-path /nix/store --bunpen-path $PWD bash -c "test -f $PWD/test_file0 && echo 'from_sandbox' > /test_file1 && sleep 2" &
|
||||
local sbox_pid=$!
|
||||
sleep 0.5
|
||||
|
||||
rc=0
|
||||
succeeded=()
|
||||
failed=()
|
||||
for f in $(declare -F); do
|
||||
if [[ "$f" =~ ^test_* ]]; then
|
||||
mkdir "$f"
|
||||
# /proc/$pid/root is the rootfs as seen from inside the sandbox.
|
||||
# within the sandbox, `/unbacked` holds the actual rootfs, without anyting mounted over it;
|
||||
# i.e., the portion of the fstree which is backed only by the tmpfs-root
|
||||
test ! -e /proc/$sbox_pid/root/unbacked/$PWD/test_file0
|
||||
test /proc/$sbox_pid/root/$PWD/test_file0
|
||||
local test_file1=$(cat /proc/$sbox_pid/root/unbacked/test_file1)
|
||||
|
||||
# diagnostics, should the test fail:
|
||||
echo -n "/proc/$sbox_pid: " && ls /proc/$sbox_pid
|
||||
echo -n "/proc/$sbox_pid/root: " && ls /proc/$sbox_pid/root
|
||||
echo -n "/proc/$sbox_pid/root/unbacked: " && ls /proc/$sbox_pid/root/unbacked
|
||||
echo -n "/proc/$sbox_pid/root/unbacked/test_file1: " && echo "$test_file1"
|
||||
echo -n "/proc/$sbox_pid/root/unbacked/$PWD: " && ls -l /proc/$sbox_pid/root/unbacked/$PWD
|
||||
|
||||
test "$test_file1" = from_sandbox
|
||||
}
|
||||
|
||||
runTests() {
|
||||
local testsToRun=("$@")
|
||||
rc=0
|
||||
succeeded=()
|
||||
failed=()
|
||||
basedir=$PWD
|
||||
for f in "${testsToRun[@]}"; do
|
||||
mkdir "$basedir/$f"
|
||||
echo -n "$f: ..."
|
||||
if (cd "$f"; "$f"); then
|
||||
cd "$basedir/$f"
|
||||
if $SELF "$f" > "$basedir/$f/stdall" 2>&1; then
|
||||
echo " SUCCESS"
|
||||
succeeded+=("$f")
|
||||
else
|
||||
rc=1
|
||||
echo " FAIL"
|
||||
cat "$basedir/$f/stdall"
|
||||
failed+=("$f")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "${#failed[@]}" != 0 ]]; then
|
||||
echo
|
||||
echo "FAILED TESTS:"
|
||||
fi
|
||||
|
||||
for t in "${failed[@]}"; do
|
||||
echo "- $t"
|
||||
done
|
||||
|
||||
echo "${#succeeded[@]} tests succeeded"
|
||||
test -n "${#succeeded[@]}" || return 1
|
||||
return "$rc"
|
||||
}
|
||||
|
||||
|
||||
self_test_succeed() {
|
||||
true
|
||||
}
|
||||
self_test_fail() {
|
||||
false
|
||||
}
|
||||
self_test_pipe_fail() {
|
||||
true | false | true
|
||||
}
|
||||
self_test_step_fail() {
|
||||
true
|
||||
false
|
||||
true
|
||||
}
|
||||
|
||||
selfTest() {
|
||||
# bash is dumb; make sure that if a test would fail, the toplevel test runner would also fail
|
||||
if "$SELF" self_test_succeed \
|
||||
&& ! "$SELF" self_test_fail \
|
||||
&& ! "$SELF" self_test_pipe_fail \
|
||||
&& ! "$SELF" self_test_step_fail \
|
||||
&& ! "$SELF" self_test_succeed self_test_fail self_test_succeed \
|
||||
; then
|
||||
echo "self-test: success"
|
||||
else
|
||||
echo "self-test: FAIL"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
allTests=()
|
||||
for f in $(declare -F); do
|
||||
if [[ "$f" =~ ^test_* ]]; then
|
||||
allTests+=("$f")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "${#failed[@]}" ]]; then
|
||||
echo
|
||||
echo "FAILED TESTS:"
|
||||
if [ $# = 1 ]; then
|
||||
# run the test inline
|
||||
"$@"
|
||||
elif [ $# = 0 ]; then
|
||||
selfTest
|
||||
runTests "${allTests[@]}"
|
||||
else
|
||||
runTests "$@"
|
||||
fi
|
||||
|
||||
for t in "${failed[@]}"; do
|
||||
echo "- $t"
|
||||
done
|
||||
|
||||
test -n "${#succeeded[@]}"
|
||||
exit "$rc"
|
||||
|
@@ -34,6 +34,10 @@
|
||||
|
||||
doCheck = true;
|
||||
|
||||
postPatch = ''
|
||||
patchShebangs --build integration_test
|
||||
'';
|
||||
|
||||
meta = {
|
||||
description = "userspace sandbox helper";
|
||||
longDescription = ''
|
||||
|
@@ -41,6 +41,23 @@ fn isolate_paths(what: *restrict::resources) void = {
|
||||
// errors::ext::check("[namespace] mount -t tmpfs tmpfs new", rt::ext::mount("tmpfs", "new", "tmpfs", rt::ext::mount_flag::NODEV | rt::ext::mount_flag::NOSUID, null));
|
||||
// errors::ext::check("[namespace] mount -o rbind new new", rt::ext::mount("new", "new", "", rt::ext::mount_flag::BIND | rt::ext::mount_flag::REC, null));
|
||||
|
||||
// bind the new `/` tmpfs also to `/unbacked`; this is entirely optional, to
|
||||
// aid with troubleshooting:
|
||||
// `/unbacked` is a shallow bind of `/`, so provides a view into which files
|
||||
// are backed only by RAM.
|
||||
// admins can debug unexpected RAM use by querying (from outside the sandbox):
|
||||
// - `for p in /proc/*; do if [ "$p" != /proc/self -a "$p" != /proc/thread-self -a -d "$p/root/unbacked" ]; then du -h "$p/root/unbacked"; fi; done | sort -h`
|
||||
errors::ext::check("[namespace] mkdir new/unbacked", rt::mkdir("new/unbacked", 0o755));
|
||||
errors::ext::check("[namespace] mount new new/unbacked",
|
||||
rt::ext::mount(
|
||||
"new",
|
||||
"new/unbacked",
|
||||
"",
|
||||
rt::ext::mount_flag::BIND,
|
||||
null,
|
||||
)
|
||||
);
|
||||
|
||||
// try to mount a new /proc.
|
||||
// - this is "safe" because we're not doing anything
|
||||
// the sandboxed program can't do. IOW, if this is unsafe, then the downstream
|
||||
|
Reference in New Issue
Block a user