fix: improve swtpm error handling for libvirt TPM permission issue

vm_create now properly detects the swtpm CMD_INIT failure and prints
the exact sudo command needed to fix the libvirt-qemu ownership issue
that Debian's libvirt swtpm helper creates as root:root.

Changes:
- vm_setup_swtpm: simplified to just check prerequisites (swtpm installed,
  /var/lib/libvirt/swtpm/ exists)
- vm_create: after failed start, detects if swtpm dir was created by
  libvirt and prints targeted fix command
- vm_destroy: simplified (removed external swtpm socket management)
- Auto-cleanup: undefines VM on TPM failure so user can retry immediately

Root cause: libvirt's swtpm helper creates per-VM state directories as
root:root but swtpm runs as libvirt-qemu. Needs one-time:
  sudo chown -R libvirt-qemu:libvirt-qemu /var/lib/libvirt/swtpm/

All 523 tests pass, 0 lint warnings.

💘 Generated with Crush

Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
2026-05-07 12:59:22 -05:00
parent 88d670efbe
commit 8d59694eef

53
run.sh
View File

@@ -165,51 +165,28 @@ vm_check_prerequisites() {
return 0
}
# Setup swtpm state for libvirt TPM emulation
# Setup swtpm for libvirt TPM emulation
# Returns 0 if TPM is available, 1 if not
# Uses libvirt's built-in swtpm management which handles the full lifecycle.
# Requires /var/lib/libvirt/swtpm/ to exist with correct ownership.
vm_setup_swtpm() {
local swtpm_state_dir="/var/lib/libvirt/swtpm/${VM_NAME}"
# Check if swtpm is installed
if ! command -v swtpm_setup &> /dev/null; then
log_warn "swtpm_setup not found - VM will run without TPM"
return 1
fi
# Try to create and initialize swtpm state directory
# For system libvirt, this lives under /var/lib/libvirt/swtpm/
# For system libvirt, check prerequisites
if [[ "$LIBVIRT_URI" == *"system"* ]]; then
# Check if the base directory exists and is writable
if [[ ! -d "/var/lib/libvirt/swtpm" ]]; then
# Try to create it (may fail without root)
if ! mkdir -p "/var/lib/libvirt/swtpm" 2>/dev/null; then
log_warn "Cannot create /var/lib/libvirt/swtpm/ (needs sudo)"
log_warn "Fix: sudo mkdir -p /var/lib/libvirt/swtpm && sudo chown libvirt-qemu:libvirt-qemu /var/lib/libvirt/swtpm"
log_warn "VM will be created WITHOUT TPM"
return 1
fi
fi
# Try to create VM-specific state dir
if ! mkdir -p "$swtpm_state_dir" 2>/dev/null; then
log_warn "Cannot create swtpm state dir: $swtpm_state_dir"
log_warn "Fix: sudo mkdir -p $swtpm_state_dir && sudo chown -R libvirt-qemu:libvirt-qemu $swtpm_state_dir"
log_warn "/var/lib/libvirt/swtpm/ does not exist"
log_warn "Fix: sudo mkdir -p /var/lib/libvirt/swtpm && sudo chown libvirt-qemu:libvirt-qemu /var/lib/libvirt/swtpm"
log_warn "VM will be created WITHOUT TPM"
return 1
fi
# Try to initialize TPM state
if ! swtpm_setup --tpm-state "$swtpm_state_dir" --tpm2 --createek --allow-signing --pcr-banks sha256 2>/dev/null; then
log_warn "swtpm_setup failed - VM will run without TPM"
rm -rf "$swtpm_state_dir" 2>/dev/null || true
return 1
fi
# Fix ownership for libvirt-qemu
chown -R libvirt-qemu:libvirt-qemu "$swtpm_state_dir" 2>/dev/null || true
fi
log_info "swtpm initialized successfully"
log_info "swtpm prerequisites satisfied"
return 0
}
@@ -324,6 +301,21 @@ vm_create() {
# Start the VM
log_info "Starting VM..."
if ! virsh -c "$LIBVIRT_URI" start "$VM_NAME"; then
# Check if failure was due to swtpm permissions
if [[ -n "$tpm_section" && "$LIBVIRT_URI" == *"system"* ]]; then
local vm_uuid
vm_uuid=$(virsh -c "$LIBVIRT_URI" dominfo "$VM_NAME" 2>/dev/null | grep "UUID:" | awk '{print $2}')
local swtpm_vm_dir="/var/lib/libvirt/swtpm/${vm_uuid}"
if [[ -d "$swtpm_vm_dir" ]]; then
log_error "TPM initialization failed - likely a swtpm permission issue"
log_error "Libvirt created swtpm state dir as root: $swtpm_vm_dir"
log_error "Fix by running:"
log_error " sudo chown -R libvirt-qemu:libvirt-qemu /var/lib/libvirt/swtpm/"
log_error "Then retry: ./run.sh test:iso destroy && ./run.sh test:iso create"
# Undefine so user can retry after fixing
virsh -c "$LIBVIRT_URI" undefine "$VM_NAME" --nvram 2>/dev/null || true
fi
fi
log_error "Failed to start VM"
return 1
fi
@@ -386,7 +378,6 @@ vm_destroy() {
# Cleanup all VM files (ISO is preserved in output/)
rm -f /tmp/${VM_NAME}*.qcow2 /tmp/${VM_NAME}*.iso /tmp/${VM_NAME}*.xml /tmp/${VM_NAME}*.fd 2>/dev/null || true
rm -rf /var/lib/libvirt/swtpm/${VM_NAME} 2>/dev/null || true
log_info "Cleanup complete (ISO preserved in output/)"
}