qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
@ 2021-09-30  5:49 Dov Murik
  2021-09-30  5:49 ` [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Dov Murik @ 2021-09-30  5:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Daniel P. Berrangé,
	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,
	Brijesh Singh, 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 AMD 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 [1] is already available in edk2 (patch series
"Measured SEV boot with kernel/initrd/cmdline").

[1] https://edk2.groups.io/g/devel/message/78250

---

v4 changes:
 - struct and variable renames (KernelLoaderContext -> SevKernelLoaderContext,
   kernel_loader_context -> sev_load_ctx).

v3 resend: https://lore.kernel.org/qemu-devel/20210825073538.959525-1-dovmurik@linux.ibm.com/
v3: https://lore.kernel.org/qemu-devel/20210624102040.2015280-1-dovmurik@linux.ibm.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(-)

-- 
2.25.1



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

* [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-09-30  5:49 [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
@ 2021-09-30  5:49 ` Dov Murik
  2021-09-30  8:32   ` Daniel P. Berrangé
  2021-10-18 18:02   ` Tom Lendacky
  2021-09-30  5:49 ` [PATCH v4 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux Dov Murik
  2021-10-04  8:03 ` [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Paolo Bonzini
  2 siblings, 2 replies; 13+ messages in thread
From: Dov Murik @ 2021-09-30  5:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Daniel P. Berrangé,
	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,
	Brijesh Singh, 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 AMD
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..2afe108069 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 SevKernelLoaderContext {
+    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;
+} SevKernelLoaderContext;
+
 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(SevKernelLoaderContext *ctx, Error **errp);
 
 #endif
diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c
index 0227cb5177..d8e6583171 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(SevKernelLoaderContext *ctx, Error **errp)
+{
+    g_assert_not_reached();
+}
diff --git a/target/i386/sev.c b/target/i386/sev.c
index 0b2c8f594a..8b98e184c2 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;
 
@@ -1071,6 +1098,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(SevKernelLoaderContext *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] 13+ messages in thread

* [PATCH v4 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux
  2021-09-30  5:49 [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
  2021-09-30  5:49 ` [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
@ 2021-09-30  5:49 ` Dov Murik
  2021-10-04  8:03 ` [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Paolo Bonzini
  2 siblings, 0 replies; 13+ messages in thread
From: Dov Murik @ 2021-09-30  5:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Tom Lendacky, Ashish Kalra, Daniel P . Berrangé,
	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,
	Brijesh Singh, 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: Daniel P. Berrangé <berrange@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 00448ed55a..3f37d17b5c 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;
+    SevKernelLoaderContext sev_load_ctx = {};
 
     /* 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);
+    sev_load_ctx.cmdline_data = (char *)kernel_cmdline;
+    sev_load_ctx.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);
+        sev_load_ctx.initrd_data = initrd_data;
+        sev_load_ctx.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);
+    sev_load_ctx.kernel_data = (char *)kernel;
+    sev_load_ctx.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);
+    sev_load_ctx.setup_data = (char *)setup;
+    sev_load_ctx.setup_size = setup_size;
+
+    if (sev_enabled()) {
+        sev_add_kernel_loader_hashes(&sev_load_ctx, &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] 13+ messages in thread

* Re: [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-09-30  5:49 ` [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
@ 2021-09-30  8:32   ` Daniel P. Berrangé
  2021-09-30 10:13     ` Dov Murik
  2021-10-18 18:02   ` Tom Lendacky
  1 sibling, 1 reply; 13+ messages in thread
From: Daniel P. Berrangé @ 2021-09-30  8:32 UTC (permalink / raw)
  To: Dov Murik
  Cc: Tom Lendacky, Ashish Kalra, Brijesh Singh, Eduardo Habkost,
	Michael S. Tsirkin, Connor Kuehl, Laszlo Ersek, James Bottomley,
	Richard Henderson, Dr. David Alan Gilbert, qemu-devel,
	Hubertus Franke, Tobin Feldman-Fitzthum, Jim Cadden,
	Paolo Bonzini, Philippe Mathieu-Daudé

On Thu, Sep 30, 2021 at 08:49:14AM +0300, 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 AMD
> 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(+)

Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>


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] 13+ messages in thread

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


On 30/09/2021 11:32, Daniel P. Berrangé wrote:
> 
> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> 

Thanks!

-Dov


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

* Re: [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline
  2021-09-30  5:49 [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
  2021-09-30  5:49 ` [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
  2021-09-30  5:49 ` [PATCH v4 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux Dov Murik
@ 2021-10-04  8:03 ` Paolo Bonzini
  2021-10-04 17:23   ` Dov Murik
  2 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2021-10-04  8:03 UTC (permalink / raw)
  To: Dov Murik
  Cc: Tom Lendacky, Ashish Kalra, Daniel P. Berrangé,
	Eduardo Habkost, Michael S. Tsirkin, Connor Kuehl, Laszlo Ersek,
	James Bottomley, Richard Henderson, Dr. David Alan Gilbert,
	qemu-devel, Hubertus Franke, Tobin Feldman-Fitzthum, Jim Cadden,
	Brijesh Singh, Philippe Mathieu-Daudé

Queued, thanks.  However, it would be nice to have a documentation of
all our SEV firmware interfaces somewhere in docs/specs/.

Paolo

On Thu, Sep 30, 2021 at 7:49 AM Dov Murik <dovmurik@linux.ibm.com> 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 AMD 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 [1] is already available in edk2 (patch series
> "Measured SEV boot with kernel/initrd/cmdline").
>
> [1] https://edk2.groups.io/g/devel/message/78250
>
> ---
>
> v4 changes:
>  - struct and variable renames (KernelLoaderContext -> SevKernelLoaderContext,
>    kernel_loader_context -> sev_load_ctx).
>
> v3 resend: https://lore.kernel.org/qemu-devel/20210825073538.959525-1-dovmurik@linux.ibm.com/
> v3: https://lore.kernel.org/qemu-devel/20210624102040.2015280-1-dovmurik@linux.ibm.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(-)
>
> --
> 2.25.1
>



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

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


On 04/10/2021 11:03, Paolo Bonzini wrote:
> Queued, thanks.  However, it would be nice to have a documentation of
> all our SEV firmware interfaces somewhere in docs/specs/.

Thanks Paolo.

I'll try to arrange a skeleton for such document.  So far I think we
have the following interfaces:

1. SEV_SECRET_GUID - Secret injection target page
2. SEV_INFO_BLOCK_GUID - Used (currently) for the SEV-ES AP reset vector
3. SEV_HASH_TABLE_RV_GUID - For hashes of kernel/initrd/cmdline


-Dov


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

* Re: [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-09-30  5:49 ` [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
  2021-09-30  8:32   ` Daniel P. Berrangé
@ 2021-10-18 18:02   ` Tom Lendacky
  2021-10-19  6:18     ` Dov Murik
  1 sibling, 1 reply; 13+ messages in thread
From: Tom Lendacky @ 2021-10-18 18:02 UTC (permalink / raw)
  To: Dov Murik, qemu-devel
  Cc: James Bottomley, Daniel P. Berrangé,
	Michael S. Tsirkin, Marcel Apfelbaum, Paolo Bonzini,
	Dr. David Alan Gilbert, Richard Henderson, Eduardo Habkost,
	Connor Kuehl, Philippe Mathieu-Daudé,
	Laszlo Ersek, Ashish Kalra, Brijesh Singh,
	Tobin Feldman-Fitzthum, Jim Cadden, Hubertus Franke

On 9/30/21 12:49 AM, Dov Murik wrote:

...

> +/*
> + * 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(SevKernelLoaderContext *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;
> +    }

This breaks backwards compatibility with an older OVMF image. Any older 
OVMF image with SEV support that doesn't have the hash table GUID will now 
fail to boot using -kernel/-initrd/-append, where it used to be able to 
boot before.

Is that anything we need to be concerned about?

Thanks,
Tom



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

* Re: [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-10-18 18:02   ` Tom Lendacky
@ 2021-10-19  6:18     ` Dov Murik
  2021-10-20 15:26       ` Tom Lendacky
  0 siblings, 1 reply; 13+ messages in thread
From: Dov Murik @ 2021-10-19  6:18 UTC (permalink / raw)
  To: Tom Lendacky, qemu-devel
  Cc: Dov Murik, Ashish Kalra, Daniel P. Berrangé,
	Eduardo Habkost, Michael S. Tsirkin, Connor Kuehl, Laszlo Ersek,
	James Bottomley, Richard Henderson, Dr. David Alan Gilbert,
	Hubertus Franke, Tobin Feldman-Fitzthum, Jim Cadden,
	Brijesh Singh, Paolo Bonzini, Philippe Mathieu-Daudé



On 18/10/2021 21:02, Tom Lendacky wrote:
> On 9/30/21 12:49 AM, Dov Murik wrote:
> 
> ...
> 
>> +/*
>> + * 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(SevKernelLoaderContext *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;
>> +    }
> 
> This breaks backwards compatibility with an older OVMF image. Any older
> OVMF image with SEV support that doesn't have the hash table GUID will
> now fail to boot using -kernel/-initrd/-append, where it used to be able
> to boot before.
> 


Thanks Tom for noticing this.

Just so we're on the same page: this patch is already merged.


We're dealing with a scenario of launching a guest with SEV enabled and
with -kernel.  The behaviours are:


A. With current QEMU:

A1. New AmdSev OVMF build: OVMF will verify the hashes and boot correctly.
A2. New Generic OvmfPkgX64 build: No verification but will boot correctly.

A3. Old AmdSev OVMF build: QEMU aborts the launch because there's no
hash table GUID.
A4. Old Generic OvmfPkgX64 build: QEMU aborts the launch because there's
no hash table GUID.


B. With older QEMU (before this patch was merged):

B1. New AmdSev OVMF build: OVMF will try to verify the hashes but they
are not populated; boot aborted.
B2. New Generic OvmfPkgX64 build: No verification but will boot correctly.

B3. Old AmdSev OVMF build: OVMF aborts the launch because -kernel is not
supported at all.
B4. Old Generic OvmfPkgX64 build: No verification but will boot correctly.


So the problem you are raising is scenario A4 (as opposed to previous
behaviour B4).



> Is that anything we need to be concerned about?
> 

Possible solutions:

1. Do nothing. For users that encounter this: tell them to upgrade OVMF.
2. Modify the code: remove the line: error_setg(errp, "SEV: kernel
specified but OVMF has no hash table guid")

I think that option 2 will not degrade security *if* the Guest Owner
verifies the measurement (which is mandatory anyway; otherwise the
untrusted host can replace OVMF with a "malicious" version that doesn't
verify the hashes). Skipping silently might make debugging a bit harder.
Maybe we can print a warning and return, and then the guest launch will
continue?

Other ideas?


-Dov



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

* Re: [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-10-19  6:18     ` Dov Murik
@ 2021-10-20 15:26       ` Tom Lendacky
  2021-10-27 19:43         ` Brijesh Singh
  0 siblings, 1 reply; 13+ messages in thread
From: Tom Lendacky @ 2021-10-20 15:26 UTC (permalink / raw)
  To: Dov Murik, qemu-devel
  Cc: James Bottomley, Daniel P. Berrangé,
	Michael S. Tsirkin, Marcel Apfelbaum, Paolo Bonzini,
	Dr. David Alan Gilbert, Richard Henderson, Eduardo Habkost,
	Connor Kuehl, Philippe Mathieu-Daudé,
	Laszlo Ersek, Ashish Kalra, Brijesh Singh,
	Tobin Feldman-Fitzthum, Jim Cadden, Hubertus Franke

On 10/19/21 1:18 AM, Dov Murik wrote:
> On 18/10/2021 21:02, Tom Lendacky wrote:
>> On 9/30/21 12:49 AM, Dov Murik wrote:
>>
>> ...
>>
>>> +/*
>>> + * 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(SevKernelLoaderContext *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;
>>> +    }
>>
>> This breaks backwards compatibility with an older OVMF image. Any older
>> OVMF image with SEV support that doesn't have the hash table GUID will
>> now fail to boot using -kernel/-initrd/-append, where it used to be able
>> to boot before.
>>
> 
> 
> Thanks Tom for noticing this.
> 
> Just so we're on the same page: this patch is already merged.

Right, just not in a release, yet.

> 
> 
> We're dealing with a scenario of launching a guest with SEV enabled and
> with -kernel.  The behaviours are:
> 
> 
> A. With current QEMU:
> 
> A1. New AmdSev OVMF build: OVMF will verify the hashes and boot correctly.
> A2. New Generic OvmfPkgX64 build: No verification but will boot correctly.
> 
> A3. Old AmdSev OVMF build: QEMU aborts the launch because there's no
> hash table GUID.
> A4. Old Generic OvmfPkgX64 build: QEMU aborts the launch because there's
> no hash table GUID.
> 
> 
> B. With older QEMU (before this patch was merged):
> 
> B1. New AmdSev OVMF build: OVMF will try to verify the hashes but they
> are not populated; boot aborted.
> B2. New Generic OvmfPkgX64 build: No verification but will boot correctly.
> 
> B3. Old AmdSev OVMF build: OVMF aborts the launch because -kernel is not
> supported at all.
> B4. Old Generic OvmfPkgX64 build: No verification but will boot correctly.
> 
> 
> So the problem you are raising is scenario A4 (as opposed to previous
> behaviour B4).

Correct, scenario A4.

> 
> 
> 
>> Is that anything we need to be concerned about?
>>
> 
> Possible solutions:
> 
> 1. Do nothing. For users that encounter this: tell them to upgrade OVMF.
> 2. Modify the code: remove the line: error_setg(errp, "SEV: kernel
> specified but OVMF has no hash table guid")
> 
> I think that option 2 will not degrade security *if* the Guest Owner
> verifies the measurement (which is mandatory anyway; otherwise the
> untrusted host can replace OVMF with a "malicious" version that doesn't
> verify the hashes). Skipping silently might make debugging a bit harder.
> Maybe we can print a warning and return, and then the guest launch will
> continue?

That sounds like it might be the best approach if there are no security 
concerns. I agree with printing a message, either informational or warning 
is ok by me.

Lets see if anyone else has some thoughts/ideas.

Thanks,
Tom

> 
> Other ideas?
> 
> 
> -Dov
> 


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

* Re: [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
  2021-10-20 15:26       ` Tom Lendacky
@ 2021-10-27 19:43         ` Brijesh Singh
  2021-10-28  8:41           ` Dov Murik
  0 siblings, 1 reply; 13+ messages in thread
From: Brijesh Singh @ 2021-10-27 19:43 UTC (permalink / raw)
  To: Tom Lendacky, Dov Murik, qemu-devel
  Cc: brijesh.singh, James Bottomley, Daniel P. Berrangé,
	Michael S. Tsirkin, Marcel Apfelbaum, Paolo Bonzini,
	Dr. David Alan Gilbert, Richard Henderson, Eduardo Habkost,
	Connor Kuehl, Philippe Mathieu-Daudé,
	Laszlo Ersek, Ashish Kalra, Tobin Feldman-Fitzthum, Jim Cadden,
	Hubertus Franke

Hi Dov,

Sorry for coming a bit late on it but I am seeing another issue with 
this patch. The hash build logic looks for a SEV_HASH_TABLE_RV_GUID in 
the GUID list. If found, it uses the base address to store the hash'es. 
Looking at the OVMF, it seems that base address for this GUID is zero. 
It seems that by default the Base Address is non-zero for the AmdSev 
Package build only.

Can we add a check in the sev_add_kernel_loader_hashes() to verify that 
base address is non-zero and at the same time improve OVMF to update 
*.fdf to reserve this page in the MEMFD ?

Thanks
Brijesh

On 10/20/21 10:26 AM, Tom Lendacky wrote:
> On 10/19/21 1:18 AM, Dov Murik wrote:
>> On 18/10/2021 21:02, Tom Lendacky wrote:
>>> On 9/30/21 12:49 AM, Dov Murik wrote:
>>>
>>> ...
>>>
>>>> +/*
>>>> + * 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(SevKernelLoaderContext *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;
>>>> +    }
>>>
>>> This breaks backwards compatibility with an older OVMF image. Any older
>>> OVMF image with SEV support that doesn't have the hash table GUID will
>>> now fail to boot using -kernel/-initrd/-append, where it used to be able
>>> to boot before.
>>>
>>
>>
>> Thanks Tom for noticing this.
>>
>> Just so we're on the same page: this patch is already merged.
> 
> Right, just not in a release, yet.
> 
>>
>>
>> We're dealing with a scenario of launching a guest with SEV enabled and
>> with -kernel.  The behaviours are:
>>
>>
>> A. With current QEMU:
>>
>> A1. New AmdSev OVMF build: OVMF will verify the hashes and boot 
>> correctly.
>> A2. New Generic OvmfPkgX64 build: No verification but will boot 
>> correctly.
>>
>> A3. Old AmdSev OVMF build: QEMU aborts the launch because there's no
>> hash table GUID.
>> A4. Old Generic OvmfPkgX64 build: QEMU aborts the launch because there's
>> no hash table GUID.
>>
>>
>> B. With older QEMU (before this patch was merged):
>>
>> B1. New AmdSev OVMF build: OVMF will try to verify the hashes but they
>> are not populated; boot aborted.
>> B2. New Generic OvmfPkgX64 build: No verification but will boot 
>> correctly.
>>
>> B3. Old AmdSev OVMF build: OVMF aborts the launch because -kernel is not
>> supported at all.
>> B4. Old Generic OvmfPkgX64 build: No verification but will boot 
>> correctly.
>>
>>
>> So the problem you are raising is scenario A4 (as opposed to previous
>> behaviour B4).
> 
> Correct, scenario A4.
> 
>>
>>
>>
>>> Is that anything we need to be concerned about?
>>>
>>
>> Possible solutions:
>>
>> 1. Do nothing. For users that encounter this: tell them to upgrade OVMF.
>> 2. Modify the code: remove the line: error_setg(errp, "SEV: kernel
>> specified but OVMF has no hash table guid")
>>
>> I think that option 2 will not degrade security *if* the Guest Owner
>> verifies the measurement (which is mandatory anyway; otherwise the
>> untrusted host can replace OVMF with a "malicious" version that doesn't
>> verify the hashes). Skipping silently might make debugging a bit harder.
>> Maybe we can print a warning and return, and then the guest launch will
>> continue?
> 
> That sounds like it might be the best approach if there are no security 
> concerns. I agree with printing a message, either informational or 
> warning is ok by me.
> 
> Lets see if anyone else has some thoughts/ideas.
> 
> Thanks,
> Tom
> 
>>
>> Other ideas?
>>
>>
>> -Dov
>>


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

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



On 27/10/2021 22:43, Brijesh Singh wrote:
> Hi Dov,
> 
> Sorry for coming a bit late on it but I am seeing another issue with
> this patch. The hash build logic looks for a SEV_HASH_TABLE_RV_GUID in
> the GUID list. If found, it uses the base address to store the hash'es.
> Looking at the OVMF, it seems that base address for this GUID is zero.

Yes, I managed to reproduce this.  With the OvmfPkgX64 build I see that
the GUID exists but base=0 and size=0.  That size should be illegal
anyway for QEMU to fill.


> It seems that by default the Base Address is non-zero for the AmdSev
> Package build only.
> 
> Can we add a check in the sev_add_kernel_loader_hashes() to verify that
> base address is non-zero and at the same time improve OVMF to update
> *.fdf to reserve this page in the MEMFD ?

I'll prepare QEMU fixes:

1. (reported by Tom) when no SEV_HASH_TABLE_RV_GUID entry is found -
just warn and continue boot.
2. (reported by Brijesh) verify that base != 0 (supposedly GPA 0 is a
valid address, but I'm willing to take a chance here and not allow it)
and size is big enough for the hashes table structure+padding. If not,
warn and continue boot.

Separately I'll try to solve the issue in the other OVMF *.fdf's.



Thanks for reporting this.

-Dov


> 
> Thanks
> Brijesh
> 
> On 10/20/21 10:26 AM, Tom Lendacky wrote:
>> On 10/19/21 1:18 AM, Dov Murik wrote:
>>> On 18/10/2021 21:02, Tom Lendacky wrote:
>>>> On 9/30/21 12:49 AM, Dov Murik wrote:
>>>>
>>>> ...
>>>>
>>>>> +/*
>>>>> + * 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(SevKernelLoaderContext *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;
>>>>> +    }
>>>>
>>>> This breaks backwards compatibility with an older OVMF image. Any older
>>>> OVMF image with SEV support that doesn't have the hash table GUID will
>>>> now fail to boot using -kernel/-initrd/-append, where it used to be
>>>> able
>>>> to boot before.
>>>>
>>>
>>>
>>> Thanks Tom for noticing this.
>>>
>>> Just so we're on the same page: this patch is already merged.
>>
>> Right, just not in a release, yet.
>>
>>>
>>>
>>> We're dealing with a scenario of launching a guest with SEV enabled and
>>> with -kernel.  The behaviours are:
>>>
>>>
>>> A. With current QEMU:
>>>
>>> A1. New AmdSev OVMF build: OVMF will verify the hashes and boot
>>> correctly.
>>> A2. New Generic OvmfPkgX64 build: No verification but will boot
>>> correctly.
>>>
>>> A3. Old AmdSev OVMF build: QEMU aborts the launch because there's no
>>> hash table GUID.
>>> A4. Old Generic OvmfPkgX64 build: QEMU aborts the launch because there's
>>> no hash table GUID.
>>>
>>>
>>> B. With older QEMU (before this patch was merged):
>>>
>>> B1. New AmdSev OVMF build: OVMF will try to verify the hashes but they
>>> are not populated; boot aborted.
>>> B2. New Generic OvmfPkgX64 build: No verification but will boot
>>> correctly.
>>>
>>> B3. Old AmdSev OVMF build: OVMF aborts the launch because -kernel is not
>>> supported at all.
>>> B4. Old Generic OvmfPkgX64 build: No verification but will boot
>>> correctly.
>>>
>>>
>>> So the problem you are raising is scenario A4 (as opposed to previous
>>> behaviour B4).
>>
>> Correct, scenario A4.
>>
>>>
>>>
>>>
>>>> Is that anything we need to be concerned about?
>>>>
>>>
>>> Possible solutions:
>>>
>>> 1. Do nothing. For users that encounter this: tell them to upgrade OVMF.
>>> 2. Modify the code: remove the line: error_setg(errp, "SEV: kernel
>>> specified but OVMF has no hash table guid")
>>>
>>> I think that option 2 will not degrade security *if* the Guest Owner
>>> verifies the measurement (which is mandatory anyway; otherwise the
>>> untrusted host can replace OVMF with a "malicious" version that doesn't
>>> verify the hashes). Skipping silently might make debugging a bit harder.
>>> Maybe we can print a warning and return, and then the guest launch will
>>> continue?
>>
>> That sounds like it might be the best approach if there are no
>> security concerns. I agree with printing a message, either
>> informational or warning is ok by me.
>>
>> Lets see if anyone else has some thoughts/ideas.
>>
>> Thanks,
>> Tom
>>
>>>
>>> Other ideas?
>>>
>>>
>>> -Dov
>>>


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

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



On 28/10/2021 11:41, Dov Murik wrote:
> 
> 
> On 27/10/2021 22:43, Brijesh Singh wrote:
>> Hi Dov,
>>
>> Sorry for coming a bit late on it but I am seeing another issue with
>> this patch. The hash build logic looks for a SEV_HASH_TABLE_RV_GUID in
>> the GUID list. If found, it uses the base address to store the hash'es.
>> Looking at the OVMF, it seems that base address for this GUID is zero.
> 
> Yes, I managed to reproduce this.  With the OvmfPkgX64 build I see that
> the GUID exists but base=0 and size=0.  That size should be illegal
> anyway for QEMU to fill.
> 
> 
>> It seems that by default the Base Address is non-zero for the AmdSev
>> Package build only.
>>
>> Can we add a check in the sev_add_kernel_loader_hashes() to verify that
>> base address is non-zero and at the same time improve OVMF to update
>> *.fdf to reserve this page in the MEMFD ?
> 
> I'll prepare QEMU fixes:
> 
> 1. (reported by Tom) when no SEV_HASH_TABLE_RV_GUID entry is found -
> just warn and continue boot.
> 2. (reported by Brijesh) verify that base != 0 (supposedly GPA 0 is a
> valid address, but I'm willing to take a chance here and not allow it)
> and size is big enough for the hashes table structure+padding. If not,
> warn and continue boot.

I submitted this small series [1].  Tom, Brijesh, I hope this solves
the issues you're experiencing and allows you to boot (and
displays a QEMU warning during launch).

[1] https://lore.kernel.org/qemu-devel/20211101102136.1706421-1-dovmurik@linux.ibm.com/


-Dov


> 
> Separately I'll try to solve the issue in the other OVMF *.fdf's.
> 
> 
> 
> Thanks for reporting this.
> 
> -Dov
> 
> 
>>
>> Thanks
>> Brijesh
>>
>> On 10/20/21 10:26 AM, Tom Lendacky wrote:
>>> On 10/19/21 1:18 AM, Dov Murik wrote:
>>>> On 18/10/2021 21:02, Tom Lendacky wrote:
>>>>> On 9/30/21 12:49 AM, Dov Murik wrote:
>>>>>
>>>>> ...
>>>>>
>>>>>> +/*
>>>>>> + * 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(SevKernelLoaderContext *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;
>>>>>> +    }
>>>>>
>>>>> This breaks backwards compatibility with an older OVMF image. Any older
>>>>> OVMF image with SEV support that doesn't have the hash table GUID will
>>>>> now fail to boot using -kernel/-initrd/-append, where it used to be
>>>>> able
>>>>> to boot before.
>>>>>
>>>>
>>>>
>>>> Thanks Tom for noticing this.
>>>>
>>>> Just so we're on the same page: this patch is already merged.
>>>
>>> Right, just not in a release, yet.
>>>
>>>>
>>>>
>>>> We're dealing with a scenario of launching a guest with SEV enabled and
>>>> with -kernel.  The behaviours are:
>>>>
>>>>
>>>> A. With current QEMU:
>>>>
>>>> A1. New AmdSev OVMF build: OVMF will verify the hashes and boot
>>>> correctly.
>>>> A2. New Generic OvmfPkgX64 build: No verification but will boot
>>>> correctly.
>>>>
>>>> A3. Old AmdSev OVMF build: QEMU aborts the launch because there's no
>>>> hash table GUID.
>>>> A4. Old Generic OvmfPkgX64 build: QEMU aborts the launch because there's
>>>> no hash table GUID.
>>>>
>>>>
>>>> B. With older QEMU (before this patch was merged):
>>>>
>>>> B1. New AmdSev OVMF build: OVMF will try to verify the hashes but they
>>>> are not populated; boot aborted.
>>>> B2. New Generic OvmfPkgX64 build: No verification but will boot
>>>> correctly.
>>>>
>>>> B3. Old AmdSev OVMF build: OVMF aborts the launch because -kernel is not
>>>> supported at all.
>>>> B4. Old Generic OvmfPkgX64 build: No verification but will boot
>>>> correctly.
>>>>
>>>>
>>>> So the problem you are raising is scenario A4 (as opposed to previous
>>>> behaviour B4).
>>>
>>> Correct, scenario A4.
>>>
>>>>
>>>>
>>>>
>>>>> Is that anything we need to be concerned about?
>>>>>
>>>>
>>>> Possible solutions:
>>>>
>>>> 1. Do nothing. For users that encounter this: tell them to upgrade OVMF.
>>>> 2. Modify the code: remove the line: error_setg(errp, "SEV: kernel
>>>> specified but OVMF has no hash table guid")
>>>>
>>>> I think that option 2 will not degrade security *if* the Guest Owner
>>>> verifies the measurement (which is mandatory anyway; otherwise the
>>>> untrusted host can replace OVMF with a "malicious" version that doesn't
>>>> verify the hashes). Skipping silently might make debugging a bit harder.
>>>> Maybe we can print a warning and return, and then the guest launch will
>>>> continue?
>>>
>>> That sounds like it might be the best approach if there are no
>>> security concerns. I agree with printing a message, either
>>> informational or warning is ok by me.
>>>
>>> Lets see if anyone else has some thoughts/ideas.
>>>
>>> Thanks,
>>> Tom
>>>
>>>>
>>>> Other ideas?
>>>>
>>>>
>>>> -Dov
>>>>


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

end of thread, other threads:[~2021-11-01 10:31 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-30  5:49 [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Dov Murik
2021-09-30  5:49 ` [PATCH v4 1/2] sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot Dov Murik
2021-09-30  8:32   ` Daniel P. Berrangé
2021-09-30 10:13     ` Dov Murik
2021-10-18 18:02   ` Tom Lendacky
2021-10-19  6:18     ` Dov Murik
2021-10-20 15:26       ` Tom Lendacky
2021-10-27 19:43         ` Brijesh Singh
2021-10-28  8:41           ` Dov Murik
2021-11-01 10:28             ` Dov Murik
2021-09-30  5:49 ` [PATCH v4 2/2] x86/sev: generate SEV kernel loader hashes in x86_load_linux Dov Murik
2021-10-04  8:03 ` [PATCH v4 0/2] x86/sev: Measured Linux SEV guest with kernel/initrd/cmdline Paolo Bonzini
2021-10-04 17:23   ` 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).