Re: [pve-devel] [PATCH qemu-server v10 2/4] config: add AMD SEV support

2024-05-17 Thread Dominik Csapak

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

2024-05-10 Thread Markus Frank
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