From: mhkelley58@gmail.com
To: haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com,
tglx@linutronix.de, mingo@redhat.com, bp@alien8.de,
dave.hansen@linux.intel.com, hpa@zytor.com, arnd@arndb.de,
tytso@mit.edu, Jason@zx2c4.com, x86@kernel.org,
linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org,
linux-arch@vger.kernel.org
Subject: [PATCH v2 1/1] x86/hyperv: Use Hyper-V entropy to seed guest random number generator
Date: Thu, 7 Mar 2024 10:48:20 -0800 [thread overview]
Message-ID: <20240307184820.70589-1-mhklinux@outlook.com> (raw)
From: Michael Kelley <mhklinux@outlook.com>
A Hyper-V host provides its guest VMs with entropy in a custom ACPI
table named "OEM0". The entropy bits are updated each time Hyper-V
boots the VM, and are suitable for seeding the Linux guest random
number generator (rng). See a brief description of OEM0 in [1].
Generation 2 VMs on Hyper-V use UEFI to boot. Existing EFI code in
Linux seeds the rng with entropy bits from the EFI_RNG_PROTOCOL.
Via this path, the rng is seeded very early during boot with good
entropy. The ACPI OEM0 table is still provided in such VMs, though
it isn't needed.
But Generation 1 VMs on Hyper-V boot from BIOS. For these VMs, Linux
doesn't currently get any entropy from the Hyper-V host. While this
is not fundamentally broken because Linux can generate its own entropy,
using the Hyper-V host provided entropy would get the rng off to a
better start and would do so earlier in the boot process.
Improve the rng seeding for Generation 1 VMs by having Hyper-V specific
code in Linux take advantage of the OEM0 table to seed the rng. Because
the OEM0 table is custom to Hyper-V, parse it directly in the Hyper-V
code in the Linux kernel and use add_bootloader_randomness() to
seed the rng. Once the entropy bits are read from OEM0, zero them
out in the table so they don't appear in /sys/firmware/acpi/tables/OEM0
in the running VM.
An equivalent change is *not* made for Linux VMs on Hyper-V for
ARM64. Such VMs are always Generation 2 and the rng is seeded
with entropy obtained via the EFI_RNG_PROTOCOL as described above.
[1] https://download.microsoft.com/download/1/c/9/1c9813b8-089c-4fef-b2ad-ad80e79403ba/Whitepaper%20-%20The%20Windows%2010%20random%20number%20generation%20infrastructure.pdf
Signed-off-by: Michael Kelley <mhklinux@outlook.com>
---
Changes in v2:
* Tweaked commit message [Wei Liu]
* Removed message when OEM0 table isn't found. Added debug-level
message when OEM0 is successfully used to add randomness. [Wei Liu]
arch/x86/kernel/cpu/mshyperv.c | 1 +
drivers/hv/hv_common.c | 64 ++++++++++++++++++++++++++++++++++
include/asm-generic/mshyperv.h | 2 ++
3 files changed, 67 insertions(+)
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 303fef824167..65c9cbdd2282 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -648,6 +648,7 @@ const __initconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
.init.x2apic_available = ms_hyperv_x2apic_available,
.init.msi_ext_dest_id = ms_hyperv_msi_ext_dest_id,
.init.init_platform = ms_hyperv_init_platform,
+ .init.guest_late_init = ms_hyperv_late_init,
#ifdef CONFIG_AMD_MEM_ENCRYPT
.runtime.sev_es_hcall_prepare = hv_sev_es_hcall_prepare,
.runtime.sev_es_hcall_finish = hv_sev_es_hcall_finish,
diff --git a/drivers/hv/hv_common.c b/drivers/hv/hv_common.c
index 0285a74363b3..219c4371314d 100644
--- a/drivers/hv/hv_common.c
+++ b/drivers/hv/hv_common.c
@@ -20,6 +20,8 @@
#include <linux/sched/task_stack.h>
#include <linux/panic_notifier.h>
#include <linux/ptrace.h>
+#include <linux/random.h>
+#include <linux/efi.h>
#include <linux/kdebug.h>
#include <linux/kmsg_dump.h>
#include <linux/slab.h>
@@ -347,6 +349,68 @@ int __init hv_common_init(void)
return 0;
}
+void __init ms_hyperv_late_init(void)
+{
+ struct acpi_table_header *header;
+ acpi_status status;
+ u8 *randomdata;
+ u32 length, i;
+
+ /*
+ * Seed the Linux random number generator with entropy provided by
+ * the Hyper-V host in ACPI table OEM0. It would be nice to do this
+ * even earlier in ms_hyperv_init_platform(), but the ACPI subsystem
+ * isn't set up at that point. Skip if booted via EFI as generic EFI
+ * code has already done some seeding using the EFI RNG protocol.
+ */
+ if (!IS_ENABLED(CONFIG_ACPI) || efi_enabled(EFI_BOOT))
+ return;
+
+ status = acpi_get_table("OEM0", 0, &header);
+ if (ACPI_FAILURE(status) || !header)
+ return;
+
+ /*
+ * Since the "OEM0" table name is for OEM specific usage, verify
+ * that what we're seeing purports to be from Microsoft.
+ */
+ if (strncmp(header->oem_table_id, "MICROSFT", 8))
+ goto error;
+
+ /*
+ * Ensure the length is reasonable. Requiring at least 32 bytes and
+ * no more than 256 bytes is somewhat arbitrary. Hyper-V currently
+ * provides 64 bytes, but allow for a change in a later version.
+ */
+ if (header->length < sizeof(*header) + 32 ||
+ header->length > sizeof(*header) + 256)
+ goto error;
+
+ length = header->length - sizeof(*header);
+ randomdata = (u8 *)(header + 1);
+
+ pr_debug("Hyper-V: Seeding rng with %d random bytes from ACPI table OEM0\n",
+ length);
+
+ add_bootloader_randomness(randomdata, length);
+
+ /*
+ * To prevent the seed data from being visible in /sys/firmware/acpi,
+ * zero out the random data in the ACPI table and fixup the checksum.
+ */
+ for (i = 0; i < length; i++) {
+ header->checksum += randomdata[i];
+ randomdata[i] = 0;
+ }
+
+ acpi_put_table(header);
+ return;
+
+error:
+ pr_info("Hyper-V: Ignoring malformed ACPI table OEM0\n");
+ acpi_put_table(header);
+}
+
/*
* Hyper-V specific initialization and die code for
* individual CPUs that is common across all architectures.
diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
index 430f0ae0dde2..e861223093df 100644
--- a/include/asm-generic/mshyperv.h
+++ b/include/asm-generic/mshyperv.h
@@ -193,6 +193,7 @@ extern u64 (*hv_read_reference_counter)(void);
int __init hv_common_init(void);
void __init hv_common_free(void);
+void __init ms_hyperv_late_init(void);
int hv_common_cpu_init(unsigned int cpu);
int hv_common_cpu_die(unsigned int cpu);
@@ -290,6 +291,7 @@ void hv_setup_dma_ops(struct device *dev, bool coherent);
static inline bool hv_is_hyperv_initialized(void) { return false; }
static inline bool hv_is_hibernation_supported(void) { return false; }
static inline void hyperv_cleanup(void) {}
+static inline void ms_hyperv_late_init(void) {}
static inline bool hv_is_isolation_supported(void) { return false; }
static inline enum hv_isolation_type hv_get_isolation_type(void)
{
--
2.25.1
next reply other threads:[~2024-03-07 18:48 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-07 18:48 mhkelley58 [this message]
2024-03-13 4:50 ` [PATCH v2 1/1] x86/hyperv: Use Hyper-V entropy to seed guest random number generator Long Li
2024-03-13 5:29 ` Michael Kelley
2024-03-13 16:36 ` Long Li
2024-03-13 23:32 ` Jason A. Donenfeld
2024-03-14 0:30 ` Michael Kelley
2024-03-14 3:05 ` Jason A. Donenfeld
2024-03-14 4:30 ` Michael Kelley
2024-03-14 4:33 ` Jason A. Donenfeld
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240307184820.70589-1-mhklinux@outlook.com \
--to=mhkelley58@gmail.com \
--cc=Jason@zx2c4.com \
--cc=arnd@arndb.de \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=decui@microsoft.com \
--cc=haiyangz@microsoft.com \
--cc=hpa@zytor.com \
--cc=linux-arch@vger.kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mhklinux@outlook.com \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=tytso@mit.edu \
--cc=wei.liu@kernel.org \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.