From: Thomas Lamprecht <t.lamprecht@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 v7 2/3] config: QEMU AMD SEV enable
Date: Tue, 23 Apr 2024 09:24:05 +0200 [thread overview]
Message-ID: <ddca7513-012c-4fda-ae8c-9e022d74b9e6@proxmox.com> (raw)
In-Reply-To: <20240422121617.1131803-2-m.frank@proxmox.com>
Am 22/04/2024 um 14:16 schrieb Markus Frank:
> This patch is for enabling AMD SEV (Secure Encrypted
> Virtualization) support in QEMU
try to keep a somewhat unified line length over the whole commit message,
most editors support re-flowing (parts of the) text to e.g. the for
commit messages commonly used 70 or 72 text width.
>
> VM-Config-Examples:
> amd_sev: type=std,nodbg=1,noks=1
> amd_sev: es,nodbg=1,kernel-hashes=1
>
> Node-Config-Example (gets generated automatically):
> amd_sev: cbitpos=47,reduced-phys-bios=1
>
> kernel-hashes, reduced-phys-bios & cbitpos correspond to the varibles
typo: 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 amd-sev-support.service on boot and saved to the /run/amd-sev-params
> 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>
> ---
> v7:
> * adjustments for the changes made in the query-machine-params C program
>
> v6:
> * rebase on master
> * removed unused $sev_node_fmt object
>
> v5:
> * parse /run/amd-sev-params for hardware parameters
> * removed NodeConfig dependency
> * only disallow live-migration and snapshots with vmstate
> -> allow offline migration and snapshots without vmstate
>
> v4:
> * reduced lines of code
> * added text that SEV-ES is experimental
>
> PVE/API2/Qemu.pm | 10 ++++++
> PVE/QemuMigrate.pm | 4 +++
> PVE/QemuServer.pm | 83 ++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 97 insertions(+)
>
> diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
> index 2a349c8..2e8d654 100644
> --- a/PVE/API2/Qemu.pm
> +++ b/PVE/API2/Qemu.pm
> @@ -4512,6 +4512,10 @@ __PACKAGE__->register_method({
> push $local_resources->@*, "clipboard=vnc";
> }
> > + if ($res->{running} && $vmconf->{amd_sev}) {
a comment might be good here
> + 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 +5196,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..7db18b2 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 "VMs with AMD SEV are not live migratable!\n";
cannot live-migrate VM when AMD SEV is enabled.
> + }
> +
> my $vollist = PVE::QemuServer::get_vm_volumes($conf);
>
> my $storages = {};
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index 28e630d..b03f1b4 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -177,6 +177,40 @@ 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 => "qemu-sev-type",
> + enum => ['std', 'es'],
> + maxLength => 3,
> + },
> + nodbg => {
'no-debug' would be more telling
> + description => "Sets policy bit 0 to 1 to disallow debugging of guest",
> + type => 'boolean',
> + format_description => "qemu-sev-nodbg",
do we need a format description for a boolean
> + default => 0,
> + optional => 1,
> + },
> + noks => {
'no-key-sharing' would be also more telling
> + description => "Sets policy bit 1 to 1 to disallow key sharing with other guests",
> + type => 'boolean',
> + format_description => "qemu-sev-noks",
do we need a format description for a boolean
> + default => 0,
> + optional => 1,
> + },
> + "kernel-hashes" => {
> + description => "Add kernel hashes to guest firmware for measured linux kernel launch",
> + type => 'boolean',
> + format_description => "qemu-sev-kernel-hashes",
> + 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 +392,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 +4131,39 @@ sub config_to_command {
> }
> }
>
> + if ($conf->{amd_sev}) {
> + if ($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_params = get_hw_parameters()->{'amd-sev'};
> +
> + if (!$sev_hw_params->{'sev-support'}) {
> + die "Your CPU does not support AMD SEV!\n";
> + }
> + if ($amd_sev_conf->{type} eq 'es' && !$sev_hw_params->{'sev-support-es'}) {
> + die "Your CPU does not support AMD SEV-ES!\n";
> + }
> +
> + my $sev_mem_object = 'sev-guest,id=sev0'
> + .',cbitpos='.$sev_hw_params->{cbitpos}
> + .',reduced-phys-bits='.$sev_hw_params->{'reduced-phys-bits'};
> +
> + my $policy = 0b0;
> + $policy += 0b1 if ($amd_sev_conf->{nodbg});
> + $policy += 0b10 if ($amd_sev_conf->{noks});
> + $policy += 0b100 if ($amd_sev_conf->{type} eq 'es');
> + # disable migration with bit 3 nosend to prevent amd-sev-migration-attack
> + $policy += 0b1000;
> +
> + $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';
> + }
> +
> push @$cmd, @$devices;
> push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
> push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
> @@ -4134,6 +4207,16 @@ sub check_rng_source {
> }
> }
>
> +sub get_hw_parameters {
> + # Get reduced-phys-bits & cbitpos from /run/qemu-server/hw-params.json
> + my $filename = '/run/qemu-server/hw-params.json';
I'd not use params, as parameters are normally something one can change in software,
(i.e. without buying a different CPU, and FW updates are a grey area ^^)
"host-hw-capabilities.json" might be better here
> + open my $fh, '<', $filename or die "Could not open '$filename' for reading: $!";
> + my $json_text = do { local $/; <$fh> };
> + close $fh;
> + my $hw_params = JSON->new->decode($json_text);
> + return $hw_params;
> +}
> +
> 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-04-23 7:24 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-22 12:16 [pve-devel] [PATCH qemu-server v7 1/3] add C program to get AMD SEV hardware parameters from CPUID Markus Frank
2024-04-22 12:16 ` [pve-devel] [PATCH qemu-server v7 2/3] config: QEMU AMD SEV enable Markus Frank
2024-04-23 7:24 ` Thomas Lamprecht [this message]
2024-04-22 12:16 ` [pve-devel] [PATCH docs v7 3/3] add AMD SEV documentation Markus Frank
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=ddca7513-012c-4fda-ae8c-9e022d74b9e6@proxmox.com \
--to=t.lamprecht@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.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal