diff mbox series

efi: random: refresh random seed on modern EFI only

Message ID 20230626140836.299395-1-Jason@zx2c4.com
State New
Headers show
Series efi: random: refresh random seed on modern EFI only | expand

Commit Message

Jason A. Donenfeld June 26, 2023, 2:08 p.m. UTC
EFI has a rather unique benefit that it has access to some limited
non-volatile storage, where the kernel can store a random seed. Register
a notification for when the RNG is initialized, and at that point, store
a new random seed.

This was previously reverted in 69cbeb61ff90 because it caused hangs on
very old EFI implementations. This time, restrict it to only modern EFIs
with a more recent revision number.

Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Bagas Sanjaya <bagasdotme@gmail.com>
Cc: Sami Korkalainen <sami.korkalainen@proton.me>
Fixes: 69cbeb61ff90 ("Revert "efi: random: refresh non-volatile random seed when RNG is initialized"")
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
 drivers/firmware/efi/efi.c | 22 ++++++++++++++++++++++
 include/linux/efi.h        |  1 +
 2 files changed, 23 insertions(+)

Comments

Linus Torvalds June 26, 2023, 6:09 p.m. UTC | #1
On Mon, 26 Jun 2023 at 07:08, Jason A. Donenfeld <Jason@zx2c4.com> wrote:
>
> EFI has a rather unique benefit that it has access to some limited
> non-volatile storage, where the kernel can store a random seed. Register
> a notification for when the RNG is initialized, and at that point, store
> a new random seed.

No.

We DO NOT DO THIS DURING EARLY BOOT.

Christ.

Stop the craziness. We already know that the machine that had problems
with this seems to literally have been problematic due to boot-time
issues, but worked after boot.

Now, I had hoped that Sami's test would have uncovered some smoking
gun actually explaining it, but that was not to be.

There's quite possibly some random ordering thing, but the fundamental
facts here are

 (a) early boot is hard to debug

 (b) there is absolutely no reason to do it during boot

 (c) entropy is at its weakest during boot

so there is no way in hell we are doing this thing during bootup, and
absolutely none of that has changed by checking some minimum EFI
version.

Don't ever re-send this crap again, ok?

               Linus
diff mbox series

Patch

diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 34b9e7876538..1281798c7d7b 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -361,6 +361,24 @@  static void __init efi_debugfs_init(void)
 static inline void efi_debugfs_init(void) {}
 #endif
 
+static void refresh_nv_rng_seed(struct work_struct *work)
+{
+	u8 seed[EFI_RANDOM_SEED_SIZE];
+
+	get_random_bytes(seed, sizeof(seed));
+	efi.set_variable(L"RandomSeed", &LINUX_EFI_RANDOM_SEED_TABLE_GUID,
+			 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			 EFI_VARIABLE_RUNTIME_ACCESS, sizeof(seed), seed);
+	memzero_explicit(seed, sizeof(seed));
+}
+static int refresh_nv_rng_seed_notification(struct notifier_block *nb, unsigned long action, void *data)
+{
+	static DECLARE_WORK(work, refresh_nv_rng_seed);
+	schedule_work(&work);
+	return NOTIFY_DONE;
+}
+static struct notifier_block refresh_nv_rng_seed_nb = { .notifier_call = refresh_nv_rng_seed_notification };
+
 /*
  * We register the efi subsystem with the firmware subsystem and the
  * efivars subsystem with the efi subsystem, if the system was booted with
@@ -433,6 +451,10 @@  static int __init efisubsys_init(void)
 		platform_device_register_simple("efi_secret", 0, NULL, 0);
 #endif
 
+	if (efi.runtime_version >= EFI_2_40_SYSTEM_TABLE_REVISION &&
+	    efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE))
+		execute_with_initialized_rng(&refresh_nv_rng_seed_nb);
+
 	return 0;
 
 err_remove_group:
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 571d1a6e1b74..3331cc17ae4f 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -462,6 +462,7 @@  typedef struct {
 #define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL)
 #define EFI_DXE_SERVICES_TABLE_SIGNATURE ((u64)0x565245535f455844ULL)
 
+#define EFI_2_40_SYSTEM_TABLE_REVISION  ((2 << 16) | (40))
 #define EFI_2_30_SYSTEM_TABLE_REVISION  ((2 << 16) | (30))
 #define EFI_2_20_SYSTEM_TABLE_REVISION  ((2 << 16) | (20))
 #define EFI_2_10_SYSTEM_TABLE_REVISION  ((2 << 16) | (10))