]> git.proxmox.com Git - qemu-server.git/commitdiff
ovmf: support secure boot with 4m and 4m-ms efidisk types
authorStefan Reiter <s.reiter@proxmox.com>
Tue, 5 Oct 2021 16:02:06 +0000 (18:02 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Tue, 5 Oct 2021 16:04:03 +0000 (18:04 +0200)
Provide support for secure boot by using the new "4m" and "4m-ms"
variants of the OVMF code/vars templates. This is specified on the
efidisk via the 'efitype' and 'ms-keys' parameters.

Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
PVE/API2/Qemu.pm
PVE/QemuServer.pm
PVE/QemuServer/Drive.pm

index 367d6ca5a3c08bbee1964c19a2f2fbb1c57caf5f..cc2a543e0d889d4e3edea02c7121e8042683d633 100644 (file)
@@ -183,7 +183,8 @@ my $create_disks = sub {
 
            my $volid;
            if ($ds eq 'efidisk0') {
-               ($volid, $size) = PVE::QemuServer::create_efidisk($storecfg, $storeid, $vmid, $fmt, $arch);
+               ($volid, $size) = PVE::QemuServer::create_efidisk(
+                   $storecfg, $storeid, $vmid, $fmt, $arch, $disk);
            } elsif ($ds eq 'tpmstate0') {
                # swtpm can only use raw volumes, and uses a fixed size
                $size = PVE::Tools::convert_size(PVE::QemuServer::Drive::TPMSTATE_DISK_SIZE, 'b' => 'kb');
index 076ce59f4c9c26b3b07b3be30d199bd952dd4dc8..3c0ecf5946a8753d5b7dbb34501ce10002db792d 100644 (file)
@@ -63,14 +63,26 @@ eval {
 
 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
 my $OVMF = {
-    x86_64 => [
-       "$EDK2_FW_BASE/OVMF_CODE.fd",
-       "$EDK2_FW_BASE/OVMF_VARS.fd"
-    ],
-    aarch64 => [
-       "$EDK2_FW_BASE/AAVMF_CODE.fd",
-       "$EDK2_FW_BASE/AAVMF_VARS.fd"
-    ],
+    x86_64 => {
+       '4m' => [
+           "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
+           "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
+       ],
+       '4m-ms' => [
+           "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
+           "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
+       ],
+       default => [
+           "$EDK2_FW_BASE/OVMF_CODE.fd",
+           "$EDK2_FW_BASE/OVMF_VARS.fd",
+       ],
+    },
+    aarch64 => {
+       default => [
+           "$EDK2_FW_BASE/AAVMF_CODE.fd",
+           "$EDK2_FW_BASE/AAVMF_VARS.fd",
+       ],
+    },
 };
 
 my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
@@ -3140,13 +3152,18 @@ sub get_vm_machine {
     return $machine;
 }
 
-sub get_ovmf_files($) {
-    my ($arch) = @_;
+sub get_ovmf_files($$) {
+    my ($arch, $efidisk) = @_;
 
-    my $ovmf = $OVMF->{$arch}
+    my $types = $OVMF->{$arch}
        or die "no OVMF images known for architecture '$arch'\n";
 
-    return @$ovmf;
+    my $type = 'default';
+    if (defined($efidisk->{efitype}) && $efidisk->{efitype} eq '4m') {
+       $type = $efidisk->{'ms-keys'} ? "4m-ms" : "4m";
+    }
+
+    return $types->{$type}->@*;
 }
 
 my $Arch2Qemu = {
@@ -3405,13 +3422,17 @@ sub config_to_command {
     }
 
     if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
-       my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch);
+       my $d;
+       if (my $efidisk = $conf->{efidisk0}) {
+           $d = parse_drive('efidisk0', $efidisk);
+       }
+
+       my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch, $d);
        die "uefi base image '$ovmf_code' not found\n" if ! -f $ovmf_code;
 
        my ($path, $format);
        my $read_only_str = '';
-       if (my $efidisk = $conf->{efidisk0}) {
-           my $d = parse_drive('efidisk0', $efidisk);
+       if ($d) {
            my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
            $format = $d->{format};
            if ($storeid) {
@@ -7516,7 +7537,8 @@ sub qemu_use_old_bios_files {
 sub get_efivars_size {
     my ($conf) = @_;
     my $arch = get_vm_arch($conf);
-    my (undef, $ovmf_vars) = get_ovmf_files($arch);
+    my $efidisk = $conf->{efidisk0} ? parse_drive('efidisk0', $conf->{efidisk0}) : undef;
+    my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk);
     die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
     return -s $ovmf_vars;
 }
@@ -7541,10 +7563,10 @@ sub update_tpmstate_size {
     $conf->{tpmstate0} = print_drive($disk);
 }
 
-sub create_efidisk($$$$$) {
-    my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
+sub create_efidisk($$$$$$) {
+    my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk) = @_;
 
-    my (undef, $ovmf_vars) = get_ovmf_files($arch);
+    my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk);
     die "EFI vars default image not found\n" if ! -f $ovmf_vars;
 
     my $vars_size_b = -s $ovmf_vars;
index 6389dbb2967df7c5079b9b40242de9c7eeca5655..57d26f59af46872d9468c0ca5ca75ce52d1fc0ea 100644 (file)
@@ -306,6 +306,26 @@ my $virtiodesc = {
 };
 PVE::JSONSchema::register_standard_option("pve-qm-virtio", $virtiodesc);
 
+my %efitype_fmt = (
+    efitype => {
+       type => 'string',
+       enum => [qw(2m 4m)],
+       description => "Size and type of the OVMF EFI vars. '4m' is newer and recommended,"
+           . " and required for Secure Boot. For backwards compatibility, '2m' is used"
+           . " if not otherwise specified.",
+       optional => 1,
+       default => '2m',
+    },
+    'ms-keys' => {
+       type => 'boolean',
+       description => "Pre-enroll the Microsoft Standard UEFI Secure Boot keys if"
+           . " used with 'efitype=4m'. Note that this will enable Secure Boot by"
+           . " default, though it can still be turned off from within the VM.",
+       optional => 1,
+       default => 0,
+    },
+);
+
 my $efidisk_fmt = {
     volume => { alias => 'file' },
     file => {
@@ -323,6 +343,7 @@ my $efidisk_fmt = {
        description => "Disk size. This is purely informational and has no effect.",
        optional => 1,
     },
+    %efitype_fmt,
 };
 
 my $efidisk_desc = {
@@ -382,6 +403,7 @@ my $alldrive_fmt = {
     %ssd_fmt,
     %wwn_fmt,
     %tpmversion_fmt,
+    %efitype_fmt,
 };
 
 my $unused_fmt = {