Microsoft's UEFI CA 2011 will expire in June 2026. It's necessary to ensure that the new UEFI CA 2023 is enrolled for Windows to keep updates working.
pve-edk2-firmware >= 4.2025.05-1 includes the 2023 certificate already, so new disks are fine. Still, check during EFI disk creation what is actually there, since there is no guarantee that a new enough version of pve-edk2-firmware is installed. A new 'ms-cert' drive property for EFI disks records the year of the last known-to-be-enrolled MS UEFI CA. This avoids the need to re-check every time if the 2023 certificate needs to be enrolled. The downside is that this breaks backwards migration, because a disk with an unknown option is dropped from the configuration. Enrollment and checking for existing disks is done via virt-fw-vars, which is a new dependency recorded in d/control. While virt-fw-vars supports raw and qcow2 files out of the box, this is not enough, because EFI disks can also be vmdk formatted and there are also storages that use a protocol path like 'rbd://' or 'iscsi://' for QEMU, which virt-fw-vars cannot handle. Thus, use a FUSE export to cover all cases. Signed-off-by: Fiona Ebner <[email protected]> --- Changes in v2: * Rebase on current master. * Add comment that ensure_ms_2023_cert_enrolled() helper can currently only be called as part of the VM start task, because it uses the main QSD instance associated to the VM. debian/control | 1 + src/PVE/QemuServer.pm | 20 ++++++++++++ src/PVE/QemuServer/Drive.pm | 9 ++++++ src/PVE/QemuServer/OVMF.pm | 61 +++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/debian/control b/debian/control index 78188c2c..d439d58b 100644 --- a/debian/control +++ b/debian/control @@ -58,6 +58,7 @@ Depends: conntrack, pve-firewall (>= 6.0.3), pve-ha-manager (>= 5.0.3), pve-qemu-kvm (>= 7.1~), + python3-virt-firmware, socat, swtpm, swtpm-tools, diff --git a/src/PVE/QemuServer.pm b/src/PVE/QemuServer.pm index bac29ac9..42f1bf49 100644 --- a/src/PVE/QemuServer.pm +++ b/src/PVE/QemuServer.pm @@ -5406,6 +5406,24 @@ sub generate_storage_hints { return $hints; } +my sub check_efi_vars { + my ($storecfg, $vmid, $conf) = @_; + + return if PVE::QemuConfig->is_template($conf); + return if !$conf->{efidisk0}; + return if $conf->{ostype} ne 'win10' && $conf->{ostype} ne 'win11'; + + if ( + my $updated = PVE::QemuServer::OVMF::ensure_ms_2023_cert_enrolled( + $storecfg, $vmid, $conf->{efidisk0}, + ) + ) { + $conf->{efidisk0} = $updated; + PVE::QemuConfig->write_config($vmid, $conf); + } + return; +} + # see vm_start_nolock for parameters, additionally: # migrate_opts: # storagemap = parsed storage map for allocating NBD disks @@ -5583,6 +5601,8 @@ sub vm_start_nolock { my $storage_hints = generate_storage_hints($conf, 1); PVE::Storage::activate_volumes($storecfg, $vollist, undef, $storage_hints); + check_efi_vars($storecfg, $vmid, $conf) if $conf->{bios} && $conf->{bios} eq 'ovmf'; + # Note that for certain cases like templates, the configuration is minimized, so need to ensure # the rest of the function here uses the same configuration that was used to build the command ($cmd, $spice_port, my $pci_devices, $conf) = config_to_command( diff --git a/src/PVE/QemuServer/Drive.pm b/src/PVE/QemuServer/Drive.pm index f54f9612..c772c803 100644 --- a/src/PVE/QemuServer/Drive.pm +++ b/src/PVE/QemuServer/Drive.pm @@ -521,6 +521,15 @@ my %efitype_fmt = ( optional => 1, default => 0, }, + 'ms-cert' => { + type => 'string', + enum => [qw(2011 2023)], + description => + "Informational marker indicating the version of the latest Microsof UEFI certificate" + . " that has been enrolled by Proxmox VE.", + optional => 1, + default => '2011', + }, ); my $efidisk_fmt = { diff --git a/src/PVE/QemuServer/OVMF.pm b/src/PVE/QemuServer/OVMF.pm index aa88bfa6..c258ae50 100644 --- a/src/PVE/QemuServer/OVMF.pm +++ b/src/PVE/QemuServer/OVMF.pm @@ -11,7 +11,9 @@ use PVE::Tools; use PVE::QemuServer::Blockdev; use PVE::QemuServer::Drive qw(checked_volume_format parse_drive print_drive); +use PVE::QemuServer::Helpers; use PVE::QemuServer::QemuImage; +use PVE::QemuServer::QSD; my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/'; my $OVMF = { @@ -139,6 +141,30 @@ sub get_efivars_size { return -s $ovmf_vars; } +my sub is_ms_2023_cert_enrolled { + my ($path) = @_; + + my $inside_db_section; + my $found_ms_2023_cert; + + my $detect_ms_2023_cert = sub { + my ($line) = @_; + return if $found_ms_2023_cert; + $inside_db_section = undef if !$line; + $found_ms_2023_cert = 1 + if $inside_db_section && $line =~ m/CN=Microsoft UEFI CA 2023/; + $inside_db_section = 1 if $line =~ m/^name=db guid=guid:EfiImageSecurityDatabase/; + return; + }; + + PVE::Tools::run_command( + ['virt-fw-vars', '--input', $path, '--print', '--verbose'], + outfunc => $detect_ms_2023_cert, + ); + + return $found_ms_2023_cert; +} + sub create_efidisk($$$$$$$$) { my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk, $smm, $cvm_type) = @_; @@ -152,6 +178,10 @@ sub create_efidisk($$$$$$$$) { PVE::QemuServer::QemuImage::convert($ovmf_vars, $volid, $vars_size_b); my $size = PVE::Storage::volume_size_info($storecfg, $volid, 3); + if ($efidisk->{'pre-enrolled-keys'} && is_ms_2023_cert_enrolled($ovmf_vars)) { + $efidisk->{'ms-cert'} = '2023' + } + return ($volid, $size / 1024); } @@ -248,4 +278,35 @@ sub print_ovmf_commandline { return ($cmd, $machine_flags); } +# May only be called as part of VM start right now, because it uses the main QSD associated to the +# VM. If required for another scenario, change the QSD ID to something else. +sub ensure_ms_2023_cert_enrolled { + my ($storecfg, $vmid, $efidisk_str) = @_; + + my $efidisk = parse_drive('efidisk0', $efidisk_str); + return if !$efidisk->{'pre-enrolled-keys'}; + return if $efidisk->{'ms-cert'} && $efidisk->{'ms-cert'} eq '2023'; + + print "efidisk0: enrolling Microsoft UEFI CA 2023\n"; + + my $new_qsd = !PVE::QemuServer::Helpers::qsd_running_locally($vmid); + PVE::QemuServer::QSD::start($vmid) if $new_qsd; + + eval { + my $efi_vars_path = + PVE::QemuServer::QSD::add_fuse_export($vmid, $efidisk, 'efidisk0-enroll'); + PVE::Tools::run_command( + ['virt-fw-vars', '--inplace', $efi_vars_path, '--distro-keys', 'ms-uefi']); + PVE::QemuServer::QSD::remove_fuse_export($vmid, 'efidisk0-enroll'); + }; + my $err = $@; + + PVE::QemuServer::QSD::quit($vmid) if $new_qsd; + + die "efidisk0: enrolling Microsoft UEFI CA 2023 failed - $err" if $err; + + $efidisk->{'ms-cert'} = '2023'; + return print_drive($efidisk); +} + 1; -- 2.47.3 _______________________________________________ pve-devel mailing list [email protected] https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
