From d8753fd5e71a4be0e99ecbbbfa052cb7bd90d717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 7 Jul 2023 16:28:19 +0100 Subject: [PATCH] efi: add helper API for detecting confidential virtualization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This helper is a simplified version of detect_confidential_virtualization() that merely returns a boolean status flag reflecting whether we are believed to be running inside a confidential VM. This flag can be used for turning off features that are inappropriate to use from a CVM, but must not be used for releasing sensitive data. The latter must only be done in response to an attestation for the environment. Signed-off-by: Daniel P. Berrangé (cherry picked from commit b354a2cafc8ea38b4551aa3e4f078f1d7aa40c7c) Related: RHEL-50651 --- src/boot/efi/vmm.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ src/boot/efi/vmm.h | 2 + 2 files changed, 119 insertions(+) diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c index f9a59dca0a..214f8f7024 100644 --- a/src/boot/efi/vmm.c +++ b/src/boot/efi/vmm.c @@ -7,6 +7,7 @@ # include #endif +#include "confidential-virt-fundamental.h" #include "drivers.h" #include "efi-string.h" #include "string-util-fundamental.h" @@ -323,3 +324,119 @@ const char* smbios_find_oem_string(const char *name) { return NULL; } + +#if defined(__i386__) || defined(__x86_64__) +static uint32_t cpuid_leaf(uint32_t eax, char ret_sig[static 13], bool swapped) { + /* zero-init as some queries explicitly require subleaf == 0 */ + uint32_t sig[3] = {}; + + if (swapped) + __cpuid_count(eax, 0, eax, sig[0], sig[2], sig[1]); + else + __cpuid_count(eax, 0, eax, sig[0], sig[1], sig[2]); + + memcpy(ret_sig, sig, sizeof(sig)); + ret_sig[12] = 0; /* \0-terminate the string to make string comparison possible */ + + return eax; +} + +static uint64_t msr(uint32_t index) { + uint64_t val; +#ifdef __x86_64__ + uint32_t low, high; + asm volatile ("rdmsr" : "=a"(low), "=d"(high) : "c"(index) : "memory"); + val = ((uint64_t)high << 32) | low; +#else + asm volatile ("rdmsr" : "=A"(val) : "c"(index) : "memory"); +#endif + return val; +} + +static bool detect_hyperv_sev(void) { + uint32_t eax, ebx, ecx, edx, feat; + char sig[13] = {}; + + feat = cpuid_leaf(CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS, sig, false); + + if (feat < CPUID_HYPERV_MIN || feat > CPUID_HYPERV_MAX) + return false; + + if (memcmp(sig, CPUID_SIG_HYPERV, sizeof(sig)) != 0) + return false; + + __cpuid(CPUID_HYPERV_FEATURES, eax, ebx, ecx, edx); + + if (ebx & CPUID_HYPERV_ISOLATION && !(ebx & CPUID_HYPERV_CPU_MANAGEMENT)) { + __cpuid(CPUID_HYPERV_ISOLATION_CONFIG, eax, ebx, ecx, edx); + + if ((ebx & CPUID_HYPERV_ISOLATION_TYPE_MASK) == CPUID_HYPERV_ISOLATION_TYPE_SNP) + return true; + } + + return false; +} + +static bool detect_sev(void) { + uint32_t eax, ebx, ecx, edx; + uint64_t msrval; + + __cpuid(CPUID_GET_HIGHEST_FUNCTION, eax, ebx, ecx, edx); + + if (eax < CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES) + return false; + + __cpuid(CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES, eax, ebx, ecx, edx); + + /* bit 1 == CPU supports SEV feature + * + * Note, Azure blocks this CPUID leaf from its SEV-SNP + * guests, so we must fallback to trying some HyperV + * specific CPUID checks. + */ + if (!(eax & EAX_SEV)) + return detect_hyperv_sev(); + + msrval = msr(MSR_AMD64_SEV); + + if (msrval & (MSR_SEV_SNP | MSR_SEV_ES | MSR_SEV)) + return true; + + return false; +} + +static bool detect_tdx(void) { + uint32_t eax, ebx, ecx, edx; + char sig[13] = {}; + + __cpuid(CPUID_GET_HIGHEST_FUNCTION, eax, ebx, ecx, edx); + + if (eax < CPUID_INTEL_TDX_ENUMERATION) + return false; + + cpuid_leaf(CPUID_INTEL_TDX_ENUMERATION, sig, true); + + if (memcmp(sig, CPUID_SIG_INTEL_TDX, sizeof(sig)) == 0) + return true; + + return false; +} +#endif /* ! __i386__ && ! __x86_64__ */ + +bool is_confidential_vm(void) { +#if defined(__i386__) || defined(__x86_64__) + char sig[13] = {}; + + if (!cpuid_in_hypervisor()) + return false; + + cpuid_leaf(0, sig, true); + + if (memcmp(sig, CPUID_SIG_AMD, sizeof(sig)) == 0) + return detect_sev(); + if (memcmp(sig, CPUID_SIG_INTEL, sizeof(sig)) == 0) + return detect_tdx(); +#endif /* ! __i386__ && ! __x86_64__ */ + + return false; +} diff --git a/src/boot/efi/vmm.h b/src/boot/efi/vmm.h index 2002f32bec..55c12039d2 100644 --- a/src/boot/efi/vmm.h +++ b/src/boot/efi/vmm.h @@ -9,4 +9,6 @@ EFI_STATUS vmm_open(EFI_HANDLE *ret_qemu_dev, EFI_FILE **ret_qemu_dir); bool in_hypervisor(void); +bool is_confidential_vm(void); + const char* smbios_find_oem_string(const char *name);