qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
@ 2021-06-24 10:20 Dov Murik
  2021-06-24 10:20 ` [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
                   ` (3 more replies)
  0 siblings, 4 replies; 16+ messages in thread
From: Dov Murik @ 2021-06-24 10:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Connor Kuehl, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Paolo Bonzini,
	Philippe Mathieu-Daudé

Currently booting with -kernel/-initrd/-append is not supported in SEV
confidential guests, because the content of these blobs is not measured
and therefore not trusted by the SEV guest.

However, in some cases the kernel, initrd, and cmdline are not secret
but should not be modified by the host.  In such a case, we want to
verify inside the trusted VM that the kernel, initrd, and cmdline are
indeed the ones expected by the Guest Owner, and only if that is the
case go on and boot them up (removing the need for grub inside OVMF in
that mode).

To support that, OVMF adds a special area for hashes of
kernel/initrd/cmdline; that area is expected to be filled by QEMU and
encrypted as part of the initial SEV guest launch.  This in turn makes
the hashes part of the PSP measured content, and OVMF can trust these
inputs if they match the hashes.

This series adds an SEV function to generate the table of hashes for
OVMF and encrypt it (patch 1/2), and calls this function if SEV is
enabled when the kernel/initrd/cmdline are prepared (patch 2/2).

Corresponding OVMF support was submitted to edk2-devel [1] (patch series
"Measured SEV boot with kernel/initrd/cmdline"); it's still under
review.

[1] https://edk2.groups.io/g/devel/topic/patch_v1_0_8_measured_sev/83074450

---

v3 changes:
 - initrd hash is now mandatory; if no -initrd is passed, calculate the
   hash of the empty buffer.  This is now aligned with the OVMF
   behaviour which verifies the empty initrd (correctly).
 - make SevHashTable entries fixed: 3 entries for cmdline, initrd, and kernel.
 - in sev_add_kernel_loader_hashes: first calculate all the hashes, only then
   fill-in the hashes table in the guest's memory.
 - Use g_assert_not_reached in sev-stub.c.
 - Use QEMU_PACKED attribute for structs.
 - Use QemuUUID type for guids.
 - in sev_add_kernel_loader_hashes: use ARRAY_SIZE(iov) instead of literal 2.

v2: https://lore.kernel.org/qemu-devel/20210621190553.1763020-1-dovmurik@linux.ibm.com/
v2 changes:
 - Extract main functionality to sev.c (with empty stub in sev-stub.c)
 - Use sev_enabled() instead of machine->cgs->ready to detect SEV guest
 - Coding style changes

v1: https://lore.kernel.org/qemu-devel/20210525065931.1628554-1-dovmurik@linux.ibm.com/

Dov Murik (2):
  sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux
    boot
  x86/sev: generate SEV kernel loader hashes in x86_load_linux

 target/i386/sev_i386.h |  12 ++++
 hw/i386/x86.c          |  25 +++++++-
 target/i386/sev-stub.c |   5 ++
 target/i386/sev.c      | 137 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 178 insertions(+), 1 deletion(-)


