summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Boccassi <bluca@debian.org>2023-07-14 23:47:37 +0200
committerGitHub <noreply@github.com>2023-07-14 23:47:37 +0200
commitd3634ac46b43794bbe7dbd30bbdda20086f72855 (patch)
tree7caa92e78127158f9ef89d9bd2f327f4e8b8648a
parentcompare: fix typo (diff)
parentefi: don't pull kernel cmdline from SMBIOS in a confidential VM (diff)
downloadsystemd-d3634ac46b43794bbe7dbd30bbdda20086f72855.tar.xz
systemd-d3634ac46b43794bbe7dbd30bbdda20086f72855.zip
Merge pull request #28301 from berrange/cvm-lockdown
Avoid using SMBIOS for kernel cmdline injection in sd-stub in confidential VMs
-rw-r--r--src/basic/confidential-virt.c67
-rw-r--r--src/boot/efi/stub.c26
-rw-r--r--src/boot/efi/vmm.c117
-rw-r--r--src/boot/efi/vmm.h2
-rw-r--r--src/fundamental/confidential-virt-fundamental.h72
5 files changed, 207 insertions, 77 deletions
diff --git a/src/basic/confidential-virt.c b/src/basic/confidential-virt.c
index e00576a713..b6521cf5bf 100644
--- a/src/basic/confidential-virt.c
+++ b/src/basic/confidential-virt.c
@@ -5,81 +5,16 @@
#endif
#include <errno.h>
#include <fcntl.h>
-#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
+#include "confidential-virt-fundamental.h"
#include "confidential-virt.h"
#include "fd-util.h"
#include "missing_threads.h"
#include "string-table.h"
#include "utf8.h"
-#define CPUID_PROCESSOR_INFO_AND_FEATURE_BITS UINT32_C(0x1)
-
-/*
- * AMD64 Architecture Programmer’s Manual Volume 3:
- * General-Purpose and System Instructions.
- * Chapter: E4.1 - Maximum Extended Function Number and Vendor String
- * https://www.amd.com/system/files/TechDocs/24594.pdf
- */
-#define CPUID_GET_HIGHEST_FUNCTION UINT32_C(0x80000000)
-
-/*
- * AMD64 Architecture Programmer’s Manual Volume 3:
- * General-Purpose and System Instructions.
- * Chapter: E4.17 - Encrypted Memory Capabilities
- * https://www.amd.com/system/files/TechDocs/24594.pdf
- */
-#define CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES UINT32_C(0x8000001f)
-
-/*
- * AMD64 Architecture Programmer’s Manual Volume 3:
- * General-Purpose and System Instructions.
- * Chapter: 15.34.10 - SEV_STATUS MSR
- * https://www.amd.com/system/files/TechDocs/24593.pdf
- */
-#define MSR_AMD64_SEV UINT32_C(0xc0010131)
-
-/*
- * Intel® TDX Module v1.5 Base Architecture Specification
- * Chapter: 11.2
- * https://www.intel.com/content/www/us/en/content-details/733575/intel-tdx-module-v1-5-base-architecture-specification.html
- */
-
-#define CPUID_INTEL_TDX_ENUMERATION UINT32_C(0x21)
-
-/* Requirements for Implementing the Microsoft Hypervisor Interface
- * https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs
- */
-#define CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS UINT32_C(0x40000000)
-
-#define CPUID_HYPERV_FEATURES UINT32_C(0x40000003)
-
-#define CPUID_HYPERV_ISOLATION_CONFIG UINT32_C(0x4000000C)
-
-#define CPUID_HYPERV_MIN UINT32_C(0x40000005)
-#define CPUID_HYPERV_MAX UINT32_C(0x4000ffff)
-
-#define CPUID_SIG_AMD "AuthenticAMD"
-#define CPUID_SIG_INTEL "GenuineIntel"
-#define CPUID_SIG_INTEL_TDX "IntelTDX "
-#define CPUID_SIG_HYPERV "Microsoft Hv"
-
-/* ecx bit 31: set => hyperpvisor, unset => bare metal */
-#define CPUID_FEATURE_HYPERVISOR (UINT32_C(1) << 31)
-
-/* Linux include/asm-generic/hyperv-tlfs.h */
-#define CPUID_HYPERV_CPU_MANAGEMENT (UINT32_C(1) << 12) /* root partition */
-#define CPUID_HYPERV_ISOLATION (UINT32_C(1) << 22) /* confidential VM partition */
-
-#define CPUID_HYPERV_ISOLATION_TYPE_MASK UINT32_C(0xf)
-#define CPUID_HYPERV_ISOLATION_TYPE_SNP 2
-
-#define EAX_SEV (UINT32_C(1) << 1)
-#define MSR_SEV (UINT64_C(1) << 0)
-#define MSR_SEV_ES (UINT64_C(1) << 1)
-#define MSR_SEV_SNP (UINT64_C(1) << 2)
#if defined(__x86_64__)
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index fd4f668eb6..8fac41258e 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -489,17 +489,21 @@ static EFI_STATUS run(EFI_HANDLE image) {
log_error_status(err, "Error loading UKI-specific addons, ignoring: %m");
parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
- const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
- if (extra) {
- _cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline), *extra16 = xstr8_to_16(extra);
- cmdline = xasprintf("%ls %ls", tmp, extra16);
-
- /* SMBIOS strings are measured in PCR1, but we also want to measure them in our specific
- * PCR12, as firmware-owned PCRs are very difficult to use as they'll contain unpredictable
- * measurements that are not under control of the machine owner. */
- m = false;
- (void) tpm_log_load_options(extra16, &m);
- parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
+ /* SMBIOS OEM Strings data is controlled by the host admin and not covered
+ * by the VM attestation, so MUST NOT be trusted when in a confidential VM */
+ if (!is_confidential_vm()) {
+ const char *extra = smbios_find_oem_string("io.systemd.stub.kernel-cmdline-extra");
+ if (extra) {
+ _cleanup_free_ char16_t *tmp = TAKE_PTR(cmdline), *extra16 = xstr8_to_16(extra);
+ cmdline = xasprintf("%ls %ls", tmp, extra16);
+
+ /* SMBIOS strings are measured in PCR1, but we also want to measure them in our specific
+ * PCR12, as firmware-owned PCRs are very difficult to use as they'll contain unpredictable
+ * measurements that are not under control of the machine owner. */
+ m = false;
+ (void) tpm_log_load_options(extra16, &m);
+ parameters_measured = parameters_measured < 0 ? m : (parameters_measured && m);
+ }
}
export_variables(loaded_image);
diff --git a/src/boot/efi/vmm.c b/src/boot/efi/vmm.c
index 951b4e3766..60e216d54c 100644
--- a/src/boot/efi/vmm.c
+++ b/src/boot/efi/vmm.c
@@ -4,6 +4,7 @@
# include <cpuid.h>
#endif
+#include "confidential-virt-fundamental.h"
#include "device-path-util.h"
#include "drivers.h"
#include "efi-string.h"
@@ -307,3 +308,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 061ad692ec..df48af3779 100644
--- a/src/boot/efi/vmm.h
+++ b/src/boot/efi/vmm.h
@@ -8,4 +8,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);
diff --git a/src/fundamental/confidential-virt-fundamental.h b/src/fundamental/confidential-virt-fundamental.h
new file mode 100644
index 0000000000..986923e1c2
--- /dev/null
+++ b/src/fundamental/confidential-virt-fundamental.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <stdint.h>
+
+/* Keep CVM detection logic in this file at feature parity with
+ * that in src/efi/boot/vmm.c */
+
+#define CPUID_PROCESSOR_INFO_AND_FEATURE_BITS UINT32_C(0x1)
+
+/*
+ * AMD64 Architecture Programmer’s Manual Volume 3:
+ * General-Purpose and System Instructions.
+ * Chapter: E4.1 - Maximum Extended Function Number and Vendor String
+ * https://www.amd.com/system/files/TechDocs/24594.pdf
+ */
+#define CPUID_GET_HIGHEST_FUNCTION UINT32_C(0x80000000)
+
+/*
+ * AMD64 Architecture Programmer’s Manual Volume 3:
+ * General-Purpose and System Instructions.
+ * Chapter: E4.17 - Encrypted Memory Capabilities
+ * https://www.amd.com/system/files/TechDocs/24594.pdf
+ */
+#define CPUID_AMD_GET_ENCRYPTED_MEMORY_CAPABILITIES UINT32_C(0x8000001f)
+
+/*
+ * AMD64 Architecture Programmer’s Manual Volume 3:
+ * General-Purpose and System Instructions.
+ * Chapter: 15.34.10 - SEV_STATUS MSR
+ * https://www.amd.com/system/files/TechDocs/24593.pdf
+ */
+#define MSR_AMD64_SEV UINT32_C(0xc0010131)
+
+/*
+ * Intel® TDX Module v1.5 Base Architecture Specification
+ * Chapter: 11.2
+ * https://www.intel.com/content/www/us/en/content-details/733575/intel-tdx-module-v1-5-base-architecture-specification.html
+ */
+
+#define CPUID_INTEL_TDX_ENUMERATION UINT32_C(0x21)
+
+/* Requirements for Implementing the Microsoft Hypervisor Interface
+ * https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/tlfs
+ */
+#define CPUID_HYPERV_VENDOR_AND_MAX_FUNCTIONS UINT32_C(0x40000000)
+
+#define CPUID_HYPERV_FEATURES UINT32_C(0x40000003)
+
+#define CPUID_HYPERV_ISOLATION_CONFIG UINT32_C(0x4000000C)
+
+#define CPUID_HYPERV_MIN UINT32_C(0x40000005)
+#define CPUID_HYPERV_MAX UINT32_C(0x4000ffff)
+
+#define CPUID_SIG_AMD "AuthenticAMD"
+#define CPUID_SIG_INTEL "GenuineIntel"
+#define CPUID_SIG_INTEL_TDX "IntelTDX "
+#define CPUID_SIG_HYPERV "Microsoft Hv"
+
+/* ecx bit 31: set => hyperpvisor, unset => bare metal */
+#define CPUID_FEATURE_HYPERVISOR (UINT32_C(1) << 31)
+
+/* Linux include/asm-generic/hyperv-tlfs.h */
+#define CPUID_HYPERV_CPU_MANAGEMENT (UINT32_C(1) << 12) /* root partition */
+#define CPUID_HYPERV_ISOLATION (UINT32_C(1) << 22) /* confidential VM partition */
+
+#define CPUID_HYPERV_ISOLATION_TYPE_MASK UINT32_C(0xf)
+#define CPUID_HYPERV_ISOLATION_TYPE_SNP 2
+
+#define EAX_SEV (UINT32_C(1) << 1)
+#define MSR_SEV (UINT64_C(1) << 0)
+#define MSR_SEV_ES (UINT64_C(1) << 1)
+#define MSR_SEV_SNP (UINT64_C(1) << 2)