Re: [pve-devel] [PATCH qemu-server v10 2/4] config: add AMD SEV support
comments inline: On 5/10/24 13:47, Markus Frank wrote: This patch is for enabling AMD SEV (Secure Encrypted Virtualization) support in QEMU. VM-Config-Examples: amd_sev: type=std,no-debug=1,no-key-sharing=1 amd_sev: es,no-debug=1,kernel-hashes=1 kernel-hashes, reduced-phys-bios & cbitpos correspond to the variables with the same name in QEMU. kernel-hashes=1 adds kernel-hashes to enable measured linux kernel launch since it is per default off for backward compatibility. reduced-phys-bios and cbitpos are system specific and are read out by the query-machine-capabilities.service on boot and saved to the /run/qemu-server/host-hw-capabilities.json file. This file is parsed and than used by qemu-server to correctly start a AMD SEV VM. type=std stands for standard sev to differentiate it from sev-es (es) or sev-snp (snp) when support is upstream. QEMU's sev-guest policy gets calculated with the parameters nodbg & noks. These parameters correspond to policy-bits 0 & 1. If type is 'es' than policy-bit 2 gets set to 1 to activate SEV-ES. Policy bit 3 (nosend) is always set to 1, because migration features for sev are not upstream yet and are attackable. SEV-ES is highly experimental since it could not be tested. see coherent doc patch Signed-off-by: Markus Frank --- changes v10: * also die if the BIOS is not set, since the default is SeaBIOS PVE/API2/Qemu.pm | 11 +++ PVE/QemuMigrate.pm | 4 +++ PVE/QemuServer.pm | 79 ++ 3 files changed, 94 insertions(+) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 2a349c8..c29809d 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -4512,6 +4512,11 @@ __PACKAGE__->register_method({ push $local_resources->@*, "clipboard=vnc"; } + # do not allow live migration with AMD SEV enabled + if ($res->{running} && $vmconf->{amd_sev}) { + push $local_resources->@*, "amd_sev"; + } + # if vm is not running, return target nodes where local storage/mapped devices are available # for offline migration if (!$res->{running}) { @@ -5192,6 +5197,12 @@ __PACKAGE__->register_method({ die "unable to use snapshot name 'pending' (reserved name)\n" if lc($snapname) eq 'pending'; + my $conf = PVE::QemuConfig->load_config($vmid); + if ($param->{vmstate} && $conf->{amd_sev}) { + die "Snapshots that include memory are not supported while memory" + ." is encrypted by AMD SEV.\n" + } + you do it for snapshots, but it's missing for suspend to disk, where we basically migrate into a file my $realcmd = sub { PVE::Cluster::log_msg('info', $authuser, "snapshot VM $vmid: $snapname"); PVE::QemuConfig->snapshot_create($vmid, $snapname, $param->{vmstate}, diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm index 8d9b35a..340402a 100644 --- a/PVE/QemuMigrate.pm +++ b/PVE/QemuMigrate.pm @@ -260,6 +260,10 @@ sub prepare { die "VMs with 'clipboard' set to 'vnc' are not live migratable!\n"; } +if ($running && $conf->{'amd_sev'}) { + die "cannot live-migrate VM when AMD SEV is enabled.\n"; +} + my $vollist = PVE::QemuServer::get_vm_volumes($conf); my $storages = {}; diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 82e7d6a..92960c5 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -177,6 +177,37 @@ my $agent_fmt = { }, }; +my $sev_fmt = { +type => { + description => "Enable standard SEV with type='std' or enable" + ." experimental SEV-ES with the 'es' option.", + type => 'string', + default_key => 1, + format_description => "sev-type", + enum => ['std', 'es'], + maxLength => 3, +}, +'no-debug' => { + description => "Sets policy bit 0 to 1 to disallow debugging of guest", + type => 'boolean', + default => 0, + optional => 1, +}, +'no-key-sharing' => { + description => "Sets policy bit 1 to 1 to disallow key sharing with other guests", + type => 'boolean', + default => 0, + optional => 1, +}, +"kernel-hashes" => { + description => "Add kernel hashes to guest firmware for measured linux kernel launch", + type => 'boolean', + default => 0, + optional => 1, +}, +}; +PVE::JSONSchema::register_format('pve-qemu-sev-fmt', $sev_fmt); + my $vga_fmt = { type => { description => "Select the VGA type.", @@ -358,6 +389,12 @@ my $confdesc = { description => "Memory properties.", format => $PVE::QemuServer::Memory::memory_fmt }, +amd_sev => { + description => "Secure Encrypted Virtualization (SEV) features by AMD CPUs", + optional => 1, + format => 'pve-qemu-sev-fmt', + type => 'string', +}, balloon => { optional => 1, type => 'integer', @@ -4091,6 +4128,39 @@ sub
[pve-devel] [PATCH qemu-server v10 2/4] config: add AMD SEV support
This patch is for enabling AMD SEV (Secure Encrypted Virtualization) support in QEMU. VM-Config-Examples: amd_sev: type=std,no-debug=1,no-key-sharing=1 amd_sev: es,no-debug=1,kernel-hashes=1 kernel-hashes, reduced-phys-bios & cbitpos correspond to the variables with the same name in QEMU. kernel-hashes=1 adds kernel-hashes to enable measured linux kernel launch since it is per default off for backward compatibility. reduced-phys-bios and cbitpos are system specific and are read out by the query-machine-capabilities.service on boot and saved to the /run/qemu-server/host-hw-capabilities.json file. This file is parsed and than used by qemu-server to correctly start a AMD SEV VM. type=std stands for standard sev to differentiate it from sev-es (es) or sev-snp (snp) when support is upstream. QEMU's sev-guest policy gets calculated with the parameters nodbg & noks. These parameters correspond to policy-bits 0 & 1. If type is 'es' than policy-bit 2 gets set to 1 to activate SEV-ES. Policy bit 3 (nosend) is always set to 1, because migration features for sev are not upstream yet and are attackable. SEV-ES is highly experimental since it could not be tested. see coherent doc patch Signed-off-by: Markus Frank --- changes v10: * also die if the BIOS is not set, since the default is SeaBIOS PVE/API2/Qemu.pm | 11 +++ PVE/QemuMigrate.pm | 4 +++ PVE/QemuServer.pm | 79 ++ 3 files changed, 94 insertions(+) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 2a349c8..c29809d 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -4512,6 +4512,11 @@ __PACKAGE__->register_method({ push $local_resources->@*, "clipboard=vnc"; } + # do not allow live migration with AMD SEV enabled + if ($res->{running} && $vmconf->{amd_sev}) { + push $local_resources->@*, "amd_sev"; + } + # if vm is not running, return target nodes where local storage/mapped devices are available # for offline migration if (!$res->{running}) { @@ -5192,6 +5197,12 @@ __PACKAGE__->register_method({ die "unable to use snapshot name 'pending' (reserved name)\n" if lc($snapname) eq 'pending'; + my $conf = PVE::QemuConfig->load_config($vmid); + if ($param->{vmstate} && $conf->{amd_sev}) { + die "Snapshots that include memory are not supported while memory" + ." is encrypted by AMD SEV.\n" + } + my $realcmd = sub { PVE::Cluster::log_msg('info', $authuser, "snapshot VM $vmid: $snapname"); PVE::QemuConfig->snapshot_create($vmid, $snapname, $param->{vmstate}, diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm index 8d9b35a..340402a 100644 --- a/PVE/QemuMigrate.pm +++ b/PVE/QemuMigrate.pm @@ -260,6 +260,10 @@ sub prepare { die "VMs with 'clipboard' set to 'vnc' are not live migratable!\n"; } +if ($running && $conf->{'amd_sev'}) { + die "cannot live-migrate VM when AMD SEV is enabled.\n"; +} + my $vollist = PVE::QemuServer::get_vm_volumes($conf); my $storages = {}; diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 82e7d6a..92960c5 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -177,6 +177,37 @@ my $agent_fmt = { }, }; +my $sev_fmt = { +type => { + description => "Enable standard SEV with type='std' or enable" + ." experimental SEV-ES with the 'es' option.", + type => 'string', + default_key => 1, + format_description => "sev-type", + enum => ['std', 'es'], + maxLength => 3, +}, +'no-debug' => { + description => "Sets policy bit 0 to 1 to disallow debugging of guest", + type => 'boolean', + default => 0, + optional => 1, +}, +'no-key-sharing' => { + description => "Sets policy bit 1 to 1 to disallow key sharing with other guests", + type => 'boolean', + default => 0, + optional => 1, +}, +"kernel-hashes" => { + description => "Add kernel hashes to guest firmware for measured linux kernel launch", + type => 'boolean', + default => 0, + optional => 1, +}, +}; +PVE::JSONSchema::register_format('pve-qemu-sev-fmt', $sev_fmt); + my $vga_fmt = { type => { description => "Select the VGA type.", @@ -358,6 +389,12 @@ my $confdesc = { description => "Memory properties.", format => $PVE::QemuServer::Memory::memory_fmt }, +amd_sev => { + description => "Secure Encrypted Virtualization (SEV) features by AMD CPUs", + optional => 1, + format => 'pve-qemu-sev-fmt', + type => 'string', +}, balloon => { optional => 1, type => 'integer', @@ -4091,6 +4128,39 @@ sub config_to_command { } } +if ($conf->{amd_sev}) { + if (!$conf->{bios} || ($conf->{bios} && $conf->{bios} ne 'ovmf')) { + die "For using SEV you need to