base-commit: b22726abdfa54592d6ad88f65b0297c0e8b363e2
-- 
2.25.1



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-06-24 10:20 [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
@ 2021-06-24 10:20 ` Dov Murik
  2021-07-01 17:23   ` Connor Kuehl
  2021-06-24 10:20 ` [PATCH v3 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux Dov Murik
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 16+ messages in thread
From: Dov Murik @ 2021-06-24 10:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Connor Kuehl, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Paolo Bonzini,
	Philippe Mathieu-Daudé

Add the sev_add_kernel_loader_hashes function to calculate the hashes of
the kernel/initrd/cmdline and fill a designated OVMF encrypted hash
table area.  For this to work, OVMF must support an encrypted area to
place the data which is advertised via a special GUID in the OVMF reset
table.

The hashes of each of the files is calculated (or the string in the case
of the cmdline with trailing '\0' included).  Each entry in the hashes
table is GUID identified and since they're passed through the
sev_encrypt_flash interface, the hashes will be accumulated by the PSP
measurement (SEV_LAUNCH_MEASURE).

Co-developed-by: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
---
 target/i386/sev_i386.h |  12 ++++
 target/i386/sev-stub.c |   5 ++
 target/i386/sev.c      | 137 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 154 insertions(+)

diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index ae6d840478..deb3eec409 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -28,6 +28,17 @@
 #define SEV_POLICY_DOMAIN       0x10
 #define SEV_POLICY_SEV          0x20
 
+typedef struct KernelLoaderContext {
+    char *setup_data;
+    size_t setup_size;
+    char *kernel_data;
+    size_t kernel_size;
+    char *initrd_data;
+    size_t initrd_size;
+    char *cmdline_data;
+    size_t cmdline_size;
+} KernelLoaderContext;
+
 extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
@@ -37,5 +48,6 @@ extern char *sev_get_launch_measurement(void);
 extern SevCapability *sev_get_capabilities(Error **errp);
 extern SevAttestationReport *
 sev_get_attestation_report(const char *mnonce, Error **errp);
+extern bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp);
 
 #endif
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 0227cb5177..addb089f36 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -81,3 +81,8 @@ sev_get_attestation_report(const char *mnonce, Error **errp)
     error_setg(errp, "SEV is not available in this QEMU");
     return NULL;
 }
+
+bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp)
+{
+    g_assert_not_reached();
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 83df8c09f6..857d75bd3e 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -23,6 +23,7 @@
 #include "qemu/base64.h"
 #include "qemu/module.h"
 #include "qemu/uuid.h"
+#include "crypto/hash.h"
 #include "sysemu/kvm.h"
 #include "sev_i386.h"
 #include "sysemu/sysemu.h"
@@ -83,6 +84,32 @@ typedef struct __attribute__((__packed__)) SevInfoBlock {
     uint32_t reset_addr;
 } SevInfoBlock;
 
+#define SEV_HASH_TABLE_RV_GUID  "7255371f-3a3b-4b04-927b-1da6efa8d454"
+typedef struct QEMU_PACKED SevHashTableDescriptor {
+    /* SEV hash table area guest address */
+    uint32_t base;
+    /* SEV hash table area size (in bytes) */
+    uint32_t size;
+} SevHashTableDescriptor;
+
+/* hard code sha256 digest size */
+#define HASH_SIZE 32
+
+typedef struct QEMU_PACKED SevHashTableEntry {
+    QemuUUID guid;
+    uint16_t len;
+    uint8_t hash[HASH_SIZE];
+} SevHashTableEntry;
+
+typedef struct QEMU_PACKED SevHashTable {
+    QemuUUID guid;
+    uint16_t len;
+    SevHashTableEntry cmdline;
+    SevHashTableEntry initrd;
+    SevHashTableEntry kernel;
+    uint8_t padding[];
+} SevHashTable;
+
 static SevGuestState *sev_guest;
 static Error *sev_mig_blocker;
 
@@ -1077,6 +1104,116 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
     return 0;
 }
 
+static const QemuUUID sev_hash_table_header_guid = {
+    .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93,
+                    0xd4, 0x11, 0xfd, 0x21)
+};
+
+static const QemuUUID sev_kernel_entry_guid = {
+    .data = UUID_LE(0x4de79437, 0xabd2, 0x427f, 0xb8, 0x35, 0xd5, 0xb1,
+                    0x72, 0xd2, 0x04, 0x5b)
+};
+static const QemuUUID sev_initrd_entry_guid = {
+    .data = UUID_LE(0x44baf731, 0x3a2f, 0x4bd7, 0x9a, 0xf1, 0x41, 0xe2,
+                    0x91, 0x69, 0x78, 0x1d)
+};
+static const QemuUUID sev_cmdline_entry_guid = {
+    .data = UUID_LE(0x97d02dd8, 0xbd20, 0x4c94, 0xaa, 0x78, 0xe7, 0x71,
+                    0x4d, 0x36, 0xab, 0x2a)
+};
+
+/*
+ * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
+ * which is included in SEV's initial memory measurement.
+ */
+bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp)
+{
+    uint8_t *data;
+    SevHashTableDescriptor *area;
+    SevHashTable *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;
+
+    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");
+        return false;
+    }
+    area = (SevHashTableDescriptor *)data;
+
+    /*
+     * Calculate hash of kernel command-line with the terminating null byte. If
+     * the user doesn't supply a command-line via -append, the 1-byte "\0" will
+     * be used.
+     */
+    hashp = cmdline_hash;
+    if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->cmdline_data,
+                           ctx->cmdline_size, &hashp, &hash_len, errp) < 0) {
+        return false;
+    }
+    assert(hash_len == HASH_SIZE);
+
+    /*
+     * Calculate hash of initrd. If the user doesn't supply an initrd via
+     * -initrd, an empty buffer will be used (ctx->initrd_size == 0).
+     */
+    hashp = initrd_hash;
+    if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->initrd_data,
+                           ctx->initrd_size, &hashp, &hash_len, errp) < 0) {
+        return false;
+    }
+    assert(hash_len == HASH_SIZE);
+
+    /* Calculate hash of the kernel */
+    hashp = kernel_hash;
+    struct iovec iov[2] = {
+        { .iov_base = ctx->setup_data, .iov_len = ctx->setup_size },
+        { .iov_base = ctx->kernel_data, .iov_len = ctx->kernel_size }
+    };
+    if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256, iov, ARRAY_SIZE(iov),
+                            &hashp, &hash_len, errp) < 0) {
+        return false;
+    }
+    assert(hash_len == HASH_SIZE);
+
+    /*
+     * 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);
+
+    ht->guid = sev_hash_table_header_guid;
+    ht->len = sizeof(*ht);
+
+    ht->cmdline.guid = sev_cmdline_entry_guid;
+    ht->cmdline.len = sizeof(ht->cmdline);
+    memcpy(ht->cmdline.hash, cmdline_hash, sizeof(ht->cmdline.hash));
+
+    ht->initrd.guid = sev_initrd_entry_guid;
+    ht->initrd.len = sizeof(ht->initrd);
+    memcpy(ht->initrd.hash, initrd_hash, sizeof(ht->initrd.hash));
+
+    ht->kernel.guid = sev_kernel_entry_guid;
+    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);
+    }
+
+    if (sev_encrypt_flash((uint8_t *)ht, aligned_len, errp) < 0) {
+        return false;
+    }
+
+    return true;
+}
+
 static void
 sev_register_types(void)
 {
-- 
2.25.1



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v3 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux
  2021-06-24 10:20 [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
  2021-06-24 10:20 ` [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
@ 2021-06-24 10:20 ` Dov Murik
  2021-07-08 16:41 ` [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Connor Kuehl
  2021-07-09  6:55 ` Michael S. Tsirkin
  3 siblings, 0 replies; 16+ messages in thread
From: Dov Murik @ 2021-06-24 10:20 UTC (permalink / raw)
  To: qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Connor Kuehl, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Paolo Bonzini,
	Philippe Mathieu-Daudé

If SEV is enabled and a kernel is passed via -kernel, pass the hashes of
kernel/initrd/cmdline in an encrypted guest page to OVMF for SEV
measured boot.

Co-developed-by: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
---
 hw/i386/x86.c | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index d30cf27e29..830c8f6f58 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -45,6 +45,7 @@
 #include "hw/i386/fw_cfg.h"
 #include "hw/intc/i8259.h"
 #include "hw/rtc/mc146818rtc.h"
+#include "target/i386/sev_i386.h"
 
 #include "hw/acpi/cpu_hotplug.h"
 #include "hw/irq.h"
@@ -778,6 +779,7 @@ void x86_load_linux(X86MachineState *x86ms,
     const char *initrd_filename = machine->initrd_filename;
     const char *dtb_filename = machine->dtb;
     const char *kernel_cmdline = machine->kernel_cmdline;
+    KernelLoaderContext kernel_loader_context = {};
 
     /* Align to 16 bytes as a paranoia measure */
     cmdline_size = (strlen(kernel_cmdline) + 16) & ~15;
@@ -924,6 +926,8 @@ void x86_load_linux(X86MachineState *x86ms,
     fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr);
     fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, strlen(kernel_cmdline) + 1);
     fw_cfg_add_string(fw_cfg, FW_CFG_CMDLINE_DATA, kernel_cmdline);
+    kernel_loader_context.cmdline_data = (char *)kernel_cmdline;
+    kernel_loader_context.cmdline_size = strlen(kernel_cmdline) + 1;
 
     if (protocol >= 0x202) {
         stl_p(header + 0x228, cmdline_addr);
@@ -1005,6 +1009,8 @@ void x86_load_linux(X86MachineState *x86ms,
         fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
         fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
         fw_cfg_add_bytes(fw_cfg, FW_CFG_INITRD_DATA, initrd_data, initrd_size);
+        kernel_loader_context.initrd_data = initrd_data;
+        kernel_loader_context.initrd_size = initrd_size;
 
         stl_p(header + 0x218, initrd_addr);
         stl_p(header + 0x21c, initrd_size);
@@ -1063,15 +1069,32 @@ void x86_load_linux(X86MachineState *x86ms,
         load_image_size(dtb_filename, setup_data->data, dtb_size);
     }
 
-    memcpy(setup, header, MIN(sizeof(header), setup_size));
+    /*
+     * If we're starting an encrypted VM, it will be OVMF based, which uses the
+     * efi stub for booting and doesn't require any values to be placed in the
+     * kernel header.  We therefore don't update the header so the hash of the
+     * kernel on the other side of the fw_cfg interface matches the hash of the
+     * file the user passed in.
+     */
+    if (!sev_enabled()) {
+        memcpy(setup, header, MIN(sizeof(header), setup_size));
+    }
 
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, prot_addr);
     fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_KERNEL_DATA, kernel, kernel_size);
+    kernel_loader_context.kernel_data = (char *)kernel;
+    kernel_loader_context.kernel_size = kernel_size;
 
     fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_ADDR, real_addr);
     fw_cfg_add_i32(fw_cfg, FW_CFG_SETUP_SIZE, setup_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_SETUP_DATA, setup, setup_size);
+    kernel_loader_context.setup_data = (char *)setup;
+    kernel_loader_context.setup_size = setup_size;
+
+    if (sev_enabled()) {
+        sev_add_kernel_loader_hashes(&kernel_loader_context, &error_fatal);
+    }
 
     option_rom[nb_option_roms].bootindex = 0;
     option_rom[nb_option_roms].name = "linuxboot.bin";
-- 
2.25.1



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-06-24 10:20 ` [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
@ 2021-07-01 17:23   ` Connor Kuehl
  2021-07-02 12:29     ` Dov Murik
  0 siblings, 1 reply; 16+ messages in thread
From: Connor Kuehl @ 2021-07-01 17:23 UTC (permalink / raw)
  To: Dov Murik, qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert,
	Tobin Feldman-Fitzthum, Jim Cadden, Paolo Bonzini,
	Philippe Mathieu-Daudé

On 6/24/21 3:20 AM, Dov Murik wrote:
> Add the sev_add_kernel_loader_hashes function to calculate the hashes of
> the kernel/initrd/cmdline and fill a designated OVMF encrypted hash
> table area.  For this to work, OVMF must support an encrypted area to
> place the data which is advertised via a special GUID in the OVMF reset
> table.
> 
> The hashes of each of the files is calculated (or the string in the case
> of the cmdline with trailing '\0' included).  Each entry in the hashes
> table is GUID identified and since they're passed through the
> sev_encrypt_flash interface, the hashes will be accumulated by the PSP
> measurement (SEV_LAUNCH_MEASURE).
> 
> Co-developed-by: James Bottomley <jejb@linux.ibm.com>
> Signed-off-by: James Bottomley <jejb@linux.ibm.com>
> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
> ---

Reviewed-by: Connor Kuehl <ckuehl@redhat.com>



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-07-01 17:23   ` Connor Kuehl
@ 2021-07-02 12:29     ` Dov Murik
  0 siblings, 0 replies; 16+ messages in thread
From: Dov Murik @ 2021-07-02 12:29 UTC (permalink / raw)
  To: Connor Kuehl, qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Paolo Bonzini,
	Philippe Mathieu-Daudé



On 01/07/2021 20:23, Connor Kuehl wrote:
> On 6/24/21 3:20 AM, Dov Murik wrote:
>> Add the sev_add_kernel_loader_hashes function to calculate the hashes of
>> the kernel/initrd/cmdline and fill a designated OVMF encrypted hash
>> table area.  For this to work, OVMF must support an encrypted area to
>> place the data which is advertised via a special GUID in the OVMF reset
>> table.
>>
>> The hashes of each of the files is calculated (or the string in the case
>> of the cmdline with trailing '\0' included).  Each entry in the hashes
>> table is GUID identified and since they're passed through the
>> sev_encrypt_flash interface, the hashes will be accumulated by the PSP
>> measurement (SEV_LAUNCH_MEASURE).
>>
>> Co-developed-by: James Bottomley <jejb@linux.ibm.com>
>> Signed-off-by: James Bottomley <jejb@linux.ibm.com>
>> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
>> ---
> 
> Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
> 

Thanks, Connor!

-Dov


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-06-24 10:20 [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
  2021-06-24 10:20 ` [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
  2021-06-24 10:20 ` [PATCH v3 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux Dov Murik
@ 2021-07-08 16:41 ` Connor Kuehl
  2021-07-08 17:03   ` Philippe Mathieu-Daudé
  2021-07-09  6:55 ` Michael S. Tsirkin
  3 siblings, 1 reply; 16+ messages in thread
From: Connor Kuehl @ 2021-07-08 16:41 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert, qemu-devel, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Philippe Mathieu-Daudé

Hi Paolo,

Please consider this series[1] for inclusion into your next pull request.

Just a note that this series has a companion series that is getting
upstreamed into OVMF[2]

[1] Patchwork link, if convenient: https://patchwork.kernel.org/project/qemu-devel/cover/20210624102040.2015280-1-dovmurik@linux.ibm.com/
[2] https://bugzilla.tianocore.org/show_bug.cgi?id=3457#c6

Thank you,

Connor

On 6/24/21 3:20 AM, Dov Murik wrote:
> Currently booting with -kernel/-initrd/-append is not supported in SEV
> confidential guests, because the content of these blobs is not measured
> and therefore not trusted by the SEV guest.
> 
> However, in some cases the kernel, initrd, and cmdline are not secret
> but should not be modified by the host.  In such a case, we want to
> verify inside the trusted VM that the kernel, initrd, and cmdline are
> indeed the ones expected by the Guest Owner, and only if that is the
> case go on and boot them up (removing the need for grub inside OVMF in
> that mode).
> 
> To support that, OVMF adds a special area for hashes of
> kernel/initrd/cmdline; that area is expected to be filled by QEMU and
> encrypted as part of the initial SEV guest launch.  This in turn makes
> the hashes part of the PSP measured content, and OVMF can trust these
> inputs if they match the hashes.
> 
> This series adds an SEV function to generate the table of hashes for
> OVMF and encrypt it (patch 1/2), and calls this function if SEV is
> enabled when the kernel/initrd/cmdline are prepared (patch 2/2).
> 
> Corresponding OVMF support was submitted to edk2-devel [1] (patch series
> "Measured SEV boot with kernel/initrd/cmdline"); it's still under
> review.
> 
> [1] https://edk2.groups.io/g/devel/topic/patch_v1_0_8_measured_sev/83074450
> 
> ---
> 
> v3 changes:
>  - initrd hash is now mandatory; if no -initrd is passed, calculate the
>    hash of the empty buffer.  This is now aligned with the OVMF
>    behaviour which verifies the empty initrd (correctly).
>  - make SevHashTable entries fixed: 3 entries for cmdline, initrd, and kernel.
>  - in sev_add_kernel_loader_hashes: first calculate all the hashes, only then
>    fill-in the hashes table in the guest's memory.
>  - Use g_assert_not_reached in sev-stub.c.
>  - Use QEMU_PACKED attribute for structs.
>  - Use QemuUUID type for guids.
>  - in sev_add_kernel_loader_hashes: use ARRAY_SIZE(iov) instead of literal 2.
> 
> v2: https://lore.kernel.org/qemu-devel/20210621190553.1763020-1-dovmurik@linux.ibm.com/
> v2 changes:
>  - Extract main functionality to sev.c (with empty stub in sev-stub.c)
>  - Use sev_enabled() instead of machine->cgs->ready to detect SEV guest
>  - Coding style changes
> 
> v1: https://lore.kernel.org/qemu-devel/20210525065931.1628554-1-dovmurik@linux.ibm.com/
> 
> Dov Murik (2):
>   sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux
>     boot
>   x86/sev: generate SEV kernel loader hashes in x86_load_linux
> 
>  target/i386/sev_i386.h |  12 ++++
>  hw/i386/x86.c          |  25 +++++++-
>  target/i386/sev-stub.c |   5 ++
>  target/i386/sev.c      | 137 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 178 insertions(+), 1 deletion(-)
> 
> 
> base-commit: b22726abdfa54592d6ad88f65b0297c0e8b363e2
> 



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-07-08 16:41 ` [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Connor Kuehl
@ 2021-07-08 17:03   ` Philippe Mathieu-Daudé
  2021-07-08 17:16     ` Connor Kuehl
  0 siblings, 1 reply; 16+ messages in thread
From: Philippe Mathieu-Daudé @ 2021-07-08 17:03 UTC (permalink / raw)
  To: Connor Kuehl, Paolo Bonzini
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, James Bottomley, Richard Henderson,
	Dr. David Alan Gilbert, qemu-devel, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Laszlo Ersek

On 7/8/21 6:41 PM, Connor Kuehl wrote:
> Hi Paolo,
> 
> Please consider this series[1] for inclusion into your next pull request.
> 
> Just a note that this series has a companion series that is getting
> upstreamed into OVMF[2]

Shouldn't we get the OVMF part merged first?

> 
> [1] Patchwork link, if convenient: https://patchwork.kernel.org/project/qemu-devel/cover/20210624102040.2015280-1-dovmurik@linux.ibm.com/
> [2] https://bugzilla.tianocore.org/show_bug.cgi?id=3457#c6
> 
> Thank you,
> 
> Connor
> 
> On 6/24/21 3:20 AM, Dov Murik wrote:
>> Currently booting with -kernel/-initrd/-append is not supported in SEV
>> confidential guests, because the content of these blobs is not measured
>> and therefore not trusted by the SEV guest.
>>
>> However, in some cases the kernel, initrd, and cmdline are not secret
>> but should not be modified by the host.  In such a case, we want to
>> verify inside the trusted VM that the kernel, initrd, and cmdline are
>> indeed the ones expected by the Guest Owner, and only if that is the
>> case go on and boot them up (removing the need for grub inside OVMF in
>> that mode).
>>
>> To support that, OVMF adds a special area for hashes of
>> kernel/initrd/cmdline; that area is expected to be filled by QEMU and
>> encrypted as part of the initial SEV guest launch.  This in turn makes
>> the hashes part of the PSP measured content, and OVMF can trust these
>> inputs if they match the hashes.
>>
>> This series adds an SEV function to generate the table of hashes for
>> OVMF and encrypt it (patch 1/2), and calls this function if SEV is
>> enabled when the kernel/initrd/cmdline are prepared (patch 2/2).
>>
>> Corresponding OVMF support was submitted to edk2-devel [1] (patch series
>> "Measured SEV boot with kernel/initrd/cmdline"); it's still under
>> review.
>>
>> [1] https://edk2.groups.io/g/devel/topic/patch_v1_0_8_measured_sev/83074450
>>
>> ---



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-07-08 17:03   ` Philippe Mathieu-Daudé
@ 2021-07-08 17:16     ` Connor Kuehl
  2021-07-29 19:31       ` Dov Murik
  0 siblings, 1 reply; 16+ messages in thread
From: Connor Kuehl @ 2021-07-08 17:16 UTC (permalink / raw)
  To: Philippe Mathieu-Daudé, Paolo Bonzini
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, James Bottomley, Richard Henderson,
	Dr. David Alan Gilbert, qemu-devel, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Laszlo Ersek

On 7/8/21 10:03 AM, Philippe Mathieu-Daudé wrote:
> On 7/8/21 6:41 PM, Connor Kuehl wrote:
>> Hi Paolo,
>>
>> Please consider this series[1] for inclusion into your next pull request.
>>
>> Just a note that this series has a companion series that is getting
>> upstreamed into OVMF[2]
> 
> Shouldn't we get the OVMF part merged first?

The approach taken in the OVMF series doesn't seem very controversial,
so I don't anticipate any breaking changes with the current state of
those patches as far as QEMU is concerned.

However, I'm fine with erring on the side of caution.

Connor



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-06-24 10:20 [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
                   ` (2 preceding siblings ...)
  2021-07-08 16:41 ` [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Connor Kuehl
@ 2021-07-09  6:55 ` Michael S. Tsirkin
  3 siblings, 0 replies; 16+ messages in thread
From: Michael S. Tsirkin @ 2021-07-09  6:55 UTC (permalink / raw)
  To: Dov Murik
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Connor Kuehl, Laszlo Ersek, James Bottomley, Richard Henderson,
	qemu-devel, Dr. David Alan Gilbert, Tobin Feldman-Fitzthum,
	Jim Cadden, Paolo Bonzini, Philippe Mathieu-Daudé

On Thu, Jun 24, 2021 at 10:20:38AM +0000, Dov Murik wrote:
> Currently booting with -kernel/-initrd/-append is not supported in SEV
> confidential guests, because the content of these blobs is not measured
> and therefore not trusted by the SEV guest.
> 
> However, in some cases the kernel, initrd, and cmdline are not secret
> but should not be modified by the host.  In such a case, we want to
> verify inside the trusted VM that the kernel, initrd, and cmdline are
> indeed the ones expected by the Guest Owner, and only if that is the
> case go on and boot them up (removing the need for grub inside OVMF in
> that mode).
> 
> To support that, OVMF adds a special area for hashes of
> kernel/initrd/cmdline; that area is expected to be filled by QEMU and
> encrypted as part of the initial SEV guest launch.  This in turn makes
> the hashes part of the PSP measured content, and OVMF can trust these
> inputs if they match the hashes.
> 
> This series adds an SEV function to generate the table of hashes for
> OVMF and encrypt it (patch 1/2), and calls this function if SEV is
> enabled when the kernel/initrd/cmdline are prepared (patch 2/2).
> 
> Corresponding OVMF support was submitted to edk2-devel [1] (patch series
> "Measured SEV boot with kernel/initrd/cmdline"); it's still under
> review.
> 
> [1] https://edk2.groups.io/g/devel/topic/patch_v1_0_8_measured_sev/83074450


Now that I figured the measurement angle

Acked-by: Michael S. Tsirkin <mst@redhat.com>

> ---
> 
> v3 changes:
>  - initrd hash is now mandatory; if no -initrd is passed, calculate the
>    hash of the empty buffer.  This is now aligned with the OVMF
>    behaviour which verifies the empty initrd (correctly).
>  - make SevHashTable entries fixed: 3 entries for cmdline, initrd, and kernel.
>  - in sev_add_kernel_loader_hashes: first calculate all the hashes, only then
>    fill-in the hashes table in the guest's memory.
>  - Use g_assert_not_reached in sev-stub.c.
>  - Use QEMU_PACKED attribute for structs.
>  - Use QemuUUID type for guids.
>  - in sev_add_kernel_loader_hashes: use ARRAY_SIZE(iov) instead of literal 2.
> 
> v2: https://lore.kernel.org/qemu-devel/20210621190553.1763020-1-dovmurik@linux.ibm.com/
> v2 changes:
>  - Extract main functionality to sev.c (with empty stub in sev-stub.c)
>  - Use sev_enabled() instead of machine->cgs->ready to detect SEV guest
>  - Coding style changes
> 
> v1: https://lore.kernel.org/qemu-devel/20210525065931.1628554-1-dovmurik@linux.ibm.com/
> 
> Dov Murik (2):
>   sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux
>     boot
>   x86/sev: generate SEV kernel loader hashes in x86_load_linux
> 
>  target/i386/sev_i386.h |  12 ++++
>  hw/i386/x86.c          |  25 +++++++-
>  target/i386/sev-stub.c |   5 ++
>  target/i386/sev.c      | 137 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 178 insertions(+), 1 deletion(-)
> 
> 
> base-commit: b22726abdfa54592d6ad88f65b0297c0e8b363e2
> -- 
> 2.25.1



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-07-08 17:16     ` Connor Kuehl
@ 2021-07-29 19:31       ` Dov Murik
  2021-07-30 14:47         ` Connor Kuehl
  0 siblings, 1 reply; 16+ messages in thread
From: Dov Murik @ 2021-07-29 19:31 UTC (permalink / raw)
  To: Connor Kuehl, Philippe Mathieu-Daudé, Paolo Bonzini
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, James Bottomley, Richard Henderson,
	Dr. David Alan Gilbert, qemu-devel, Dov Murik,
	Tobin Feldman-Fitzthum, Jim Cadden, Laszlo Ersek

Hi Paolo, Phil, Connor,

On 08/07/2021 20:16, Connor Kuehl wrote:
> On 7/8/21 10:03 AM, Philippe Mathieu-Daudé wrote:
>> On 7/8/21 6:41 PM, Connor Kuehl wrote:
>>> Hi Paolo,
>>>
>>> Please consider this series[1] for inclusion into your next pull request.
>>>
>>> Just a note that this series has a companion series that is getting
>>> upstreamed into OVMF[2]
>>
>> Shouldn't we get the OVMF part merged first?

The OVMF companion series has been reviewed by the new OVMF maintainer
and merged to edk2 master branch as of edk2 commit 514b3aa08ece [1].

[1] https://github.com/tianocore/edk2/commit/514b3aa08ece


Thanks,
Dov


> 
> The approach taken in the OVMF series doesn't seem very controversial,
> so I don't anticipate any breaking changes with the current state of
> those patches as far as QEMU is concerned.
> 
> However, I'm fine with erring on the side of caution.
> 
> Connor
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-07-29 19:31       ` Dov Murik
@ 2021-07-30 14:47         ` Connor Kuehl
  2021-07-30 18:02           ` Dov Murik
  0 siblings, 1 reply; 16+ messages in thread
From: Connor Kuehl @ 2021-07-30 14:47 UTC (permalink / raw)
  To: Dov Murik, Philippe Mathieu-Daudé, Paolo Bonzini
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, James Bottomley, Richard Henderson,
	Dr. David Alan Gilbert, qemu-devel, Tobin Feldman-Fitzthum,
	Jim Cadden, Laszlo Ersek

On Thu Jul 29, 2021 at 2:31 PM CDT, Dov Murik wrote:
> The OVMF companion series has been reviewed by the new OVMF maintainer
> and merged to edk2 master branch as of edk2 commit 514b3aa08ece [1].
>
> [1] https://github.com/tianocore/edk2/commit/514b3aa08ece

Awesome! Unfortunately, it's looking like we'll have to wait[1] for QEMU to
thaw before this series goes in.

Connor

[1] https://wiki.qemu.org/Planning/6.1



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-07-30 14:47         ` Connor Kuehl
@ 2021-07-30 18:02           ` Dov Murik
  2021-07-30 18:14             ` Connor Kuehl
  0 siblings, 1 reply; 16+ messages in thread
From: Dov Murik @ 2021-07-30 18:02 UTC (permalink / raw)
  To: Connor Kuehl, Philippe Mathieu-Daudé, Paolo Bonzini
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, James Bottomley, Richard Henderson,
	Dr. David Alan Gilbert, qemu-devel, Tobin Feldman-Fitzthum,
	Jim Cadden, Laszlo Ersek



On 30/07/2021 17:47, Connor Kuehl wrote:
> On Thu Jul 29, 2021 at 2:31 PM CDT, Dov Murik wrote:
>> The OVMF companion series has been reviewed by the new OVMF maintainer
>> and merged to edk2 master branch as of edk2 commit 514b3aa08ece [1].
>>
>> [1] https://github.com/tianocore/edk2/commit/514b3aa08ece
> 
> Awesome! Unfortunately, it's looking like we'll have to wait[1] for QEMU to
> thaw before this series goes in.
> 

Thanks for explaining this.  Do I need to do anything after 6.1 is
released? Ping? Rebase and re-send?

-Dov


> Connor
> 
> [1] https://wiki.qemu.org/Planning/6.1
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-07-30 18:02           ` Dov Murik
@ 2021-07-30 18:14             ` Connor Kuehl
  0 siblings, 0 replies; 16+ messages in thread
From: Connor Kuehl @ 2021-07-30 18:14 UTC (permalink / raw)
  To: Dov Murik, Philippe Mathieu-Daudé, Paolo Bonzini
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, James Bottomley, Richard Henderson,
	Dr. David Alan Gilbert, qemu-devel, Tobin Feldman-Fitzthum,
	Jim Cadden, Laszlo Ersek

On Fri Jul 30, 2021 at 1:02 PM CDT, Dov Murik wrote:
>
>
> > Awesome! Unfortunately, it's looking like we'll have to wait[1] for QEMU to
> > thaw before this series goes in.
> > 
>
> Thanks for explaining this. Do I need to do anything after 6.1 is
> released? Ping? Rebase and re-send?

Rebase and re-send. I think your patches already have the Reviewed-by
tags in the patch descriptions, but if that's not the case, make sure
you add them for the re-send so it's obvious that the patches have
already been reviewed.

Thank you,

Connor



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-09-27 17:00   ` Daniel P. Berrangé
@ 2021-09-29  9:39     ` Dov Murik
  0 siblings, 0 replies; 16+ messages in thread
From: Dov Murik @ 2021-09-29  9:39 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Connor Kuehl, Philippe Mathieu-Daudé,
	James Bottomley, Richard Henderson, qemu-devel,
	Dr. David Alan Gilbert, Dov Murik, Hubertus Franke, Jim Cadden,
	Tobin Feldman-Fitzthum, Paolo Bonzini, Laszlo Ersek



On 27/09/2021 20:00, Daniel P. Berrangé wrote:
> On Wed, Aug 25, 2021 at 07:35:37AM +0000, Dov Murik wrote:
>> Add the sev_add_kernel_loader_hashes function to calculate the hashes of
>> the kernel/initrd/cmdline and fill a designated OVMF encrypted hash
>> table area.  For this to work, OVMF must support an encrypted area to
>> place the data which is advertised via a special GUID in the OVMF reset
>> table.
>>
>> The hashes of each of the files is calculated (or the string in the case
>> of the cmdline with trailing '\0' included).  Each entry in the hashes
>> table is GUID identified and since they're passed through the
>> sev_encrypt_flash interface, the hashes will be accumulated by the PSP
>> measurement (SEV_LAUNCH_MEASURE).
>>
>> Co-developed-by: James Bottomley <jejb@linux.ibm.com>
>> Signed-off-by: James Bottomley <jejb@linux.ibm.com>
>> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
>> Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
>> ---
>>  target/i386/sev_i386.h |  12 ++++
>>  target/i386/sev-stub.c |   5 ++
>>  target/i386/sev.c      | 137 +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 154 insertions(+)
>>
>> diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
>> index ae6d840478..deb3eec409 100644
>> --- a/target/i386/sev_i386.h
>> +++ b/target/i386/sev_i386.h
>> @@ -28,6 +28,17 @@
>>  #define SEV_POLICY_DOMAIN       0x10
>>  #define SEV_POLICY_SEV          0x20
>>  
>> +typedef struct KernelLoaderContext {
>> +    char *setup_data;
>> +    size_t setup_size;
>> +    char *kernel_data;
>> +    size_t kernel_size;
>> +    char *initrd_data;
>> +    size_t initrd_size;
>> +    char *cmdline_data;
>> +    size_t cmdline_size;
>> +} KernelLoaderContext;
> 
> I'd expect the struct to have 'Sev' as its name prefix, in common
> with everything else SEV related that's exported here. 

Yes, you're right.  I'll fix that.

-Dov

> 
>> +
>>  extern bool sev_es_enabled(void);
>>  extern uint64_t sev_get_me_mask(void);
>>  extern SevInfo *sev_get_info(void);
>> @@ -37,5 +48,6 @@ extern char *sev_get_launch_measurement(void);
>>  extern SevCapability *sev_get_capabilities(Error **errp);
>>  extern SevAttestationReport *
>>  sev_get_attestation_report(const char *mnonce, Error **errp);
>> +extern bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp);
> 
> Regards,
> Daniel
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-08-25  7:35 ` [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
@ 2021-09-27 17:00   ` Daniel P. Berrangé
  2021-09-29  9:39     ` Dov Murik
  0 siblings, 1 reply; 16+ messages in thread
From: Daniel P. Berrangé @ 2021-09-27 17:00 UTC (permalink / raw)
  To: Dov Murik
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Connor Kuehl, Philippe Mathieu-Daudé,
	James Bottomley, Richard Henderson, qemu-devel,
	Dr. David Alan Gilbert, Hubertus Franke, Jim Cadden,
	Tobin Feldman-Fitzthum, Paolo Bonzini, Laszlo Ersek

On Wed, Aug 25, 2021 at 07:35:37AM +0000, Dov Murik wrote:
> Add the sev_add_kernel_loader_hashes function to calculate the hashes of
> the kernel/initrd/cmdline and fill a designated OVMF encrypted hash
> table area.  For this to work, OVMF must support an encrypted area to
> place the data which is advertised via a special GUID in the OVMF reset
> table.
> 
> The hashes of each of the files is calculated (or the string in the case
> of the cmdline with trailing '\0' included).  Each entry in the hashes
> table is GUID identified and since they're passed through the
> sev_encrypt_flash interface, the hashes will be accumulated by the PSP
> measurement (SEV_LAUNCH_MEASURE).
> 
> Co-developed-by: James Bottomley <jejb@linux.ibm.com>
> Signed-off-by: James Bottomley <jejb@linux.ibm.com>
> Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
> Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
> ---
>  target/i386/sev_i386.h |  12 ++++
>  target/i386/sev-stub.c |   5 ++
>  target/i386/sev.c      | 137 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 154 insertions(+)
> 
> diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
> index ae6d840478..deb3eec409 100644
> --- a/target/i386/sev_i386.h
> +++ b/target/i386/sev_i386.h
> @@ -28,6 +28,17 @@
>  #define SEV_POLICY_DOMAIN       0x10
>  #define SEV_POLICY_SEV          0x20
>  
> +typedef struct KernelLoaderContext {
> +    char *setup_data;
> +    size_t setup_size;
> +    char *kernel_data;
> +    size_t kernel_size;
> +    char *initrd_data;
> +    size_t initrd_size;
> +    char *cmdline_data;
> +    size_t cmdline_size;
> +} KernelLoaderContext;

I'd expect the struct to have 'Sev' as its name prefix, in common
with everything else SEV related that's exported here. 

> +
>  extern bool sev_es_enabled(void);
>  extern uint64_t sev_get_me_mask(void);
>  extern SevInfo *sev_get_info(void);
> @@ -37,5 +48,6 @@ extern char *sev_get_launch_measurement(void);
>  extern SevCapability *sev_get_capabilities(Error **errp);
>  extern SevAttestationReport *
>  sev_get_attestation_report(const char *mnonce, Error **errp);
> +extern bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp);

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-08-25  7:35 [PATCH v3 0/2] [RESEND] " Dov Murik
@ 2021-08-25  7:35 ` Dov Murik
  2021-09-27 17:00   ` Daniel P. Berrangé
  0 siblings, 1 reply; 16+ messages in thread
From: Dov Murik @ 2021-08-25  7:35 UTC (permalink / raw)
  To: qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Connor Kuehl, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert, Dov Murik,
	Hubertus Franke, Tobin Feldman-Fitzthum, Jim Cadden,
	Paolo Bonzini, Philippe Mathieu-Daudé

Add the sev_add_kernel_loader_hashes function to calculate the hashes of
the kernel/initrd/cmdline and fill a designated OVMF encrypted hash
table area.  For this to work, OVMF must support an encrypted area to
place the data which is advertised via a special GUID in the OVMF reset
table.

The hashes of each of the files is calculated (or the string in the case
of the cmdline with trailing '\0' included).  Each entry in the hashes
table is GUID identified and since they're passed through the
sev_encrypt_flash interface, the hashes will be accumulated by the PSP
measurement (SEV_LAUNCH_MEASURE).

Co-developed-by: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: James Bottomley <jejb@linux.ibm.com>
Signed-off-by: Dov Murik <dovmurik@linux.ibm.com>
Reviewed-by: Connor Kuehl <ckuehl@redhat.com>
---
 target/i386/sev_i386.h |  12 ++++
 target/i386/sev-stub.c |   5 ++
 target/i386/sev.c      | 137 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 154 insertions(+)

diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h
index ae6d840478..deb3eec409 100644
--- a/target/i386/sev_i386.h
+++ b/target/i386/sev_i386.h
@@ -28,6 +28,17 @@
 #define SEV_POLICY_DOMAIN       0x10
 #define SEV_POLICY_SEV          0x20
 
+typedef struct KernelLoaderContext {
+    char *setup_data;
+    size_t setup_size;
+    char *kernel_data;
+    size_t kernel_size;
+    char *initrd_data;
+    size_t initrd_size;
+    char *cmdline_data;
+    size_t cmdline_size;
+} KernelLoaderContext;
+
 extern bool sev_es_enabled(void);
 extern uint64_t sev_get_me_mask(void);
 extern SevInfo *sev_get_info(void);
@@ -37,5 +48,6 @@ extern char *sev_get_launch_measurement(void);
 extern SevCapability *sev_get_capabilities(Error **errp);
 extern SevAttestationReport *
 sev_get_attestation_report(const char *mnonce, Error **errp);
+extern bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp);
 
 #endif
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 0227cb5177..addb089f36 100644
--- a/target/i386/sev-stub.c
+++ b/target/i386/sev-stub.c
@@ -81,3 +81,8 @@ sev_get_attestation_report(const char *mnonce, Error **errp)
     error_setg(errp, "SEV is not available in this QEMU");
     return NULL;
 }
+
+bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp)
+{
+    g_assert_not_reached();
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 83df8c09f6..857d75bd3e 100644
--- a/target/i386/sev.c
+++ b/target/i386/sev.c
@@ -23,6 +23,7 @@
 #include "qemu/base64.h"
 #include "qemu/module.h"
 #include "qemu/uuid.h"
+#include "crypto/hash.h"
 #include "sysemu/kvm.h"
 #include "sev_i386.h"
 #include "sysemu/sysemu.h"
@@ -83,6 +84,32 @@ typedef struct __attribute__((__packed__)) SevInfoBlock {
     uint32_t reset_addr;
 } SevInfoBlock;
 
+#define SEV_HASH_TABLE_RV_GUID  "7255371f-3a3b-4b04-927b-1da6efa8d454"
+typedef struct QEMU_PACKED SevHashTableDescriptor {
+    /* SEV hash table area guest address */
+    uint32_t base;
+    /* SEV hash table area size (in bytes) */
+    uint32_t size;
+} SevHashTableDescriptor;
+
+/* hard code sha256 digest size */
+#define HASH_SIZE 32
+
+typedef struct QEMU_PACKED SevHashTableEntry {
+    QemuUUID guid;
+    uint16_t len;
+    uint8_t hash[HASH_SIZE];
+} SevHashTableEntry;
+
+typedef struct QEMU_PACKED SevHashTable {
+    QemuUUID guid;
+    uint16_t len;
+    SevHashTableEntry cmdline;
+    SevHashTableEntry initrd;
+    SevHashTableEntry kernel;
+    uint8_t padding[];
+} SevHashTable;
+
 static SevGuestState *sev_guest;
 static Error *sev_mig_blocker;
 
@@ -1077,6 +1104,116 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size)
     return 0;
 }
 
+static const QemuUUID sev_hash_table_header_guid = {
+    .data = UUID_LE(0x9438d606, 0x4f22, 0x4cc9, 0xb4, 0x79, 0xa7, 0x93,
+                    0xd4, 0x11, 0xfd, 0x21)
+};
+
+static const QemuUUID sev_kernel_entry_guid = {
+    .data = UUID_LE(0x4de79437, 0xabd2, 0x427f, 0xb8, 0x35, 0xd5, 0xb1,
+                    0x72, 0xd2, 0x04, 0x5b)
+};
+static const QemuUUID sev_initrd_entry_guid = {
+    .data = UUID_LE(0x44baf731, 0x3a2f, 0x4bd7, 0x9a, 0xf1, 0x41, 0xe2,
+                    0x91, 0x69, 0x78, 0x1d)
+};
+static const QemuUUID sev_cmdline_entry_guid = {
+    .data = UUID_LE(0x97d02dd8, 0xbd20, 0x4c94, 0xaa, 0x78, 0xe7, 0x71,
+                    0x4d, 0x36, 0xab, 0x2a)
+};
+
+/*
+ * Add the hashes of the linux kernel/initrd/cmdline to an encrypted guest page
+ * which is included in SEV's initial memory measurement.
+ */
+bool sev_add_kernel_loader_hashes(KernelLoaderContext *ctx, Error **errp)
+{
+    uint8_t *data;
+    SevHashTableDescriptor *area;
+    SevHashTable *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;
+
+    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");
+        return false;
+    }
+    area = (SevHashTableDescriptor *)data;
+
+    /*
+     * Calculate hash of kernel command-line with the terminating null byte. If
+     * the user doesn't supply a command-line via -append, the 1-byte "\0" will
+     * be used.
+     */
+    hashp = cmdline_hash;
+    if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->cmdline_data,
+                           ctx->cmdline_size, &hashp, &hash_len, errp) < 0) {
+        return false;
+    }
+    assert(hash_len == HASH_SIZE);
+
+    /*
+     * Calculate hash of initrd. If the user doesn't supply an initrd via
+     * -initrd, an empty buffer will be used (ctx->initrd_size == 0).
+     */
+    hashp = initrd_hash;
+    if (qcrypto_hash_bytes(QCRYPTO_HASH_ALG_SHA256, ctx->initrd_data,
+                           ctx->initrd_size, &hashp, &hash_len, errp) < 0) {
+        return false;
+    }
+    assert(hash_len == HASH_SIZE);
+
+    /* Calculate hash of the kernel */
+    hashp = kernel_hash;
+    struct iovec iov[2] = {
+        { .iov_base = ctx->setup_data, .iov_len = ctx->setup_size },
+        { .iov_base = ctx->kernel_data, .iov_len = ctx->kernel_size }
+    };
+    if (qcrypto_hash_bytesv(QCRYPTO_HASH_ALG_SHA256, iov, ARRAY_SIZE(iov),
+                            &hashp, &hash_len, errp) < 0) {
+        return false;
+    }
+    assert(hash_len == HASH_SIZE);
+
+    /*
+     * 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);
+
+    ht->guid = sev_hash_table_header_guid;
+    ht->len = sizeof(*ht);
+
+    ht->cmdline.guid = sev_cmdline_entry_guid;
+    ht->cmdline.len = sizeof(ht->cmdline);
+    memcpy(ht->cmdline.hash, cmdline_hash, sizeof(ht->cmdline.hash));
+
+    ht->initrd.guid = sev_initrd_entry_guid;
+    ht->initrd.len = sizeof(ht->initrd);
+    memcpy(ht->initrd.hash, initrd_hash, sizeof(ht->initrd.hash));
+
+    ht->kernel.guid = sev_kernel_entry_guid;
+    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);
+    }
+
+    if (sev_encrypt_flash((uint8_t *)ht, aligned_len, errp) < 0) {
+        return false;
+    }
+
+    return true;
+}
+
 static void
 sev_register_types(void)
 {
-- 
2.25.1



^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-09-29  9:42 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-24 10:20 [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
2021-06-24 10:20 ` [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
2021-07-01 17:23   ` Connor Kuehl
2021-07-02 12:29     ` Dov Murik
2021-06-24 10:20 ` [PATCH v3 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux Dov Murik
2021-07-08 16:41 ` [PATCH v3 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Connor Kuehl
2021-07-08 17:03   ` Philippe Mathieu-Daudé
2021-07-08 17:16     ` Connor Kuehl
2021-07-29 19:31       ` Dov Murik
2021-07-30 14:47         ` Connor Kuehl
2021-07-30 18:02           ` Dov Murik
2021-07-30 18:14             ` Connor Kuehl
2021-07-09  6:55 ` Michael S. Tsirkin
2021-08-25  7:35 [PATCH v3 0/2] [RESEND] " Dov Murik
2021-08-25  7:35 ` [PATCH v3 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
2021-09-27 17:00   ` Daniel P. Berrangé
2021-09-29  9:39     ` Dov Murik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).