diff --git a/internal/runtime/unshare.go b/internal/runtime/unshare.go index 987f8fe..134e147 100644 --- a/internal/runtime/unshare.go +++ b/internal/runtime/unshare.go @@ -17,6 +17,14 @@ import ( // pause process exists. The environment podman unshare would set is set the // same way, so helpers that check for it behave identically. func inPodmanNS(argv ...string) *exec.Cmd { + // Already inside it -- `box __fc` and the other helpers run there -- + // the namespace cannot be entered again: setns into the user namespace + // one is in fails with EINVAL. Run argv directly. Without this, a + // Firecracker VM torn down from inside never got its crun kill, and every + // run and snapshot left its VM running. + if os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" { + return exec.Command(argv[0], argv[1:]...) + } if pid := pausePID(); pid > 0 { args := []string{"--user", "--mount", "--preserve-credentials", "--target", strconv.Itoa(pid), "--"} cmd := exec.Command("nsenter", append(args, argv...)...) diff --git a/security/escape-test.sh b/security/escape-test.sh index 5f671be..690a46b 100755 --- a/security/escape-test.sh +++ b/security/escape-test.sh @@ -261,6 +261,18 @@ t0=$(date +%s%N); ls / >/dev/null; t1=$(date +%s%N) [ $(( (t1 - t0) / 1000000 )) -lt 1000 ] && pass "host responsive during a guest fork bomb" \ || fail "host slowed by a guest fork bomb" +echo +echo "nothing left behind" +# A run's VM is gone when the run is; only the sandbox that is up stays. +"$BB" run "$NAME" -- true >/dev/null 2>&1 +sleep 1 +case "$BACKEND" in + firecracker) left=$(podman unshare crun --root "${XDG_RUNTIME_DIR:-/tmp}/box/fc" list 2>/dev/null | awk -v up="box-up-$NAME" 'NR>1 && $1 ~ /^box-/ && $1 != up' | wc -l) ;; + krun) left=$(podman unshare krun --root "${XDG_RUNTIME_DIR:-/tmp}/box/krun" list 2>/dev/null | awk -v up="box-up-$NAME" 'NR>1 && $1 ~ /^box-/ && $1 != up' | wc -l) ;; + *) left=$(podman ps -a --format '{{.Names}}' 2>/dev/null | grep "^box-$NAME-" | wc -l) ;; +esac +[ "$left" -eq 0 ] && pass "no VM outlives its run" || fail "$left VM(s) still running after their run ended" + echo if [ "$FAILS" -eq 0 ]; then echo "no escapes."