From: Michal Fox <me@dualfroz.com>
To: pve-devel@lists.proxmox.com
Subject: [PATCH manager] fix #7178: pve8to9: detect qcow2 TPM state volumes containing raw data
Date: Sun, 4 Oct 2026 17:05:18 +0000 [thread overview]
Message-ID: <20261004170518.7-1-me@dualfroz.com> (raw)
Before qemu-server 8.3.3, cloning a VM template with a raw TPM state on
a directory storage as linked clone created a qcow2 overlay for it.
swtpm_setup used that file as raw TPM state and, as it found no valid
state in it, overwrote it with a new one, turning it into a raw file
with a qcow2 name.
With Proxmox VE 9, the TPM state is attached with the format of the
volume name, so such a VM fails to start with 'Image is not in qcow2
format'. Since qemu-server 8.3.3, it also fails to start on Proxmox VE
8, as swtpm only accepts raw volumes there, but the VM might not have
been started since then.
Check the TPM state volumes of all VMs that are named as qcow2 and on
a file based storage for the qcow2 magic, and warn about those that do
not have it, with how to fix them, as described in the bug report.
Signed-off-by: Michal Fox <me@dualfroz.com>
---
Tested the new check with mocked VM configs and storage config, on a
directory storage with a linked clone TPM state overwritten with raw
data (which 'qemu-img info' reports as raw), a real qcow2 and a raw TPM
state, one on LVM, one with a missing file and one on a storage that
does not exist: only the first one is reported, the last two are
skipped with the error. With the detection disabled or always true, the
test fails.
This is for master, it also applies to stable-8 with a 3-way merge, as
only the context of the 'use' lines differs there.
PVE/CLI/pve8to9.pm | 48 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)
diff --git a/PVE/CLI/pve8to9.pm b/PVE/CLI/pve8to9.pm
index 7305a7b6..b147f56e 100644
--- a/PVE/CLI/pve8to9.pm
+++ b/PVE/CLI/pve8to9.pm
@@ -27,6 +27,7 @@ use PVE::Storage::Plugin;
use PVE::Tools qw(run_command split_list file_get_contents trim);
use PVE::QemuConfig;
use PVE::QemuServer;
+use PVE::QemuServer::Drive;
use PVE::QemuServer::Machine;
use PVE::QemuServer::Network;
use PVE::VZDump::Common;
@@ -1076,6 +1077,51 @@ my sub check_qemu_machine_versions {
}
}
+sub check_qemu_tpmstate_volumes {
+ log_info("Checking VM TPM state volumes for qcow2 files containing raw data..");
+
+ my $storecfg = PVE::Storage::config();
+ my $affected = [];
+
+ my $vms = PVE::QemuServer::config_list();
+ for my $vmid (sort { $a <=> $b } keys $vms->%*) {
+ my $conf = PVE::QemuConfig->load_config($vmid);
+ next if !$conf->{tpmstate0};
+
+ my $volid = PVE::QemuServer::Drive::parse_drive('tpmstate0', $conf->{tpmstate0})->{file};
+ eval {
+ my ($storeid) = PVE::Storage::parse_volume_id($volid);
+ my $format = (PVE::Storage::parse_volname($storecfg, $volid))[6];
+ my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
+ # only volumes on file based storages could end up like this
+ return if $format ne 'qcow2' || !$scfg->{path};
+
+ my $path = PVE::Storage::path($storecfg, $volid);
+ open(my $fh, '<', $path) or die "unable to open '$path' - $!\n";
+ my $magic = '';
+ read($fh, $magic, 4);
+ close($fh);
+
+ # before qemu-server 8.3.3, swtpm_setup used the qcow2 overlay of linked clones as raw
+ # file and overwrote it with a new state
+ push $affected->@*, "VM $vmid: $volid" if $magic ne "QFI\xfb";
+ };
+ log_skip("could not check TPM state volume '$volid' of VM $vmid - $@") if $@;
+ }
+
+ if (!scalar($affected->@*)) {
+ log_pass("No qcow2 TPM state volumes with raw data found.");
+ return;
+ }
+
+ log_warn(
+ "The TPM state volumes of the following VMs are qcow2 files that contain raw data, which"
+ . " happened with linked clones. Such a VM fails to start in Proxmox VE 9. Rename the"
+ . " file to end with '.raw' and adapt the 'tpmstate0' line of the VM config accordingly,"
+ . " also dropping the base volume, like '101/base-101-disk-2.raw/':\n\t"
+ . join("\n\t", $affected->@*));
+}
+
my sub check_max_length {
my ($raw, $max_length, $warning) = @_;
log_warn($warning) if defined($raw) && length($raw) > $max_length;
@@ -2098,6 +2144,8 @@ sub check_virtual_guests {
}
check_qemu_machine_versions();
+
+ check_qemu_tpmstate_volumes();
}
my $LEGACY_IPAM_DB = "/etc/pve/priv/ipam.db";
--
2.43.0
reply other threads:[~2026-10-04 17:05 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261004170518.7-1-me@dualfroz.com \
--to=me@dualfroz.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox