model: validate VM names as DNS labels at CLI + daemon
A VM name flows into five places that all have narrower grammars
than "arbitrary string":
- the guest's /etc/hostname (vm_disk.patchRootOverlay)
- the guest's /etc/hosts (same)
- the <name>.vm DNS record (vmdns.RecordName)
- the kernel command line (system.BuildBootArgs*)
- VM-dir file-path fragments (layout.VMsDir/<id>, etc.)
Nothing in the chain was validating the input. A name with
whitespace, newline, dot, slash, colon, or = would produce broken
hostnames, weird DNS labels, smuggled kernel cmdline tokens, or
(in the worst case) surprising traversal through the on-disk
layout. Not host shell injection — we already avoid shelling out
with the raw name — but a real correctness and supportability bug.
New: model.ValidateVMName. Rules:
- 1..63 chars (DNS label max per RFC 1123; also a comfortable
/etc/hostname cap)
- lowercase ASCII letters, digits, '-' only
- no leading or trailing '-'
- no normalization — the name is the user-visible identifier
(store key, `ssh <name>.vm`, `vm show`); silently rewriting
"MyVM" → "myvm" would hand the user back something different
than they typed
Called from two places:
- internal/cli/commands_vm.go vmCreateParamsFromFlags — rejects
bad `--name` values before any RPC. Empty name still passes
through so the daemon can generate one.
- internal/daemon/vm_create.go reserveVM — defense in depth for
any non-CLI RPC caller (SDK, direct JSON over the socket).
Tests:
- internal/model/vm_name_test.go — exhaustive character-class
matrix (space, newline, tab, dot, slash, colon, equals, quote,
control chars, unicode letters, uppercase, leading/trailing
hyphen, over-length, max-length-exact, digits-only).
- internal/cli TestVMCreateParamsFromFlagsRejectsInvalidName —
CLI wire-through + empty-name passthrough.
- internal/daemon TestReserveVMRejectsInvalidName — daemon
defense-in-depth (including `box/../evil` path-traversal).
- scripts/smoke.sh — end-to-end rejection + no-leaked-row
assertion.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
700a1e6e60
commit
caa6a2b996
7 changed files with 225 additions and 0 deletions
|
|
@ -561,6 +561,27 @@ set -e
|
|||
post_vms="$("$BANGER" vm list --all 2>/dev/null | wc -l)"
|
||||
[[ "$pre_vms" == "$post_vms" ]] || die "invalid spec leaked a VM row: pre=$pre_vms, post=$post_vms"
|
||||
|
||||
# --- invalid name rejection ------------------------------------------
|
||||
# VM names become DNS labels, guest hostnames, kernel-cmdline tokens
|
||||
# and file-path fragments — the validator (ValidateVMName) must reject
|
||||
# anything that isn't [a-z0-9-] with no leading/trailing hyphen and no
|
||||
# dots. Smoke covers a few of the worst offenders end-to-end through
|
||||
# the CLI; the full character-class matrix lives in
|
||||
# internal/model/vm_name_test.go. Rejected names must also leave no
|
||||
# VM row behind.
|
||||
log 'invalid name rejection: uppercase / space / dot / leading-hyphen must all fail'
|
||||
pre_vms="$("$BANGER" vm list --all 2>/dev/null | wc -l)"
|
||||
for bad in 'MyBox' 'my box' 'box.vm' '-box'; do
|
||||
set +e
|
||||
"$BANGER" vm create --name "$bad" --no-start >/dev/null 2>&1
|
||||
rc=$?
|
||||
set -e
|
||||
[[ "$rc" -ne 0 ]] || die "invalid name: vm create accepted '$bad'"
|
||||
done
|
||||
post_vms="$("$BANGER" vm list --all 2>/dev/null | wc -l)"
|
||||
[[ "$pre_vms" == "$post_vms" ]] \
|
||||
|| die "invalid name leaked VM row(s): pre=$pre_vms, post=$post_vms"
|
||||
|
||||
# --- daemon stop (flushes coverage) -----------------------------------
|
||||
log 'stopping daemon so instrumented binaries flush coverage'
|
||||
"$BANGER" daemon stop >/dev/null 2>&1 || true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue