diff options
author | Richard Henderson <richard.henderson@linaro.org> | 2021-10-05 11:29:42 -0700 |
---|---|---|
committer | Richard Henderson <richard.henderson@linaro.org> | 2021-10-05 11:29:42 -0700 |
commit | 08a9b68dc033c9826da89f84202e547beadd92f0 (patch) | |
tree | aafcb717250d0cb0648e4d8fee8fe8c6b3489c5b /target | |
parent | 9618c5badaa8eed25259cf095ff880efb939fbe7 (diff) | |
parent | bb647c49b8f1f986d8171dd61db65e8a8d255be0 (diff) | |
download | qemu-08a9b68dc033c9826da89f84202e547beadd92f0.zip qemu-08a9b68dc033c9826da89f84202e547beadd92f0.tar.gz qemu-08a9b68dc033c9826da89f84202e547beadd92f0.tar.bz2 |
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* Meson version update
* fix search path when configuring with --cpu
* support for measured SEV boot with -kernel (Dov)
* fix missing BQL locks (Emanuele)
* retrieve applesmc key from the host (Pedro)
* KVM PV feature documentation (Vitaly)
# gpg: Signature made Tue 05 Oct 2021 04:13:00 AM PDT
# gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83
# gpg: issuer "pbonzini@redhat.com"
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full]
# gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full]
* remotes/bonzini/tags/for-upstream:
meson: show library versions in the summary
target/xtensa: list cores in a text file
hexagon: use env keyword argument to pass PYTHONPATH
meson: switch minimum meson version to 0.58.2, minimum recommended to 0.59.2
meson: bump submodule to 0.59.2
migration: add missing qemu_mutex_lock_iothread in migration_completion
migration: block-dirty-bitmap: add missing qemu_mutex_lock_iothread
configure, meson: move CPU_CFLAGS out of QEMU_CFLAGS
hw/misc: applesmc: use host osk as default on macs
x86/sev: generate SEV kernel loader hashes in x86_load_linux
sev/i386: Introduce sev_add_kernel_loader_hashes for measured linux boot
i386: docs: Briefly describe KVM PV features
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target')
-rw-r--r-- | target/hexagon/meson.build | 3 | ||||
-rw-r--r-- | target/i386/sev-stub.c | 5 | ||||
-rw-r--r-- | target/i386/sev.c | 137 | ||||
-rw-r--r-- | target/i386/sev_i386.h | 12 | ||||
-rw-r--r-- | target/xtensa/cores.list | 9 | ||||
-rwxr-xr-x | target/xtensa/import_core.sh | 3 | ||||
-rw-r--r-- | target/xtensa/meson.build | 4 |
7 files changed, 170 insertions, 3 deletions
diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build index 6fd9360..c6d858f 100644 --- a/target/hexagon/meson.build +++ b/target/hexagon/meson.build @@ -156,7 +156,8 @@ dectree_generated = custom_target( 'dectree_generated.h.inc', output: 'dectree_generated.h.inc', depends: [iset_py], - command: ['env', 'PYTHONPATH=' + meson.current_build_dir(), files('dectree.py'), '@OUTPUT@'], + env: {'PYTHONPATH': meson.current_build_dir()}, + command: [python, files('dectree.py'), '@OUTPUT@'], ) hexagon_ss.add(dectree_generated) diff --git a/target/i386/sev-stub.c b/target/i386/sev-stub.c index 0227cb5..d8e6583 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 fa72104..bcd9260 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) { diff --git a/target/i386/sev_i386.h b/target/i386/sev_i386.h index ae6d840..2afe108 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/xtensa/cores.list b/target/xtensa/cores.list new file mode 100644 index 0000000..5772a00 --- /dev/null +++ b/target/xtensa/cores.list @@ -0,0 +1,9 @@ +core-dc232b.c +core-dc233c.c +core-de212.c +core-de233_fpu.c +core-dsp3400.c +core-fsf.c +core-sample_controller.c +core-test_kc705_be.c +core-test_mmuhifi_c3.c diff --git a/target/xtensa/import_core.sh b/target/xtensa/import_core.sh index 396b264..df66d09 100755 --- a/target/xtensa/import_core.sh +++ b/target/xtensa/import_core.sh @@ -66,3 +66,6 @@ static XtensaConfig $NAME __attribute__((unused)) = { REGISTER_CORE($NAME) EOF + +grep -qxf core-${NAME}.c "$BASE"/cores.list || \ + echo core-${NAME}.c >> "$BASE"/cores.list diff --git a/target/xtensa/meson.build b/target/xtensa/meson.build index 7c4efa6..20bbf9b 100644 --- a/target/xtensa/meson.build +++ b/target/xtensa/meson.build @@ -1,7 +1,7 @@ xtensa_ss = ss.source_set() -xtensa_cores = run_command('sh', '-c', 'cd $MESON_SOURCE_ROOT/$MESON_SUBDIR ; ls -1 core-*.c') -xtensa_ss.add(files(xtensa_cores.stdout().strip().split('\n'))) +xtensa_cores = fs.read('cores.list') +xtensa_ss.add(files(xtensa_cores.strip().split('\n'))) xtensa_ss.add(files( 'cpu.c', |