110 lines
5.9 KiB
Bash
110 lines
5.9 KiB
Bash
#!/usr/bin/env bash
|
|
# Full-VM e2e for the shared content-addressed pack store + per-VM idmapped
|
|
# bind mount. Drives the *serve API* (the cloud/node path that the shared store
|
|
# targets) as root so the per-VM uid drop (#456) is active and the idmap mount
|
|
# fires. Validates: (1) shared store extracts ONCE into _shared/<checksum>,
|
|
# root-owned 0700; (2) a second machine from the same .smolmachine REUSES it
|
|
# (no second decode); (3) each machine leaves an empty `pack` mountpoint + a
|
|
# `.pack-shared` pointer; (4) both guests BOOT and exec reads files (proving the
|
|
# idmap mount presented the root-owned pack as the VM's dropped uid); (5) the
|
|
# on-disk shared copy stays root:root (isolation preserved).
|
|
#
|
|
# Run as root on a Linux/KVM box: sudo SMOLVM=... SMOLVM_LIB_DIR=... ./idmap_e2e_boot.sh /path/to/x.smolmachine
|
|
set -u
|
|
|
|
SMOLVM="${SMOLVM:?set SMOLVM to the smolvm binary}"
|
|
SIDECAR="${1:?usage: idmap_e2e_boot.sh <file.smolmachine>}"
|
|
DATA_DIR="${SMOLVM_DATA_DIR:-/tmp/idmap-e2e-data}"
|
|
SOCK="/tmp/idmap-e2e.sock"
|
|
CURL=(curl -s --unix-socket "$SOCK")
|
|
URL="http://localhost"
|
|
PASS=0; FAIL=0
|
|
ok() { echo " PASS: $*"; PASS=$((PASS+1)); }
|
|
bad() { echo " FAIL: $*"; FAIL=$((FAIL+1)); }
|
|
|
|
# Fresh, world-traversable data root so the dropped VM uid can reach its dirs.
|
|
rm -rf "$DATA_DIR"; mkdir -p "$DATA_DIR"; chmod 755 "$DATA_DIR"
|
|
export SMOLVM_DATA_DIR="$DATA_DIR"
|
|
|
|
# Seed the node-constant guest agent-rootfs (the serve API gates `start` on it
|
|
# via "verify rootfs"). It's install-state, not part of the per-image pack the
|
|
# shared store optimizes, so we copy a known-good tree in rather than re-install.
|
|
AGENT_ROOTFS_SRC="${AGENT_ROOTFS_SRC:-$HOME/.local/share/smolvm/agent-rootfs}"
|
|
if [ -d "$AGENT_ROOTFS_SRC" ]; then
|
|
mkdir -p "$DATA_DIR/.local/share/smolvm"
|
|
cp -a "$AGENT_ROOTFS_SRC" "$DATA_DIR/.local/share/smolvm/agent-rootfs"
|
|
chmod -R a+rX "$DATA_DIR/.local/share/smolvm"
|
|
else
|
|
echo "[!] no agent-rootfs at $AGENT_ROOTFS_SRC — boot steps will fail (set AGENT_ROOTFS_SRC)"
|
|
fi
|
|
|
|
echo "[*] euid=$(id -u) (expect 0 for uid-drop), data=$DATA_DIR, sidecar=$SIDECAR"
|
|
|
|
rm -f "$SOCK"
|
|
"$SMOLVM" serve start -l "unix://$SOCK" >"$DATA_DIR/serve.log" 2>&1 &
|
|
SERVE_PID=$!
|
|
cleanup() {
|
|
"${CURL[@]}" -X DELETE "$URL/api/v1/machines/e2e-a" >/dev/null 2>&1 || true
|
|
"${CURL[@]}" -X DELETE "$URL/api/v1/machines/e2e-b" >/dev/null 2>&1 || true
|
|
kill "$SERVE_PID" 2>/dev/null || true; wait "$SERVE_PID" 2>/dev/null || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
for i in $(seq 1 50); do "${CURL[@]}" "$URL/health" >/dev/null 2>&1 && break; sleep 0.2; done
|
|
"${CURL[@]}" "$URL/health" | grep -q '"status":"ok"' && ok "serve up" || { bad "serve did not start"; cat "$DATA_DIR/serve.log"; exit 1; }
|
|
|
|
create() {
|
|
"${CURL[@]}" -o /dev/null -w "%{http_code}" -X POST "$URL/api/v1/machines" \
|
|
-H 'Content-Type: application/json' -d "{\"name\":\"$1\",\"from\":\"$SIDECAR\",\"cpus\":1,\"mem\":512}"
|
|
}
|
|
|
|
# --- Create machine A: first extraction populates the shared store ----------
|
|
echo "[*] creating e2e-a"
|
|
[ "$(create e2e-a)" = "200" ] && ok "create e2e-a 200" || bad "create e2e-a !=200"
|
|
|
|
# Layout: SMOLVM_DATA_DIR becomes $HOME, so the store is $HOME/.cache/smolvm/vms.
|
|
VMS_ROOT="$(find "$DATA_DIR" -type d -path '*/smolvm/vms' | head -1)"
|
|
SHARED_ROOT="$VMS_ROOT/_shared"
|
|
[ -d "$SHARED_ROOT" ] && ok "shared root exists: $SHARED_ROOT" || bad "no shared root (vms=$VMS_ROOT)"
|
|
CKDIR="$(find "$SHARED_ROOT" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | head -1)"
|
|
[ -n "$CKDIR" ] && ok "shared checksum dir: $(basename "$CKDIR")" || bad "no shared checksum dir"
|
|
# Root-owned + 0700 (isolation): a sibling dropped-uid cannot read it directly.
|
|
own="$(stat -c '%U:%G %a' "$CKDIR" 2>/dev/null)"
|
|
[ "$own" = "root:root 700" ] && ok "shared dir is root:root 0700" || bad "shared dir perms = $own (want root:root 700)"
|
|
# Per-machine: empty `pack` mountpoint + a pointer to the shared dir.
|
|
PACK_A="$(find "$VMS_ROOT" -mindepth 2 -maxdepth 2 -name pack -type d 2>/dev/null | grep -v _shared | head -1)"
|
|
PTR_A="$(dirname "$PACK_A")/.pack-shared"
|
|
[ -f "$PTR_A" ] && ok "pointer written: $PTR_A -> $(cat "$PTR_A")" || bad "no .pack-shared pointer"
|
|
[ -z "$(ls -A "$PACK_A" 2>/dev/null)" ] && ok "pack mountpoint is empty (pre-boot)" || bad "pack mountpoint not empty"
|
|
|
|
# --- Create machine B from the SAME sidecar: must REUSE, not re-extract ------
|
|
echo "[*] creating e2e-b (same sidecar)"
|
|
[ "$(create e2e-b)" = "200" ] && ok "create e2e-b 200" || bad "create e2e-b !=200"
|
|
NDIRS="$(find "$SHARED_ROOT" -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')"
|
|
[ "$NDIRS" = "1" ] && ok "still ONE shared dir after 2 creates (reuse, no re-decode)" || bad "shared dirs=$NDIRS (expected 1)"
|
|
|
|
# --- Boot both: idmap mount presents the root-owned pack as each VM's uid ----
|
|
boot_and_exec() {
|
|
local n="$1"
|
|
local st; st="$("${CURL[@]}" -X POST "$URL/api/v1/machines/$n/start")"
|
|
echo "$st" | grep -q '"state":"running"' && ok "$n booted (state=running)" || { bad "$n did not boot"; echo "$st"; }
|
|
local ex; ex="$("${CURL[@]}" -X POST "$URL/api/v1/machines/$n/exec" -H 'Content-Type: application/json' -d '{"command":["cat","/etc/os-release"]}')"
|
|
echo "$ex" | grep -qi 'alpine\|linux' && ok "$n exec read rootfs through idmap mount" || { bad "$n exec failed"; echo "$ex" | head -c 400; }
|
|
}
|
|
boot_and_exec e2e-a
|
|
boot_and_exec e2e-b
|
|
|
|
# --- Isolation: shared copy still root-owned after both VMs booted -----------
|
|
own2="$(stat -c '%U:%G %a' "$CKDIR" 2>/dev/null)"
|
|
[ "$own2" = "root:root 700" ] && ok "shared copy still root:root 0700 post-boot" || bad "shared perms changed: $own2"
|
|
|
|
# --- The two VMMs dropped to DIFFERENT uids (per-VM isolation #456) ----------
|
|
uids="$(ps -eo uid,args | grep '[_]boot-vm' | awk '{print $1}' | sort -u)"
|
|
nuid="$(echo "$uids" | grep -c .)"
|
|
echo "[*] live _boot-vm uids: $(echo $uids | tr '\n' ' ')"
|
|
[ "$nuid" -ge 2 ] && ok "VMMs run under >=2 distinct dropped uids" || echo " INFO: distinct boot-vm uids=$nuid (VMs may share or have exited)"
|
|
|
|
echo ""
|
|
echo "==== idmap e2e: $PASS passed, $FAIL failed ===="
|
|
[ "$FAIL" = "0" ]
|