-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.
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::
#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)
char *session_file;
uint32_t cbitpos;
uint32_t reduced_phys_bits;
+ bool kernel_hashes;
/* runtime state */
uint32_t handle;
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;
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)
{
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
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
* 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);
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 *)ht, aligned_len, errp) < 0) {
- return false;
+ if (sev_encrypt_flash((uint8_t *)padded_ht, sizeof(*padded_ht), errp) < 0) {
+ ret = false;
}
- return true;
+ address_space_unmap(&address_space_memory, padded_ht,
+ mapped_len, true, mapped_len);
+
+ return ret;
}
static void