vm: validate cached disk images before reuse (docker-vm, truenas-vm) - #16243
vm: validate cached disk images before reuse (docker-vm, truenas-vm)#16243Ali-Shaikh wants to merge 2 commits into
Conversation
Both scripts treat any non-empty file in the image cache as a good
download:
if [[ ! -s "$CACHE_FILE" ]]; then
curl -f#SL -o "$CACHE_FILE" "$URL"
curl writes as it streams, so an interrupted transfer leaves a partial
image at the cache path. It is non-empty, so every later run reports
"Using cached image" and builds a VM from a truncated disk. Interrupting
a Debian cloud image download after three seconds leaves 1.2 MB standing
in for a ~350 MB image, and nothing ever re-downloads it.
Neither script verifies the image either, and because the vendor URLs
are "latest"/"current" the basename never changes, so a security-updated
upstream image is never picked up.
Fixed by following the pattern download_and_validate_xz() already uses in
haos-vm.sh and umbrel-os-vm.sh - validate the cached file, delete and
retry when it is bad:
- download to "$CACHE_FILE.part" and rename only after validation, so a
partial transfer is never cached
- verify against the checksum the vendor publishes next to the image:
SHA512SUMS (Debian), SHA256SUMS (Ubuntu), .sha256 sidecar (TrueNAS)
- validate the cached file on reuse, deleting it on mismatch
Verification degrades gracefully by design: an unreachable checksum file,
a changed vendor layout, or an image absent from the list all proceed as
before. Only a definite mismatch aborts, so this cannot break VM creation
if a vendor reorganises their mirror.
asylumexp
left a comment
There was a problem hiding this comment.
this should be a func inside vm-core and not defined in each vm script
Per review, the checksum helpers belong in the shared library rather than
being defined in each VM script.
misc/vm-core.func gains three functions:
get_checksum_source - maps an image URL to the checksum the vendor
publishes, and its format
verify_image_checksum - best-effort verification, mismatch only fails
download_and_validate_image - cached-copy validation plus an atomic
download through a .part file
docker-vm.sh now calls download_and_validate_image and carries no
validation logic of its own.
truenas-vm.sh is reverted to its current state in this PR. It sources only
api.func, and vm-core.func applies "set -euo pipefail" at source time,
which truenas-vm.sh is not written for - it runs under plain "set -e" and
has pipelines and optional variables that "set -u" and "pipefail" would
change the behaviour of. Wiring it up is a larger change than this fix
warrants, so it is left for a follow-up.
The TrueNAS sidecar format is kept in get_checksum_source so that
follow-up is a one-line call.
|
Thanks — moved into One judgement call I'd like your view on: I've dropped It sources only So this PR now fixes
I've kept the TrueNAS sidecar format in Re-tested after the move — mismatch detection against live Debian, Ubuntu and TrueNAS checksum endpoints, and the four degradation paths (unknown vendor, checksum 404, image absent from listing, sidecar 404) all still pass through untouched. |
✍️ Description
vm/docker-vm.shandvm/truenas-vm.shtreat any non-empty file in the image cache as a completed download:curlwrites as it streams, so an interrupted transfer leaves a partial image at the cache path. It is non-empty, so-sis satisfied and every later run reports "Using cached image" and builds a VM from a truncated disk. Nothing ever re-downloads it.Interrupting a Debian cloud image download after three seconds:
1.2 MB standing in for a ~350 MB image, cached permanently.
Two related gaps: neither script verifies the image it imports, and because the vendor URLs are
latest/currentthe basename never changes, so a security-updated upstream image is never picked up.Fix
haos-vm.shandumbrel-os-vm.shalready solve this withdownload_and_validate_xz()— validate the cached file, delete and re-download when bad. This applies the same pattern to the two scripts that lack it:"$CACHE_FILE.part", rename only after validation, so a partial transfer is never cacheddocker-vm.shSHA512SUMSin the image directorydocker-vm.shSHA256SUMSin the image directorytruenas-vm.sh.sha256sidecar next to the ISOVerification degrades gracefully
This cannot break VM creation if a vendor reorganises their mirror. An unreachable checksum file, a changed layout, or an image absent from the list all proceed exactly as before. Only a definite hash mismatch aborts.
Testing done
Checksum logic exercised against live vendor endpoints:
Atomic download, A/B against current
main:Checksum URL derivation verified for Debian generic/nocloud and Ubuntu
current; live hash extraction returns a 128-char SHA512 for Debian and 64-char SHA256 for Ubuntu, covering both the Debian<hash> <file>and Ubuntu<hash> *<file>formats.bash -nandshellcheck -S warningclean apart from pre-existing findings (SC1090on thesource <(curl ...)lines, the UTF-8 BOM intruenas-vm.sh).Tested end-to-end on a Proxmox VE node, covering all three paths:
Clean download with an empty cache — image downloaded, verified against
SHA512SUMS, VM built normally.Cached reuse — second run verified the existing cached image and reported
Using cached image, no needless re-download.Corrupted cache — cached image truncated to 50 MB, then re-run. Detected and re-downloaded:
On current
mainthat same truncated file is silently used to build the VM.🔗 Related Issue
N/A — found while reading the VM scripts, no existing issue.
✅ Prerequisites (X in brackets)
🤖 AI Assistance (X in brackets)
AGENTS.mdand.github/agents/pve-script-creator.agent.mdas guidance, and the output has been reviewed and corrected to match those guidelines.🛠️ Type of Change (X in brackets)
README,AppName.md,CONTRIBUTING.md, or other docs.