From: Dominik Csapak <d.csapak@proxmox.com>
To: Proxmox VE development discussion <pve-devel@lists.proxmox.com>,
Markus Frank <m.frank@proxmox.com>
Subject: Re: [pve-devel] [PATCH qemu-server v10 2/4] config: add AMD SEV support
Date: Fri, 17 May 2024 13:21:47 +0200 [thread overview]
Message-ID: <2a3f067a-adc3-4958-b8d8-1a70f8332616@proxmox.com> (raw)
In-Reply-To: <20240510114706.990385-3-m.frank@proxmox.com>
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 <m.frank@proxmox.com>
> ---
> 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 config_to_command {
> }
> }
>
> + if ($conf->{amd_sev}) {
> + if (!$conf->{bios} || ($conf->{bios} && $conf->{bios} ne 'ovmf')) {
> + die "For using SEV you need to change your guest bios to ovmf.\n";
> + }
> +
> + my $amd_sev_conf = parse_property_string($sev_fmt, $conf->{amd_sev});
> + my $sev_hw_caps = get_hw_capabilities()->{'amd-sev'};
> +
> + if (!$sev_hw_caps->{'sev-support'}) {
> + die "Your CPU does not support AMD SEV!\n";
> + }
> + if ($amd_sev_conf->{type} eq 'es' && !$sev_hw_caps->{'sev-support-es'}) {
> + die "Your CPU does not support AMD SEV-ES!\n";
> + }
> +
> + my $sev_mem_object = 'sev-guest,id=sev0'
> + .',cbitpos='.$sev_hw_caps->{cbitpos}
> + .',reduced-phys-bits='.$sev_hw_caps->{'reduced-phys-bits'};
> +
> + my $policy = 0b0;
> + $policy += 0b1 if ($amd_sev_conf->{'no-debug'});
> + $policy += 0b10 if ($amd_sev_conf->{'no-key-sharing'});
> + $policy += 0b100 if ($amd_sev_conf->{type} eq 'es');
> + # disable migration with bit 3 nosend to prevent amd-sev-migration-attack
> + $policy += 0b1000;
isn't it possible to keep the bitlength identically? makes it easier to compare
e.g. like this:
my $policy = 0b0000;
$policy += 0b0001 if ...
$policy += 0b0010 if ...
etc..
> +
> + $sev_mem_object .= ',policy='.sprintf("%#x", $policy);
> + $sev_mem_object .= ',kernel-hashes=on' if ($amd_sev_conf->{'kernel-hashes'});
> +
> + push @$devices, '-object' , $sev_mem_object;
> + push @$machineFlags, 'confidential-guest-support=sev0';
> + }
> +
also i'd prefer to put this whole block into e.g. PVE/QemuServer/CPUConfig
so 'config_to_command' does not get more bloated than it already is
> push @$cmd, @$devices;
> push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
> push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
> @@ -4134,6 +4204,15 @@ sub check_rng_source {
> }
> }
>
> +sub get_hw_capabilities {
> + # Get reduced-phys-bits & cbitpos from host-hw-capabilities.json
> + my $filename = '/run/qemu-server/host-hw-capabilities.json';
> + my $json_text = PVE::Tools::file_get_contents($filename);
> + ($json_text) = $json_text =~ /(.*)/; # untaint json text
> + my $hw_capabilities = decode_json($json_text);
> + return $hw_capabilities;
> +}
> +
also this maybe? though it could also live in 'Helpers'
> sub spice_port {
> my ($vmid) = @_;
>
_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
next prev parent reply other threads:[~2024-05-17 11:21 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-10 11:47 [pve-devel] [PATCH qemu-server/docs/manager v10 0/4] AMD SEV Markus Frank
2024-05-10 11:47 ` [pve-devel] [PATCH qemu-server v10 1/4] add C program to get hardware capabilities from CPUID Markus Frank
2024-05-17 11:21 ` Dominik Csapak
2024-05-21 9:51 ` Thomas Lamprecht
2024-05-10 11:47 ` [pve-devel] [PATCH qemu-server v10 2/4] config: add AMD SEV support Markus Frank
2024-05-17 11:21 ` Dominik Csapak [this message]
2024-05-10 11:47 ` [pve-devel] [PATCH docs v10 3/4] add AMD SEV documentation Markus Frank
2024-05-10 11:47 ` [pve-devel] [PATCH manager v10 4/4] ui: add AMD SEV configuration to Options Markus Frank
2024-05-17 11:21 ` Dominik Csapak
2024-05-17 11:21 ` [pve-devel] [PATCH qemu-server/docs/manager v10 0/4] AMD SEV Dominik Csapak
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=2a3f067a-adc3-4958-b8d8-1a70f8332616@proxmox.com \
--to=d.csapak@proxmox.com \
--cc=m.frank@proxmox.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.