Add property for requesting AMD SEV measured kernel launch
- The 'sev-guest' object gains a boolean 'kernel-hashes' property which must be enabled to request a measured kernel launch. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmGWViUACgkQvobrtBUQ T9+nmw/+OIAj3gWwpPNrUdi2KeqmBdSBMG13CUCFXfAmQUDD8GkYZ78Cgzm7gkjm kH/bNiOWxA8QnteeEC6K1SF0z+wlyl0Q6SKxP+Zo+iRWw0fJkKivvtz/e7bE3E/K A8l7u5ZUUSGcP8fc/LbPzXKwS0C46B506MekeKbV4A03renXxfK0WLsNDcB29n7G /f4JEDbs96WyfRJdyzo9U4oumndKEvh6c8CazRk9g3PZQlULmLq5JpvbQzap/4HL Z/46ZalJkbrAMrby+0e9wNBE+5g+vkD/bVOJwHG9bv6ZEvp1vWMYwI0wF5T7Y0Wx 2Uv4d0z+mjP5zPoxhKHmVrZNGoYKG80vnOIO45WqTWeJFsF7khLZ+oBEy6ito/Zy +DOo/FJCeCxdlh6JRB2xPM452iswx8moC/1fY6jeuVDF14s/Br5TpIYP+cqeBF1B YKzyzPSOUKZWoyVTHCVzEu4ddrlIyw9FHemG4RvBRuVd7ed12xzWHs3pa6i8smHf zmroL34X+//MorgFk5fzNbTmR65EzXTjR6gp/UbEmgaOZRpM2Gyh94DQttaOm3Kq FaLHP+jLFmuJPcfthJYRpzC7WvVoX2YT5mk3xQNXtEPzA6ESodzWPc1cTignth3t 5/+sYkT+KCj5BhENqKWxUPmewpmgM3L+GxNWyucEqX62TNxRN8g= =1HDG -----END PGP SIGNATURE----- Merge tag 'sev-hashes-pull-request' of https://gitlab.com/berrange/qemu into staging Add property for requesting AMD SEV measured kernel launch - The 'sev-guest' object gains a boolean 'kernel-hashes' property which must be enabled to request a measured kernel launch. # gpg: Signature made Thu 18 Nov 2021 02:33:25 PM CET # gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full] * tag 'sev-hashes-pull-request' of https://gitlab.com/berrange/qemu: target/i386/sev: Replace qemu_map_ram_ptr with address_space_map target/i386/sev: Perform padding calculations at compile-time target/i386/sev: Fail when invalid hashes table area detected target/i386/sev: Rephrase error message when no hashes table in guest firmware target/i386/sev: Add kernel hashes only if sev-guest.kernel-hashes=on qapi/qom,target/i386: sev-guest: Introduce kernel-hashes=on|off option Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
44a3aa0608
@ -769,6 +769,10 @@
|
||||
# @reduced-phys-bits: number of bits in physical addresses that become
|
||||
# unavailable when SEV is enabled
|
||||
#
|
||||
# @kernel-hashes: if true, add hashes of kernel/initrd/cmdline to a
|
||||
# designated guest firmware page for measured boot
|
||||
# with -kernel (default: false) (since 6.2)
|
||||
#
|
||||
# Since: 2.12
|
||||
##
|
||||
{ 'struct': 'SevGuestProperties',
|
||||
@ -778,7 +782,8 @@
|
||||
'*policy': 'uint32',
|
||||
'*handle': 'uint32',
|
||||
'*cbitpos': 'uint32',
|
||||
'reduced-phys-bits': 'uint32' } }
|
||||
'reduced-phys-bits': 'uint32',
|
||||
'*kernel-hashes': 'bool' } }
|
||||
|
||||
##
|
||||
# @ObjectType:
|
||||
|
@ -5189,7 +5189,7 @@ SRST
|
||||
-object secret,id=sec0,keyid=secmaster0,format=base64,\\
|
||||
data=$SECRET,iv=$(<iv.b64)
|
||||
|
||||
``-object sev-guest,id=id,cbitpos=cbitpos,reduced-phys-bits=val,[sev-device=string,policy=policy,handle=handle,dh-cert-file=file,session-file=file]``
|
||||
``-object sev-guest,id=id,cbitpos=cbitpos,reduced-phys-bits=val,[sev-device=string,policy=policy,handle=handle,dh-cert-file=file,session-file=file,kernel-hashes=on|off]``
|
||||
Create a Secure Encrypted Virtualization (SEV) guest object,
|
||||
which can be used to provide the guest memory encryption support
|
||||
on AMD processors.
|
||||
@ -5229,6 +5229,10 @@ SRST
|
||||
session with the guest owner to negotiate keys used for
|
||||
attestation. The file must be encoded in base64.
|
||||
|
||||
The ``kernel-hashes`` adds the hashes of given kernel/initrd/
|
||||
cmdline to a designated guest firmware page for measured Linux
|
||||
boot with -kernel. The default is off. (Since 6.2)
|
||||
|
||||
e.g to launch a SEV guest
|
||||
|
||||
.. parsed-literal::
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "exec/confidential-guest-support.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
#define TYPE_SEV_GUEST "sev-guest"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(SevGuestState, SEV_GUEST)
|
||||
@ -62,6 +63,7 @@ struct SevGuestState {
|
||||
char *session_file;
|
||||
uint32_t cbitpos;
|
||||
uint32_t reduced_phys_bits;
|
||||
bool kernel_hashes;
|
||||
|
||||
/* runtime state */
|
||||
uint32_t handle;
|
||||
@ -109,9 +111,19 @@ typedef struct QEMU_PACKED SevHashTable {
|
||||
SevHashTableEntry cmdline;
|
||||
SevHashTableEntry initrd;
|
||||
SevHashTableEntry kernel;
|
||||
uint8_t padding[];
|
||||
} SevHashTable;
|
||||
|
||||
/*
|
||||
* Data encrypted by sev_encrypt_flash() must be padded to a multiple of
|
||||
* 16 bytes.
|
||||
*/
|
||||
typedef struct QEMU_PACKED PaddedSevHashTable {
|
||||
SevHashTable ht;
|
||||
uint8_t padding[ROUND_UP(sizeof(SevHashTable), 16) - sizeof(SevHashTable)];
|
||||
} PaddedSevHashTable;
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(PaddedSevHashTable) % 16 != 0);
|
||||
|
||||
static SevGuestState *sev_guest;
|
||||
static Error *sev_mig_blocker;
|
||||
|
||||
@ -327,6 +339,20 @@ sev_guest_set_sev_device(Object *obj, const char *value, Error **errp)
|
||||
sev->sev_device = g_strdup(value);
|
||||
}
|
||||
|
||||
static bool sev_guest_get_kernel_hashes(Object *obj, Error **errp)
|
||||
{
|
||||
SevGuestState *sev = SEV_GUEST(obj);
|
||||
|
||||
return sev->kernel_hashes;
|
||||
}
|
||||
|
||||
static void sev_guest_set_kernel_hashes(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
SevGuestState *sev = SEV_GUEST(obj);
|
||||
|
||||
sev->kernel_hashes = value;
|
||||
}
|
||||
|
||||
static void
|
||||
sev_guest_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
@ -345,6 +371,11 @@ sev_guest_class_init(ObjectClass *oc, void *data)
|
||||
sev_guest_set_session_file);
|
||||
object_class_property_set_description(oc, "session-file",
|
||||
"guest owners session parameters (encoded with base64)");
|
||||
object_class_property_add_bool(oc, "kernel-hashes",
|
||||
sev_guest_get_kernel_hashes,
|
||||
sev_guest_set_kernel_hashes);
|
||||
object_class_property_set_description(oc, "kernel-hashes",
|
||||
"add kernel hashes to guest firmware for measured Linux boot");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1196,18 +1227,35 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
|
||||
uint8_t *data;
|
||||
SevHashTableDescriptor *area;
|
||||
SevHashTable *ht;
|
||||
PaddedSevHashTable *padded_ht;
|
||||
uint8_t cmdline_hash[HASH_SIZE];
|
||||
uint8_t initrd_hash[HASH_SIZE];
|
||||
uint8_t kernel_hash[HASH_SIZE];
|
||||
uint8_t *hashp;
|
||||
size_t hash_len = HASH_SIZE;
|
||||
int aligned_len;
|
||||
hwaddr mapped_len = sizeof(*padded_ht);
|
||||
MemTxAttrs attrs = { 0 };
|
||||
bool ret = true;
|
||||
|
||||
/*
|
||||
* Only add the kernel hashes if the sev-guest configuration explicitly
|
||||
* stated kernel-hashes=on.
|
||||
*/
|
||||
if (!sev_guest->kernel_hashes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pc_system_ovmf_table_find(SEV_HASH_TABLE_RV_GUID, &data, NULL)) {
|
||||
error_setg(errp, "SEV: kernel specified but OVMF has no hash table guid");
|
||||
error_setg(errp, "SEV: kernel specified but guest firmware "
|
||||
"has no hashes table GUID");
|
||||
return false;
|
||||
}
|
||||
area = (SevHashTableDescriptor *)data;
|
||||
if (!area->base || area->size < sizeof(PaddedSevHashTable)) {
|
||||
error_setg(errp, "SEV: guest firmware hashes table area is invalid "
|
||||
"(base=0x%x size=0x%x)", area->base, area->size);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate hash of kernel command-line with the terminating null byte. If
|
||||
@ -1248,7 +1296,13 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
|
||||
* Populate the hashes table in the guest's memory at the OVMF-designated
|
||||
* area for the SEV hashes table
|
||||
*/
|
||||
ht = qemu_map_ram_ptr(NULL, area->base);
|
||||
padded_ht = address_space_map(&address_space_memory, area->base,
|
||||
&mapped_len, true, attrs);
|
||||
if (!padded_ht || mapped_len != sizeof(*padded_ht)) {
|
||||
error_setg(errp, "SEV: cannot map hashes table guest memory area");
|
||||
return false;
|
||||
}
|
||||
ht = &padded_ht->ht;
|
||||
|
||||
ht->guid = sev_hash_table_header_guid;
|
||||
ht->len = sizeof(*ht);
|
||||
@ -1265,18 +1319,17 @@ bool sev_add_kernel_loader_hashes(SevKernelLoaderContext *ctx, Error **errp)
|
||||
ht->kernel.len = sizeof(ht->kernel);
|
||||
memcpy(ht->kernel.hash, kernel_hash, sizeof(ht->kernel.hash));
|
||||
|
||||
/* When calling sev_encrypt_flash, the length has to be 16 byte aligned */
|
||||
aligned_len = ROUND_UP(ht->len, 16);
|
||||
if (aligned_len != ht->len) {
|
||||
/* zero the excess data so the measurement can be reliably calculated */
|
||||
memset(ht->padding, 0, aligned_len - ht->len);
|
||||
/* zero the excess data so the measurement can be reliably calculated */
|
||||
memset(padded_ht->padding, 0, sizeof(padded_ht->padding));
|
||||
|
||||
if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht), errp) < 0) {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (sev_encrypt_flash((uint8_t *)ht, aligned_len, errp) < 0) {
|
||||
return false;
|
||||
}
|
||||
address_space_unmap(&address_space_memory, padded_ht,
|
||||
mapped_len, true, mapped_len);
|
||||
|
||||
return true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user