All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86/setup: Allow passing RNG seeds via e820 setup table
@ 2022-06-30 11:33 Jason A. Donenfeld
  2022-06-30 11:59 ` [PATCH v2] " Jason A. Donenfeld
  2022-07-11  9:39 ` [tip: x86/kdump] " tip-bot2 for Jason A. Donenfeld
  0 siblings, 2 replies; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-06-30 11:33 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, linux-kernel; +Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. Here, we really want
the ability for the firmware to pass a random seed, similar to what OF
platforms do with the "rng-seed" property. It also would be nice for
bootloaders to be able to append seeds to the kernel before launching.

This patch accomplishes that by adding SETUP_RNG_SEED, similar to the
other 7 SETUP_* entries that are parsed from the e820 setup table. I've
verified that this works well with QEMU.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
 arch/x86/include/uapi/asm/bootparam.h | 1 +
 arch/x86/kernel/setup.c               | 8 +++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..a60676b8d1d4 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -11,6 +11,7 @@
 #define SETUP_APPLE_PROPERTIES		5
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
+#define SETUP_RNG_SEED			8
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bd6c6fd373ae..4135fa17a90e 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -23,6 +23,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -343,7 +344,8 @@ static void __init parse_setup_data(void)
 		data_len = data->len + sizeof(struct setup_data);
 		data_type = data->type;
 		pa_next = data->next;
-		early_memunmap(data, sizeof(*data));
+		if (data_type != SETUP_RNG_SEED)
+			early_memunmap(data, sizeof(*data));
 
 		switch (data_type) {
 		case SETUP_E820_EXT:
@@ -355,6 +357,10 @@ static void __init parse_setup_data(void)
 		case SETUP_EFI:
 			parse_efi_setup(pa_data, data_len);
 			break;
+		case SETUP_RNG_SEED:
+			add_bootloader_randomness(data + 1, data_len);
+			early_memunmap(data, sizeof(*data));
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v2] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-06-30 11:33 [PATCH] x86/setup: Allow passing RNG seeds via e820 setup table Jason A. Donenfeld
@ 2022-06-30 11:59 ` Jason A. Donenfeld
  2022-06-30 12:09   ` [PATCH v3] " Jason A. Donenfeld
  2022-07-11  9:39 ` [tip: x86/kdump] " tip-bot2 for Jason A. Donenfeld
  1 sibling, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-06-30 11:59 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, linux-kernel; +Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. Here, we really want
the ability for the firmware to pass a random seed, similar to what OF
platforms do with the "rng-seed" property. It also would be nice for
bootloaders to be able to append seeds to the kernel before launching.

This patch accomplishes that by adding SETUP_RNG_SEED, similar to the
other 7 SETUP_* entries that are parsed from the e820 setup table. I've
verified that this works well with QEMU.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v1->v2:
- Fix small typo of data_len -> data->len.

 arch/x86/include/uapi/asm/bootparam.h | 1 +
 arch/x86/kernel/setup.c               | 8 +++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..a60676b8d1d4 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -11,6 +11,7 @@
 #define SETUP_APPLE_PROPERTIES		5
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
+#define SETUP_RNG_SEED			8
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bd6c6fd373ae..ce8bb744e576 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -23,6 +23,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -343,7 +344,8 @@ static void __init parse_setup_data(void)
 		data_len = data->len + sizeof(struct setup_data);
 		data_type = data->type;
 		pa_next = data->next;
-		early_memunmap(data, sizeof(*data));
+		if (data_type != SETUP_RNG_SEED)
+			early_memunmap(data, sizeof(*data));
 
 		switch (data_type) {
 		case SETUP_E820_EXT:
@@ -355,6 +357,10 @@ static void __init parse_setup_data(void)
 		case SETUP_EFI:
 			parse_efi_setup(pa_data, data_len);
 			break;
+		case SETUP_RNG_SEED:
+			add_bootloader_randomness(data + 1, data->len);
+			early_memunmap(data, sizeof(*data));
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v3] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-06-30 11:59 ` [PATCH v2] " Jason A. Donenfeld
@ 2022-06-30 12:09   ` Jason A. Donenfeld
  2022-06-30 13:31     ` [PATCH v4] " Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-06-30 12:09 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, linux-kernel; +Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. Here, we really want
the ability for the firmware to pass a random seed, similar to what OF
platforms do with the "rng-seed" property. It also would be nice for
bootloaders to be able to append seeds to the kernel before launching.

This patch accomplishes that by adding SETUP_RNG_SEED, similar to the
other 7 SETUP_* entries that are parsed from the e820 setup table. I've
verified that this works well with QEMU.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.

 arch/x86/include/uapi/asm/bootparam.h | 1 +
 arch/x86/kernel/setup.c               | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..a60676b8d1d4 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -11,6 +11,7 @@
 #define SETUP_APPLE_PROPERTIES		5
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
+#define SETUP_RNG_SEED			8
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bd6c6fd373ae..33e9d23296b6 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -23,6 +23,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -355,6 +356,13 @@ static void __init parse_setup_data(void)
 		case SETUP_EFI:
 			parse_efi_setup(pa_data, data_len);
 			break;
+		case SETUP_RNG_SEED:
+			pa_data += sizeof(*data);
+			data_len -= sizeof(*data);
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data, data_len);
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v4] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-06-30 12:09   ` [PATCH v3] " Jason A. Donenfeld
@ 2022-06-30 13:31     ` Jason A. Donenfeld
  2022-07-01 17:58       ` [PATCH v5] " Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-06-30 13:31 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, linux-kernel; +Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. Here, we really want
the ability for the firmware to pass a random seed, similar to what OF
platforms do with the "rng-seed" property. It also would be nice for
bootloaders to be able to append seeds to the kernel before launching.

This patch accomplishes that by adding SETUP_RNG_SEED, similar to the
other 7 SETUP_* entries that are parsed from the e820 setup table. I've
verified that this works well with QEMU.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Sorry for all the churn. I keep forgetting things. I'll slow down a bit
after this one.

Changes v3->v4:
- Zero out data after using, for forward secrecy and so that kexec
  doesn't reuse the data.
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.
Changes v1->v2:
- Fix small typo of data_len -> data->len.

 arch/x86/include/uapi/asm/bootparam.h | 1 +
 arch/x86/kernel/setup.c               | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..a60676b8d1d4 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -11,6 +11,7 @@
 #define SETUP_APPLE_PROPERTIES		5
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
+#define SETUP_RNG_SEED			8
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bd6c6fd373ae..6c807a4ae141 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -23,6 +23,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -355,6 +356,13 @@ static void __init parse_setup_data(void)
 		case SETUP_EFI:
 			parse_efi_setup(pa_data, data_len);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			memzero_explicit(data->data, data->len);
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v5] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-06-30 13:31     ` [PATCH v4] " Jason A. Donenfeld
@ 2022-07-01 17:58       ` Jason A. Donenfeld
  2022-07-01 18:25         ` H. Peter Anvin
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-01 17:58 UTC (permalink / raw)
  To: tglx, mingo, bp, dave.hansen, x86, hpa, linux-kernel; +Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
VMs, EFI is not something you generally need or want.

Rather, here we want the ability for the image loader or firmware to
pass a single random seed, exactly as device tree platforms do with the
"rng-seed" property. Additionally, this is something that bootloaders
can append, with their own seed file management, which is something
every other major OS ecosystem has that we do not (yet).

This patch adds SETUP_RNG_SEED, similar to the other seven SETUP_*
entries that are parsed from the e820 setup table. It also takes care to
zero out the seed immediately after using, in order to retain forward
secrecy. This all takes about 7 trivial lines of code.

Then, on kexec_file_load(), a new fresh seed is generated and passed to
the next kernel, just as is done on device tree architectures when
using kexec. And, importantly, I've tested that QEMU is able to properly
pass SETUP_RNG_SEED as well, making this work for every step of the way.
This code too is pretty straight forward.

Together these measures ensure that VMs and nested kexec()'d kernels
always are getting a proper boot time RNG seed at the earliest possible
stage from their parents:

   - Host [already has strongly initialized RNG]
     - QEMU [passes fresh seed in e820 SETUP_RNG_SEED field]
       - Linux [uses parent's seed and gathers entropy of its own]
         - kexec [passes this in e820 SETUP_RNG_SEED field]
           - Linux [uses parent's seed and gathers entropy of its own]
             - kexec [passes this in e820 SETUP_RNG_SEED field]
               - Linux [uses parent's seed and gathers entropy of its own]
                 - kexec [passes this in e820 SETUP_RNG_SEED field]
		   - ...

I've verified in several scenarios that this works quite well from a
host kernel to QEMU and down inwards, mixing and matching loaders, with
every layer providing a seed to the next.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Another day, another patch revision. If you haven't noticed, I'm quite
determined to make this work well and robustly. At some point I'd of
course appreciate some review. Either way, I've got every intention of
plugging away at this until it's perfect.

Changes v4->v5:
- Populate field when loading bzimages for kexec, just like device tree
  platforms do.
Changes v3->v4:
- Zero out data after using, for forward secrecy.
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.
Changes v1->v2:
- Fix small typo of data_len -> data->len.

 arch/x86/include/uapi/asm/bootparam.h |  1 +
 arch/x86/kernel/kexec-bzimage64.c     | 36 ++++++++++++++++++++++++---
 arch/x86/kernel/setup.c               |  8 ++++++
 3 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..a60676b8d1d4 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -11,6 +11,7 @@
 #define SETUP_APPLE_PROPERTIES		5
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
+#define SETUP_RNG_SEED			8
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 170d0fd68b1f..13b2c55ebbf0 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +111,27 @@ static int setup_e820_entries(struct boot_params *params)
 	return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+add_rng_seed_setup_data(struct boot_params *params,
+			unsigned long params_load_addr,
+			unsigned int rng_seed_setup_data_offset)
+{
+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+	unsigned long setup_data_phys;
+
+	if (!rng_is_initialized())
+		return;
+
+	sd->type = SETUP_RNG_SEED;
+	sd->len = RNG_SEED_LENGTH;
+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+	sd->next = params->hdr.setup_data;
+	params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
 				  unsigned long params_load_addr,
@@ -190,7 +212,8 @@ static int
 setup_boot_parameters(struct kimage *image, struct boot_params *params,
 		      unsigned long params_load_addr,
 		      unsigned int efi_map_offset, unsigned int efi_map_sz,
-		      unsigned int efi_setup_data_offset)
+		      unsigned int efi_setup_data_offset,
+		      unsigned int rng_seed_setup_data_offset)
 {
 	unsigned int nr_e820_entries;
 	unsigned long long mem_k, start, end;
@@ -242,6 +265,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 		}
 	}
 
+	add_rng_seed_setup_data(params, params_load_addr,
+				rng_seed_setup_data_offset);
 #ifdef CONFIG_EFI
 	/* Setup EFI state */
 	setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz,
@@ -337,6 +362,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	void *stack;
 	unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr);
 	unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset;
+	unsigned int rng_seed_setup_data_offset;
 	struct kexec_buf kbuf = { .image = image, .buf_max = ULONG_MAX,
 				  .top_down = true };
 	struct kexec_buf pbuf = { .image = image, .buf_min = MIN_PURGATORY_ADDR,
@@ -401,13 +427,16 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
 				sizeof(struct setup_data) +
-				sizeof(struct efi_setup_data);
+				sizeof(struct efi_setup_data) +
+				sizeof(struct setup_data) +
+				RNG_SEED_LENGTH;
 
 	params = kzalloc(kbuf.bufsz, GFP_KERNEL);
 	if (!params)
 		return ERR_PTR(-ENOMEM);
 	efi_map_offset = params_cmdline_sz;
 	efi_setup_data_offset = efi_map_offset + ALIGN(efi_map_sz, 16);
+	rng_seed_setup_data_offset = efi_setup_data_offset + sizeof(struct efi_setup_data);
 
 	/* Copy setup header onto bootparams. Documentation/x86/boot.rst */
 	setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset;
@@ -490,7 +519,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 
 	ret = setup_boot_parameters(image, params, bootparam_load_addr,
 				    efi_map_offset, efi_map_sz,
-				    efi_setup_data_offset);
+				    efi_setup_data_offset,
+				    rng_seed_setup_data_offset);
 	if (ret)
 		goto out_free_params;
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bd6c6fd373ae..6c807a4ae141 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -23,6 +23,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -355,6 +356,13 @@ static void __init parse_setup_data(void)
 		case SETUP_EFI:
 			parse_efi_setup(pa_data, data_len);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			memzero_explicit(data->data, data->len);
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH v5] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-07-01 17:58       ` [PATCH v5] " Jason A. Donenfeld
@ 2022-07-01 18:25         ` H. Peter Anvin
  2022-07-01 18:42           ` Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: H. Peter Anvin @ 2022-07-01 18:25 UTC (permalink / raw)
  To: Jason A. Donenfeld, tglx, mingo, bp, dave.hansen, x86, linux-kernel

On July 1, 2022 10:58:08 AM PDT, "Jason A. Donenfeld" <Jason@zx2c4.com> wrote:
>Currently the only way x86 can get an early boot RNG seed is via EFI,
>which is generally always used now for physical machines, but is very
>rarely used in VMs, especially VMs that are optimized for starting
>"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
>VMs, EFI is not something you generally need or want.
>
>Rather, here we want the ability for the image loader or firmware to
>pass a single random seed, exactly as device tree platforms do with the
>"rng-seed" property. Additionally, this is something that bootloaders
>can append, with their own seed file management, which is something
>every other major OS ecosystem has that we do not (yet).
>
>This patch adds SETUP_RNG_SEED, similar to the other seven SETUP_*
>entries that are parsed from the e820 setup table. It also takes care to
>zero out the seed immediately after using, in order to retain forward
>secrecy. This all takes about 7 trivial lines of code.
>
>Then, on kexec_file_load(), a new fresh seed is generated and passed to
>the next kernel, just as is done on device tree architectures when
>using kexec. And, importantly, I've tested that QEMU is able to properly
>pass SETUP_RNG_SEED as well, making this work for every step of the way.
>This code too is pretty straight forward.
>
>Together these measures ensure that VMs and nested kexec()'d kernels
>always are getting a proper boot time RNG seed at the earliest possible
>stage from their parents:
>
>   - Host [already has strongly initialized RNG]
>     - QEMU [passes fresh seed in e820 SETUP_RNG_SEED field]
>       - Linux [uses parent's seed and gathers entropy of its own]
>         - kexec [passes this in e820 SETUP_RNG_SEED field]
>           - Linux [uses parent's seed and gathers entropy of its own]
>             - kexec [passes this in e820 SETUP_RNG_SEED field]
>               - Linux [uses parent's seed and gathers entropy of its own]
>                 - kexec [passes this in e820 SETUP_RNG_SEED field]
>		   - ...
>
>I've verified in several scenarios that this works quite well from a
>host kernel to QEMU and down inwards, mixing and matching loaders, with
>every layer providing a seed to the next.
>
>Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
>---
>Another day, another patch revision. If you haven't noticed, I'm quite
>determined to make this work well and robustly. At some point I'd of
>course appreciate some review. Either way, I've got every intention of
>plugging away at this until it's perfect.
>
>Changes v4->v5:
>- Populate field when loading bzimages for kexec, just like device tree
>  platforms do.
>Changes v3->v4:
>- Zero out data after using, for forward secrecy.
>Changes v2->v3:
>- Actually memmap the right area with the random bytes in it. This
>  worked before because of page sizes, but the code wasn't right. Now
>  it's right.
>Changes v1->v2:
>- Fix small typo of data_len -> data->len.
>
> arch/x86/include/uapi/asm/bootparam.h |  1 +
> arch/x86/kernel/kexec-bzimage64.c     | 36 ++++++++++++++++++++++++---
> arch/x86/kernel/setup.c               |  8 ++++++
> 3 files changed, 42 insertions(+), 3 deletions(-)
>
>diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
>index bea5cdcdf532..a60676b8d1d4 100644
>--- a/arch/x86/include/uapi/asm/bootparam.h
>+++ b/arch/x86/include/uapi/asm/bootparam.h
>@@ -11,6 +11,7 @@
> #define SETUP_APPLE_PROPERTIES		5
> #define SETUP_JAILHOUSE			6
> #define SETUP_CC_BLOB			7
>+#define SETUP_RNG_SEED			8
> 
> #define SETUP_INDIRECT			(1<<31)
> 
>diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
>index 170d0fd68b1f..13b2c55ebbf0 100644
>--- a/arch/x86/kernel/kexec-bzimage64.c
>+++ b/arch/x86/kernel/kexec-bzimage64.c
>@@ -18,6 +18,7 @@
> #include <linux/mm.h>
> #include <linux/efi.h>
> #include <linux/verification.h>
>+#include <linux/random.h>
> 
> #include <asm/bootparam.h>
> #include <asm/setup.h>
>@@ -110,6 +111,27 @@ static int setup_e820_entries(struct boot_params *params)
> 	return 0;
> }
> 
>+enum { RNG_SEED_LENGTH = 32 };
>+
>+static void
>+add_rng_seed_setup_data(struct boot_params *params,
>+			unsigned long params_load_addr,
>+			unsigned int rng_seed_setup_data_offset)
>+{
>+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
>+	unsigned long setup_data_phys;
>+
>+	if (!rng_is_initialized())
>+		return;
>+
>+	sd->type = SETUP_RNG_SEED;
>+	sd->len = RNG_SEED_LENGTH;
>+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
>+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
>+	sd->next = params->hdr.setup_data;
>+	params->hdr.setup_data = setup_data_phys;
>+}
>+
> #ifdef CONFIG_EFI
> static int setup_efi_info_memmap(struct boot_params *params,
> 				  unsigned long params_load_addr,
>@@ -190,7 +212,8 @@ static int
> setup_boot_parameters(struct kimage *image, struct boot_params *params,
> 		      unsigned long params_load_addr,
> 		      unsigned int efi_map_offset, unsigned int efi_map_sz,
>-		      unsigned int efi_setup_data_offset)
>+		      unsigned int efi_setup_data_offset,
>+		      unsigned int rng_seed_setup_data_offset)
> {
> 	unsigned int nr_e820_entries;
> 	unsigned long long mem_k, start, end;
>@@ -242,6 +265,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
> 		}
> 	}
> 
>+	add_rng_seed_setup_data(params, params_load_addr,
>+				rng_seed_setup_data_offset);
> #ifdef CONFIG_EFI
> 	/* Setup EFI state */
> 	setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz,
>@@ -337,6 +362,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> 	void *stack;
> 	unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr);
> 	unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset;
>+	unsigned int rng_seed_setup_data_offset;
> 	struct kexec_buf kbuf = { .image = image, .buf_max = ULONG_MAX,
> 				  .top_down = true };
> 	struct kexec_buf pbuf = { .image = image, .buf_min = MIN_PURGATORY_ADDR,
>@@ -401,13 +427,16 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
> 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
> 				sizeof(struct setup_data) +
>-				sizeof(struct efi_setup_data);
>+				sizeof(struct efi_setup_data) +
>+				sizeof(struct setup_data) +
>+				RNG_SEED_LENGTH;
> 
> 	params = kzalloc(kbuf.bufsz, GFP_KERNEL);
> 	if (!params)
> 		return ERR_PTR(-ENOMEM);
> 	efi_map_offset = params_cmdline_sz;
> 	efi_setup_data_offset = efi_map_offset + ALIGN(efi_map_sz, 16);
>+	rng_seed_setup_data_offset = efi_setup_data_offset + sizeof(struct efi_setup_data);
> 
> 	/* Copy setup header onto bootparams. Documentation/x86/boot.rst */
> 	setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset;
>@@ -490,7 +519,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> 
> 	ret = setup_boot_parameters(image, params, bootparam_load_addr,
> 				    efi_map_offset, efi_map_sz,
>-				    efi_setup_data_offset);
>+				    efi_setup_data_offset,
>+				    rng_seed_setup_data_offset);
> 	if (ret)
> 		goto out_free_params;
> 
>diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
>index bd6c6fd373ae..6c807a4ae141 100644
>--- a/arch/x86/kernel/setup.c
>+++ b/arch/x86/kernel/setup.c
>@@ -23,6 +23,7 @@
> #include <linux/usb/xhci-dbgp.h>
> #include <linux/static_call.h>
> #include <linux/swiotlb.h>
>+#include <linux/random.h>
> 
> #include <uapi/linux/mount.h>
> 
>@@ -355,6 +356,13 @@ static void __init parse_setup_data(void)
> 		case SETUP_EFI:
> 			parse_efi_setup(pa_data, data_len);
> 			break;
>+		case SETUP_RNG_SEED:
>+			data = early_memremap(pa_data, data_len);
>+			add_bootloader_randomness(data->data, data->len);
>+			memzero_explicit(data->data, data->len);
>+			memzero_explicit(&data->len, sizeof(data->len));
>+			early_memunmap(data, data_len);
>+			break;
> 		default:
> 			break;
> 		}

Please correct the incredibly confusing title of this patch.

The setup_data linked list has nothing to do with memory types (e820), except that memory types is one kind of data that can be passed on by this mechanism. This title makes it sound like you are passing random data in as a memory type, which could make some bizarre sense if it were, say, some kind of ring buffer preconfigured by the BIOS/VMM/boot loader to be continually overwritten with new random data.


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-07-01 18:25         ` H. Peter Anvin
@ 2022-07-01 18:42           ` Jason A. Donenfeld
  2022-07-01 18:52             ` H. Peter Anvin
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-01 18:42 UTC (permalink / raw)
  To: H. Peter Anvin; +Cc: tglx, mingo, bp, dave.hansen, x86, linux-kernel

Hi Peter,

On Fri, Jul 01, 2022 at 11:25:49AM -0700, H. Peter Anvin wrote:
> Please correct the incredibly confusing title of this patch.
> 
> The setup_data linked list has nothing to do with memory types (e820),
> except that memory types is one kind of data that can be passed on by
> this mechanism. This title makes it sound like you are passing random
> data in as a memory type, which could make some bizarre sense if it
> were, say, some kind of ring buffer preconfigured by the BIOS/VMM/boot
> loader to be continually overwritten with new random data.

Yea that is pretty confusing. Alright, I'll retitle that to something
like:

    x86/setup: Allow passing RNG seeds via setup data

Hopefully that matches more, considering the function that does the work
is called "parse_setup_data".

(I'll wait some more time before posting yet another v+1 with that
change, in case others have more feedback.)

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-07-01 18:42           ` Jason A. Donenfeld
@ 2022-07-01 18:52             ` H. Peter Anvin
  2022-07-01 18:53               ` Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: H. Peter Anvin @ 2022-07-01 18:52 UTC (permalink / raw)
  To: Jason A. Donenfeld; +Cc: tglx, mingo, bp, dave.hansen, x86, linux-kernel

On July 1, 2022 11:42:03 AM PDT, "Jason A. Donenfeld" <Jason@zx2c4.com> wrote:
>Hi Peter,
>
>On Fri, Jul 01, 2022 at 11:25:49AM -0700, H. Peter Anvin wrote:
>> Please correct the incredibly confusing title of this patch.
>> 
>> The setup_data linked list has nothing to do with memory types (e820),
>> except that memory types is one kind of data that can be passed on by
>> this mechanism. This title makes it sound like you are passing random
>> data in as a memory type, which could make some bizarre sense if it
>> were, say, some kind of ring buffer preconfigured by the BIOS/VMM/boot
>> loader to be continually overwritten with new random data.
>
>Yea that is pretty confusing. Alright, I'll retitle that to something
>like:
>
>    x86/setup: Allow passing RNG seeds via setup data
>
>Hopefully that matches more, considering the function that does the work
>is called "parse_setup_data".
>
>(I'll wait some more time before posting yet another v+1 with that
>change, in case others have more feedback.)
>
>Jason

We usually refer to it as setup_data (with the underscore) to indicate that it is a name and not a description.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH v5] x86/setup: Allow passing RNG seeds via e820 setup table
  2022-07-01 18:52             ` H. Peter Anvin
@ 2022-07-01 18:53               ` Jason A. Donenfeld
  2022-07-03  0:44                 ` [PATCH v6] x86/setup: Use rng seeds from setup_data Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-01 18:53 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, X86 ML, LKML

On Fri, Jul 1, 2022 at 8:52 PM H. Peter Anvin <hpa@zytor.com> wrote:
>
> On July 1, 2022 11:42:03 AM PDT, "Jason A. Donenfeld" <Jason@zx2c4.com> wrote:
> >Hi Peter,
> >
> >On Fri, Jul 01, 2022 at 11:25:49AM -0700, H. Peter Anvin wrote:
> >> Please correct the incredibly confusing title of this patch.
> >>
> >> The setup_data linked list has nothing to do with memory types (e820),
> >> except that memory types is one kind of data that can be passed on by
> >> this mechanism. This title makes it sound like you are passing random
> >> data in as a memory type, which could make some bizarre sense if it
> >> were, say, some kind of ring buffer preconfigured by the BIOS/VMM/boot
> >> loader to be continually overwritten with new random data.
> >
> >Yea that is pretty confusing. Alright, I'll retitle that to something
> >like:
> >
> >    x86/setup: Allow passing RNG seeds via setup data
> >
> >Hopefully that matches more, considering the function that does the work
> >is called "parse_setup_data".
> >
> >(I'll wait some more time before posting yet another v+1 with that
> >change, in case others have more feedback.)
> >
> >Jason
>
> We usually refer to it as setup_data (with the underscore) to indicate that it is a name and not a description.

That makes sense. I'll do that.

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH v6] x86/setup: Use rng seeds from setup_data
  2022-07-01 18:53               ` Jason A. Donenfeld
@ 2022-07-03  0:44                 ` Jason A. Donenfeld
  2022-07-07  0:08                   ` [PATCH v7] " Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-03  0:44 UTC (permalink / raw)
  To: hpa, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	X86 ML, LKML
  Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
VMs, EFI is not something you generally need or want.

Rather, here we want the ability for the image loader or firmware to
pass a single random seed, exactly as device tree platforms do with the
"rng-seed" property. Additionally, this is something that bootloaders
can append, with their own seed file management, which is something
every other major OS ecosystem has that we do not (yet).

This patch adds SETUP_RNG_SEED, similar to the other seven setup_data
entries that are parsed at boot. It also takes care to zero out the seed
immediately after using, in order to retain forward secrecy. This all
takes about 7 trivial lines of code.

Then, on kexec_file_load(), a new fresh seed is generated and passed to
the next kernel, just as is done on device tree architectures when
using kexec. And, importantly, I've tested that QEMU is able to properly
pass SETUP_RNG_SEED as well, making this work for every step of the way.
This code too is pretty straight forward.

Together these measures ensure that VMs and nested kexec()'d kernels
always receive a proper boot time RNG seed at the earliest possible
stage from their parents:

   - Host [already has strongly initialized RNG]
     - QEMU [passes fresh seed in SETUP_RNG_SEED field]
       - Linux [uses parent's seed and gathers entropy of its own]
         - kexec [passes this in SETUP_RNG_SEED field]
           - Linux [uses parent's seed and gathers entropy of its own]
             - kexec [passes this in SETUP_RNG_SEED field]
               - Linux [uses parent's seed and gathers entropy of its own]
                 - kexec [passes this in SETUP_RNG_SEED field]
		   - ...

I've verified in several scenarios that this works quite well from a
host kernel to QEMU and down inwards, mixing and matching loaders, with
every layer providing a seed to the next.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v5->v6:
- Rework commit message for hpa to be less confusing and not improperly
  mention e820.
Changes v4->v5:
- Populate field when loading bzimages for kexec, just like device tree
  platforms do.
Changes v3->v4:
- Zero out data after using, for forward secrecy.
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.
Changes v1->v2:
- Fix small typo of data_len -> data->len.


 arch/x86/include/uapi/asm/bootparam.h |  1 +
 arch/x86/kernel/kexec-bzimage64.c     | 36 ++++++++++++++++++++++++---
 arch/x86/kernel/setup.c               |  8 ++++++
 3 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..a60676b8d1d4 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -11,6 +11,7 @@
 #define SETUP_APPLE_PROPERTIES		5
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
+#define SETUP_RNG_SEED			8
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 170d0fd68b1f..13b2c55ebbf0 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +111,27 @@ static int setup_e820_entries(struct boot_params *params)
 	return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+add_rng_seed_setup_data(struct boot_params *params,
+			unsigned long params_load_addr,
+			unsigned int rng_seed_setup_data_offset)
+{
+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+	unsigned long setup_data_phys;
+
+	if (!rng_is_initialized())
+		return;
+
+	sd->type = SETUP_RNG_SEED;
+	sd->len = RNG_SEED_LENGTH;
+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+	sd->next = params->hdr.setup_data;
+	params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
 				  unsigned long params_load_addr,
@@ -190,7 +212,8 @@ static int
 setup_boot_parameters(struct kimage *image, struct boot_params *params,
 		      unsigned long params_load_addr,
 		      unsigned int efi_map_offset, unsigned int efi_map_sz,
-		      unsigned int efi_setup_data_offset)
+		      unsigned int efi_setup_data_offset,
+		      unsigned int rng_seed_setup_data_offset)
 {
 	unsigned int nr_e820_entries;
 	unsigned long long mem_k, start, end;
@@ -242,6 +265,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 		}
 	}
 
+	add_rng_seed_setup_data(params, params_load_addr,
+				rng_seed_setup_data_offset);
 #ifdef CONFIG_EFI
 	/* Setup EFI state */
 	setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz,
@@ -337,6 +362,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	void *stack;
 	unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr);
 	unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset;
+	unsigned int rng_seed_setup_data_offset;
 	struct kexec_buf kbuf = { .image = image, .buf_max = ULONG_MAX,
 				  .top_down = true };
 	struct kexec_buf pbuf = { .image = image, .buf_min = MIN_PURGATORY_ADDR,
@@ -401,13 +427,16 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
 				sizeof(struct setup_data) +
-				sizeof(struct efi_setup_data);
+				sizeof(struct efi_setup_data) +
+				sizeof(struct setup_data) +
+				RNG_SEED_LENGTH;
 
 	params = kzalloc(kbuf.bufsz, GFP_KERNEL);
 	if (!params)
 		return ERR_PTR(-ENOMEM);
 	efi_map_offset = params_cmdline_sz;
 	efi_setup_data_offset = efi_map_offset + ALIGN(efi_map_sz, 16);
+	rng_seed_setup_data_offset = efi_setup_data_offset + sizeof(struct efi_setup_data);
 
 	/* Copy setup header onto bootparams. Documentation/x86/boot.rst */
 	setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset;
@@ -490,7 +519,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 
 	ret = setup_boot_parameters(image, params, bootparam_load_addr,
 				    efi_map_offset, efi_map_sz,
-				    efi_setup_data_offset);
+				    efi_setup_data_offset,
+				    rng_seed_setup_data_offset);
 	if (ret)
 		goto out_free_params;
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bd6c6fd373ae..6c807a4ae141 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -23,6 +23,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -355,6 +356,13 @@ static void __init parse_setup_data(void)
 		case SETUP_EFI:
 			parse_efi_setup(pa_data, data_len);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			memzero_explicit(data->data, data->len);
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH v7] x86/setup: Use rng seeds from setup_data
  2022-07-03  0:44                 ` [PATCH v6] x86/setup: Use rng seeds from setup_data Jason A. Donenfeld
@ 2022-07-07  0:08                   ` Jason A. Donenfeld
  2022-07-08 11:39                     ` [PATCH tip v8] " Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-07  0:08 UTC (permalink / raw)
  To: hpa, Thomas Gleixner, Ingo Molnar, Borislav Petkov, X86 ML, LKML,
	Andy Lutomirski
  Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
VMs, EFI is not something you generally need or want.

Rather, here we want the ability for the image loader or firmware to
pass a single random seed, exactly as device tree platforms do with the
"rng-seed" property. Additionally, this is something that bootloaders
can append, with their own seed file management, which is something
every other major OS ecosystem has that we do not (yet).

This patch adds SETUP_RNG_SEED, similar to the other seven setup_data
entries that are parsed at boot. It also takes care to zero out the seed
immediately after using, in order to retain forward secrecy. This all
takes about 7 trivial lines of code.

Then, on kexec_file_load(), a new fresh seed is generated and passed to
the next kernel, just as is done on device tree architectures when
using kexec. And, importantly, I've tested that QEMU is able to properly
pass SETUP_RNG_SEED as well, making this work for every step of the way.
This code too is pretty straight forward.

Together these measures ensure that VMs and nested kexec()'d kernels
always receive a proper boot time RNG seed at the earliest possible
stage from their parents:

   - Host [already has strongly initialized RNG]
     - QEMU [passes fresh seed in SETUP_RNG_SEED field]
       - Linux [uses parent's seed and gathers entropy of its own]
         - kexec [passes this in SETUP_RNG_SEED field]
           - Linux [uses parent's seed and gathers entropy of its own]
             - kexec [passes this in SETUP_RNG_SEED field]
               - Linux [uses parent's seed and gathers entropy of its own]
                 - kexec [passes this in SETUP_RNG_SEED field]
		   - ...

I've verified in several scenarios that this works quite well from a
host kernel to QEMU and down inwards, mixing and matching loaders, with
every layer providing a seed to the next.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v6->v7:
- [amluto] Add comment about zeroing fields - data for forward secrecy, len in
  case of accidental reset-to-entry-jump bug.
Changes v5->v6:
- [hpa] Rework commit message to be less confusing and not improperly
  mention e820.
Changes v4->v5:
- Populate field when loading bzimages for kexec, just like device tree
  platforms do.
Changes v3->v4:
- Zero out data after using, for forward secrecy.
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.
Changes v1->v2:
- Fix small typo of data_len -> data->len.

 arch/x86/include/uapi/asm/bootparam.h |  1 +
 arch/x86/kernel/kexec-bzimage64.c     | 36 ++++++++++++++++++++++++---
 arch/x86/kernel/setup.c               | 10 ++++++++
 3 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..a60676b8d1d4 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -11,6 +11,7 @@
 #define SETUP_APPLE_PROPERTIES		5
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
+#define SETUP_RNG_SEED			8
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 170d0fd68b1f..13b2c55ebbf0 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +111,27 @@ static int setup_e820_entries(struct boot_params *params)
 	return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+add_rng_seed_setup_data(struct boot_params *params,
+			unsigned long params_load_addr,
+			unsigned int rng_seed_setup_data_offset)
+{
+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+	unsigned long setup_data_phys;
+
+	if (!rng_is_initialized())
+		return;
+
+	sd->type = SETUP_RNG_SEED;
+	sd->len = RNG_SEED_LENGTH;
+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+	sd->next = params->hdr.setup_data;
+	params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
 				  unsigned long params_load_addr,
@@ -190,7 +212,8 @@ static int
 setup_boot_parameters(struct kimage *image, struct boot_params *params,
 		      unsigned long params_load_addr,
 		      unsigned int efi_map_offset, unsigned int efi_map_sz,
-		      unsigned int efi_setup_data_offset)
+		      unsigned int efi_setup_data_offset,
+		      unsigned int rng_seed_setup_data_offset)
 {
 	unsigned int nr_e820_entries;
 	unsigned long long mem_k, start, end;
@@ -242,6 +265,8 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 		}
 	}
 
+	add_rng_seed_setup_data(params, params_load_addr,
+				rng_seed_setup_data_offset);
 #ifdef CONFIG_EFI
 	/* Setup EFI state */
 	setup_efi_state(params, params_load_addr, efi_map_offset, efi_map_sz,
@@ -337,6 +362,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	void *stack;
 	unsigned int setup_hdr_offset = offsetof(struct boot_params, hdr);
 	unsigned int efi_map_offset, efi_map_sz, efi_setup_data_offset;
+	unsigned int rng_seed_setup_data_offset;
 	struct kexec_buf kbuf = { .image = image, .buf_max = ULONG_MAX,
 				  .top_down = true };
 	struct kexec_buf pbuf = { .image = image, .buf_min = MIN_PURGATORY_ADDR,
@@ -401,13 +427,16 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
 				sizeof(struct setup_data) +
-				sizeof(struct efi_setup_data);
+				sizeof(struct efi_setup_data) +
+				sizeof(struct setup_data) +
+				RNG_SEED_LENGTH;
 
 	params = kzalloc(kbuf.bufsz, GFP_KERNEL);
 	if (!params)
 		return ERR_PTR(-ENOMEM);
 	efi_map_offset = params_cmdline_sz;
 	efi_setup_data_offset = efi_map_offset + ALIGN(efi_map_sz, 16);
+	rng_seed_setup_data_offset = efi_setup_data_offset + sizeof(struct efi_setup_data);
 
 	/* Copy setup header onto bootparams. Documentation/x86/boot.rst */
 	setup_header_size = 0x0202 + kernel[0x0201] - setup_hdr_offset;
@@ -490,7 +519,8 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 
 	ret = setup_boot_parameters(image, params, bootparam_load_addr,
 				    efi_map_offset, efi_map_sz,
-				    efi_setup_data_offset);
+				    efi_setup_data_offset,
+				    rng_seed_setup_data_offset);
 	if (ret)
 		goto out_free_params;
 
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index bd6c6fd373ae..409de5308a8c 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -23,6 +23,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -355,6 +356,15 @@ static void __init parse_setup_data(void)
 		case SETUP_EFI:
 			parse_efi_setup(pa_data, data_len);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			/* Zero seed for forward secrecy. */
+			memzero_explicit(data->data, data->len);
+			/* Zero length in case we find ourselves back here by accident. */
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-07  0:08                   ` [PATCH v7] " Jason A. Donenfeld
@ 2022-07-08 11:39                     ` Jason A. Donenfeld
  2022-07-09  1:51                       ` H. Peter Anvin
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-08 11:39 UTC (permalink / raw)
  To: hpa, Thomas Gleixner, Ingo Molnar, Borislav Petkov, X86 ML, LKML,
	Andy Lutomirski
  Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
VMs, EFI is not something you generally need or want.

Rather, here we want the ability for the image loader or firmware to
pass a single random seed, exactly as device tree platforms do with the
"rng-seed" property. Additionally, this is something that bootloaders
can append, with their own seed file management, which is something
every other major OS ecosystem has that we do not (yet).

This patch adds SETUP_RNG_SEED, similar to the other seven setup_data
entries that are parsed at boot. It also takes care to zero out the seed
immediately after using, in order to retain forward secrecy. This all
takes about 7 trivial lines of code.

Then, on kexec_file_load(), a new fresh seed is generated and passed to
the next kernel, just as is done on device tree architectures when
using kexec. And, importantly, I've tested that QEMU is able to properly
pass SETUP_RNG_SEED as well, making this work for every step of the way.
This code too is pretty straight forward.

Together these measures ensure that VMs and nested kexec()'d kernels
always receive a proper boot time RNG seed at the earliest possible
stage from their parents:

   - Host [already has strongly initialized RNG]
     - QEMU [passes fresh seed in SETUP_RNG_SEED field]
       - Linux [uses parent's seed and gathers entropy of its own]
         - kexec [passes this in SETUP_RNG_SEED field]
           - Linux [uses parent's seed and gathers entropy of its own]
             - kexec [passes this in SETUP_RNG_SEED field]
               - Linux [uses parent's seed and gathers entropy of its own]
                 - kexec [passes this in SETUP_RNG_SEED field]
		   - ...

I've verified in several scenarios that this works quite well from a
host kernel to QEMU and down inwards, mixing and matching loaders, with
every layer providing a seed to the next.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v7->v8:
- Rebase against tip.
Changes v6->v7:
- [amluto] Add comment about zeroing fields - data for forward secrecy, len in
  case of accidental reset-to-entry-jump bug.
Changes v5->v6:
- [hpa] Rework commit message to be less confusing and not improperly
  mention e820.
Changes v4->v5:
- Populate field when loading bzimages for kexec, just like device tree
  platforms do.
Changes v3->v4:
- Zero out data after using, for forward secrecy.
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.
Changes v1->v2:
- Fix small typo of data_len -> data->len.

 arch/x86/include/uapi/asm/bootparam.h |  1 +
 arch/x86/kernel/kexec-bzimage64.c     | 40 +++++++++++++++++++++++----
 arch/x86/kernel/setup.c               | 10 +++++++
 3 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index ca0796ac4403..2cbfe630230d 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -12,6 +12,7 @@
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
 #define SETUP_IMA			8
+#define SETUP_RNG_SEED			9
 
 #define SETUP_INDIRECT			(1<<31)
 
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index c63974e94272..e39d8932249d 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +111,26 @@ static int setup_e820_entries(struct boot_params *params)
 	return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+setup_rng_seed(struct boot_params *params, unsigned long params_load_addr,
+	       unsigned int rng_seed_setup_data_offset)
+{
+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+	unsigned long setup_data_phys;
+
+	if (!rng_is_initialized())
+		return;
+
+	sd->type = SETUP_RNG_SEED;
+	sd->len = RNG_SEED_LENGTH;
+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+	sd->next = params->hdr.setup_data;
+	params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
 				  unsigned long params_load_addr,
@@ -191,7 +212,6 @@ setup_ima_state(const struct kimage *image, struct boot_params *params,
 		unsigned long params_load_addr,
 		unsigned int ima_setup_data_offset)
 {
-#ifdef CONFIG_IMA_KEXEC
 	struct setup_data *sd = (void *)params + ima_setup_data_offset;
 	unsigned long setup_data_phys;
 	struct ima_setup_data *ima;
@@ -210,7 +230,6 @@ setup_ima_state(const struct kimage *image, struct boot_params *params,
 	setup_data_phys = params_load_addr + ima_setup_data_offset;
 	sd->next = params->hdr.setup_data;
 	params->hdr.setup_data = setup_data_phys;
-#endif /* CONFIG_IMA_KEXEC */
 }
 
 static int
@@ -277,9 +296,16 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 			sizeof(struct efi_setup_data);
 #endif
 
-	/* Setup IMA log buffer state */
-	setup_ima_state(image, params, params_load_addr,
-			setup_data_offset);
+	if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
+		/* Setup IMA log buffer state */
+		setup_ima_state(image, params, params_load_addr,
+				setup_data_offset);
+		setup_data_offset += sizeof(struct setup_data) +
+				     sizeof(struct ima_setup_data);
+	}
+
+	/* Setup RNG seed */
+	setup_rng_seed(params, params_load_addr, setup_data_offset);
 
 	/* Setup EDD info */
 	memcpy(params->eddbuf, boot_params.eddbuf,
@@ -435,7 +461,9 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
 				sizeof(struct setup_data) +
-				sizeof(struct efi_setup_data);
+				sizeof(struct efi_setup_data) +
+				sizeof(struct setup_data) +
+				RNG_SEED_LENGTH;
 
 	if (IS_ENABLED(CONFIG_IMA_KEXEC))
 		kbuf.bufsz += sizeof(struct setup_data) +
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 53f863f28b4c..216fee7144ee 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -24,6 +24,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -418,6 +419,15 @@ static void __init parse_setup_data(void)
 		case SETUP_IMA:
 			add_early_ima_buffer(pa_data);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			/* Zero seed for forward secrecy. */
+			memzero_explicit(data->data, data->len);
+			/* Zero length in case we find ourselves back here by accident. */
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-08 11:39                     ` [PATCH tip v8] " Jason A. Donenfeld
@ 2022-07-09  1:51                       ` H. Peter Anvin
  2022-07-09  9:43                         ` Jason A. Donenfeld
  2022-07-09  9:49                         ` [PATCH tip v8] " Borislav Petkov
  0 siblings, 2 replies; 29+ messages in thread
From: H. Peter Anvin @ 2022-07-09  1:51 UTC (permalink / raw)
  To: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, X86 ML, LKML, Andy Lutomirski

On 7/8/22 04:39, Jason A. Donenfeld wrote:
> 
> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
> index ca0796ac4403..2cbfe630230d 100644
> --- a/arch/x86/include/uapi/asm/bootparam.h
> +++ b/arch/x86/include/uapi/asm/bootparam.h
> @@ -12,6 +12,7 @@
>   #define SETUP_JAILHOUSE			6
>   #define SETUP_CC_BLOB			7
>   #define SETUP_IMA			8
> +#define SETUP_RNG_SEED			9
>   
>   #define SETUP_INDIRECT			(1<<31)
>   

Just one miss here: you need to bump SETUP_TYPE_MAX. It is a bit more 
confusing than it needs to be that SETUP_INDIRECT sits in between, and 
honestly I think SETUP_TYPE_MAX shouldn't include the SETUP_INDIRECT 
bit; however, this is uapi and so we can't change that per se.

Perhaps we should do:

#define SETUP_ENUM_MAX	SETUP_RNG_SEED
#define SETUP_INDIRECT	(1<<31)
#define SETUP_TYPE_MAX	(SETUP_ENUM_MAX | SETUP_INDIRECT)

	-hpa

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09  1:51                       ` H. Peter Anvin
@ 2022-07-09  9:43                         ` Jason A. Donenfeld
  2022-07-09  9:48                           ` [PATCH tip v9] " Jason A. Donenfeld
  2022-07-09  9:49                         ` [PATCH tip v8] " Borislav Petkov
  1 sibling, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-09  9:43 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, X86 ML, LKML,
	Andy Lutomirski

Hi Peter,

On Fri, Jul 08, 2022 at 06:51:16PM -0700, H. Peter Anvin wrote:
> On 7/8/22 04:39, Jason A. Donenfeld wrote:
> > 
> > diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
> > index ca0796ac4403..2cbfe630230d 100644
> > --- a/arch/x86/include/uapi/asm/bootparam.h
> > +++ b/arch/x86/include/uapi/asm/bootparam.h
> > @@ -12,6 +12,7 @@
> >   #define SETUP_JAILHOUSE			6
> >   #define SETUP_CC_BLOB			7
> >   #define SETUP_IMA			8
> > +#define SETUP_RNG_SEED			9
> >   
> >   #define SETUP_INDIRECT			(1<<31)
> >   
> 
> Just one miss here: you need to bump SETUP_TYPE_MAX. It is a bit more 
> confusing than it needs to be that SETUP_INDIRECT sits in between, and 
> honestly I think SETUP_TYPE_MAX shouldn't include the SETUP_INDIRECT 
> bit; however, this is uapi and so we can't change that per se.
> 
> Perhaps we should do:
> 
> #define SETUP_ENUM_MAX	SETUP_RNG_SEED
> #define SETUP_INDIRECT	(1<<31)
> #define SETUP_TYPE_MAX	(SETUP_ENUM_MAX | SETUP_INDIRECT)

Thanks, nice catch. I'll do exactly that. v+1 incoming.

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH tip v9] x86/setup: Use rng seeds from setup_data
  2022-07-09  9:43                         ` Jason A. Donenfeld
@ 2022-07-09  9:48                           ` Jason A. Donenfeld
  2022-07-09 22:42                             ` H. Peter Anvin
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-09  9:48 UTC (permalink / raw)
  To: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	X86 ML, LKML, Andy Lutomirski
  Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
VMs, EFI is not something you generally need or want.

Rather, here we want the ability for the image loader or firmware to
pass a single random seed, exactly as device tree platforms do with the
"rng-seed" property. Additionally, this is something that bootloaders
can append, with their own seed file management, which is something
every other major OS ecosystem has that we do not (yet).

This patch adds SETUP_RNG_SEED, similar to the other seven setup_data
entries that are parsed at boot. It also takes care to zero out the seed
immediately after using, in order to retain forward secrecy. This all
takes about 7 trivial lines of code.

Then, on kexec_file_load(), a new fresh seed is generated and passed to
the next kernel, just as is done on device tree architectures when
using kexec. And, importantly, I've tested that QEMU is able to properly
pass SETUP_RNG_SEED as well, making this work for every step of the way.
This code too is pretty straight forward.

Together these measures ensure that VMs and nested kexec()'d kernels
always receive a proper boot time RNG seed at the earliest possible
stage from their parents:

   - Host [already has strongly initialized RNG]
     - QEMU [passes fresh seed in SETUP_RNG_SEED field]
       - Linux [uses parent's seed and gathers entropy of its own]
         - kexec [passes this in SETUP_RNG_SEED field]
           - Linux [uses parent's seed and gathers entropy of its own]
             - kexec [passes this in SETUP_RNG_SEED field]
               - Linux [uses parent's seed and gathers entropy of its own]
                 - kexec [passes this in SETUP_RNG_SEED field]
		   - ...

I've verified in several scenarios that this works quite well from a
host kernel to QEMU and down inwards, mixing and matching loaders, with
every layer providing a seed to the next.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v8->v9:
- [hpa] Update SETUP_TYPE_MAX and add SETUP_ENUM_MAX.
Changes v7->v8:
- Rebase against tip.
Changes v6->v7:
- [amluto] Add comment about zeroing fields - data for forward secrecy, len in
  case of accidental reset-to-entry-jump bug.
Changes v5->v6:
- [hpa] Rework commit message to be less confusing and not improperly
  mention e820.
Changes v4->v5:
- Populate field when loading bzimages for kexec, just like device tree
  platforms do.
Changes v3->v4:
- Zero out data after using, for forward secrecy.
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.
Changes v1->v2:
- Fix small typo of data_len -> data->len.


 arch/x86/include/uapi/asm/bootparam.h |  6 ++--
 arch/x86/kernel/kexec-bzimage64.c     | 40 +++++++++++++++++++++++----
 arch/x86/kernel/setup.c               | 10 +++++++
 3 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index ca0796ac4403..342290624040 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -12,11 +12,11 @@
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
 #define SETUP_IMA			8
+#define SETUP_RNG_SEED			9
+#define SETUP_ENUM_MAX			SETUP_RNG_SEED
 
 #define SETUP_INDIRECT			(1<<31)
-
-/* SETUP_INDIRECT | max(SETUP_*) */
-#define SETUP_TYPE_MAX			(SETUP_INDIRECT | SETUP_JAILHOUSE)
+#define SETUP_TYPE_MAX			(SETUP_ENUM_MAX | SETUP_INDIRECT)
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK	0x07FF
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index c63974e94272..e39d8932249d 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +111,26 @@ static int setup_e820_entries(struct boot_params *params)
 	return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+setup_rng_seed(struct boot_params *params, unsigned long params_load_addr,
+	       unsigned int rng_seed_setup_data_offset)
+{
+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+	unsigned long setup_data_phys;
+
+	if (!rng_is_initialized())
+		return;
+
+	sd->type = SETUP_RNG_SEED;
+	sd->len = RNG_SEED_LENGTH;
+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+	sd->next = params->hdr.setup_data;
+	params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
 				  unsigned long params_load_addr,
@@ -191,7 +212,6 @@ setup_ima_state(const struct kimage *image, struct boot_params *params,
 		unsigned long params_load_addr,
 		unsigned int ima_setup_data_offset)
 {
-#ifdef CONFIG_IMA_KEXEC
 	struct setup_data *sd = (void *)params + ima_setup_data_offset;
 	unsigned long setup_data_phys;
 	struct ima_setup_data *ima;
@@ -210,7 +230,6 @@ setup_ima_state(const struct kimage *image, struct boot_params *params,
 	setup_data_phys = params_load_addr + ima_setup_data_offset;
 	sd->next = params->hdr.setup_data;
 	params->hdr.setup_data = setup_data_phys;
-#endif /* CONFIG_IMA_KEXEC */
 }
 
 static int
@@ -277,9 +296,16 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 			sizeof(struct efi_setup_data);
 #endif
 
-	/* Setup IMA log buffer state */
-	setup_ima_state(image, params, params_load_addr,
-			setup_data_offset);
+	if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
+		/* Setup IMA log buffer state */
+		setup_ima_state(image, params, params_load_addr,
+				setup_data_offset);
+		setup_data_offset += sizeof(struct setup_data) +
+				     sizeof(struct ima_setup_data);
+	}
+
+	/* Setup RNG seed */
+	setup_rng_seed(params, params_load_addr, setup_data_offset);
 
 	/* Setup EDD info */
 	memcpy(params->eddbuf, boot_params.eddbuf,
@@ -435,7 +461,9 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
 				sizeof(struct setup_data) +
-				sizeof(struct efi_setup_data);
+				sizeof(struct efi_setup_data) +
+				sizeof(struct setup_data) +
+				RNG_SEED_LENGTH;
 
 	if (IS_ENABLED(CONFIG_IMA_KEXEC))
 		kbuf.bufsz += sizeof(struct setup_data) +
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 53f863f28b4c..216fee7144ee 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -24,6 +24,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -418,6 +419,15 @@ static void __init parse_setup_data(void)
 		case SETUP_IMA:
 			add_early_ima_buffer(pa_data);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			/* Zero seed for forward secrecy. */
+			memzero_explicit(data->data, data->len);
+			/* Zero length in case we find ourselves back here by accident. */
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09  1:51                       ` H. Peter Anvin
  2022-07-09  9:43                         ` Jason A. Donenfeld
@ 2022-07-09  9:49                         ` Borislav Petkov
  2022-07-09  9:53                           ` Jason A. Donenfeld
                                             ` (2 more replies)
  1 sibling, 3 replies; 29+ messages in thread
From: Borislav Petkov @ 2022-07-09  9:49 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On Fri, Jul 08, 2022 at 06:51:16PM -0700, H. Peter Anvin wrote:
> #define SETUP_ENUM_MAX	SETUP_RNG_SEED
> #define SETUP_INDIRECT	(1<<31)
> #define SETUP_TYPE_MAX	(SETUP_ENUM_MAX | SETUP_INDIRECT)

Wait, if we get to add a new number, SETUP_ENUM_MAX and thus
SETUP_TYPE_MAX will change. And they're uapi too...

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09  9:49                         ` [PATCH tip v8] " Borislav Petkov
@ 2022-07-09  9:53                           ` Jason A. Donenfeld
  2022-07-09 10:21                           ` Borislav Petkov
  2022-07-09 21:45                           ` H. Peter Anvin
  2 siblings, 0 replies; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-09  9:53 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

Hi Borislav,

On Sat, Jul 9, 2022 at 11:49 AM Borislav Petkov <bp@alien8.de> wrote:
>
> On Fri, Jul 08, 2022 at 06:51:16PM -0700, H. Peter Anvin wrote:
> > #define SETUP_ENUM_MAX        SETUP_RNG_SEED
> > #define SETUP_INDIRECT        (1<<31)
> > #define SETUP_TYPE_MAX        (SETUP_ENUM_MAX | SETUP_INDIRECT)
>
> Wait, if we get to add a new number, SETUP_ENUM_MAX and thus
> SETUP_TYPE_MAX will change. And they're uapi too...

Perhaps this is the reason it wasn't bumped earlier from 6 to 8 (this
patch adds 9)? I suspect the primary usage is in .rodata.kernel_info,
though.

Anyway, you now have my v9 which updates the value, and my v8 which
does not. Whichever one, v8 or v9, is fine with me. Maybe you should
take v8 into tip now, and then I'll send a follow up that updates the
values, so it can be reverted separately need-be?

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09  9:49                         ` [PATCH tip v8] " Borislav Petkov
  2022-07-09  9:53                           ` Jason A. Donenfeld
@ 2022-07-09 10:21                           ` Borislav Petkov
  2022-07-09 21:45                           ` H. Peter Anvin
  2 siblings, 0 replies; 29+ messages in thread
From: Borislav Petkov @ 2022-07-09 10:21 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On Sat, Jul 09, 2022 at 11:49:29AM +0200, Borislav Petkov wrote:
> On Fri, Jul 08, 2022 at 06:51:16PM -0700, H. Peter Anvin wrote:
> > #define SETUP_ENUM_MAX	SETUP_RNG_SEED
> > #define SETUP_INDIRECT	(1<<31)
> > #define SETUP_TYPE_MAX	(SETUP_ENUM_MAX | SETUP_INDIRECT)
> 
> Wait, if we get to add a new number, SETUP_ENUM_MAX and thus
> SETUP_TYPE_MAX will change. And they're uapi too...

Err, we've already dropped the ball there:

#define SETUP_INDIRECT                  (1<<31)

/* SETUP_INDIRECT | max(SETUP_*) */
#define SETUP_TYPE_MAX                  (SETUP_INDIRECT | SETUP_JAILHOUSE)

and by "we" I probably mean "me" because I didn't catch that with
SETUP_CC_BLOB.

The good news is, CC_BLOB is not in a released kernel yet so we still
have chance to fix it properly...

;-\

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09  9:49                         ` [PATCH tip v8] " Borislav Petkov
  2022-07-09  9:53                           ` Jason A. Donenfeld
  2022-07-09 10:21                           ` Borislav Petkov
@ 2022-07-09 21:45                           ` H. Peter Anvin
  2022-07-09 21:57                             ` Borislav Petkov
  2 siblings, 1 reply; 29+ messages in thread
From: H. Peter Anvin @ 2022-07-09 21:45 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On 7/9/22 02:49, Borislav Petkov wrote:
> On Fri, Jul 08, 2022 at 06:51:16PM -0700, H. Peter Anvin wrote:
>> #define SETUP_ENUM_MAX	SETUP_RNG_SEED
>> #define SETUP_INDIRECT	(1<<31)
>> #define SETUP_TYPE_MAX	(SETUP_ENUM_MAX | SETUP_INDIRECT)
> 
> Wait, if we get to add a new number, SETUP_ENUM_MAX and thus
> SETUP_TYPE_MAX will change. And they're uapi too...

Talking API here rather than ABI, i.e. the semantics of those symbols.

	-hpa


^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09 21:45                           ` H. Peter Anvin
@ 2022-07-09 21:57                             ` Borislav Petkov
  2022-07-09 22:41                               ` H. Peter Anvin
  0 siblings, 1 reply; 29+ messages in thread
From: Borislav Petkov @ 2022-07-09 21:57 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On Sat, Jul 09, 2022 at 02:45:24PM -0700, H. Peter Anvin wrote:
> On 7/9/22 02:49, Borislav Petkov wrote:
> > On Fri, Jul 08, 2022 at 06:51:16PM -0700, H. Peter Anvin wrote:
> > > #define SETUP_ENUM_MAX	SETUP_RNG_SEED
> > > #define SETUP_INDIRECT	(1<<31)
> > > #define SETUP_TYPE_MAX	(SETUP_ENUM_MAX | SETUP_INDIRECT)
> > 
> > Wait, if we get to add a new number, SETUP_ENUM_MAX and thus
> > SETUP_TYPE_MAX will change. And they're uapi too...
> 
> Talking API here rather than ABI, i.e. the semantics of those symbols.

Sure but do we worry about some userspace including those headers and
relying on the SETUP_ENUM_MAX number?

Or is userspace required to be recompiled against newer uapi headers?

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09 21:57                             ` Borislav Petkov
@ 2022-07-09 22:41                               ` H. Peter Anvin
  2022-07-10  9:45                                 ` Borislav Petkov
  0 siblings, 1 reply; 29+ messages in thread
From: H. Peter Anvin @ 2022-07-09 22:41 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On 7/9/22 14:57, Borislav Petkov wrote:
> On Sat, Jul 09, 2022 at 02:45:24PM -0700, H. Peter Anvin wrote:
>> On 7/9/22 02:49, Borislav Petkov wrote:
>>> On Fri, Jul 08, 2022 at 06:51:16PM -0700, H. Peter Anvin wrote:
>>>> #define SETUP_ENUM_MAX	SETUP_RNG_SEED
>>>> #define SETUP_INDIRECT	(1<<31)
>>>> #define SETUP_TYPE_MAX	(SETUP_ENUM_MAX | SETUP_INDIRECT)
>>>
>>> Wait, if we get to add a new number, SETUP_ENUM_MAX and thus
>>> SETUP_TYPE_MAX will change. And they're uapi too...
>>
>> Talking API here rather than ABI, i.e. the semantics of those symbols.
> 
> Sure but do we worry about some userspace including those headers and
> relying on the SETUP_ENUM_MAX number?
> 
> Or is userspace required to be recompiled against newer uapi headers?
> 

In ABI/API terms, that symbol has the semantic of connecting the API 
version to the underlying ABI version; a piece of code that sees an 
enumeration type > SETUP_ENUM_MAX must by definition treat it as an 
opaque blob. In the future, should it become warranted, we may add flags 
that indicate how unaware code should handle them, but I don't think we 
can engineer that right now.

	-hpa

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v9] x86/setup: Use rng seeds from setup_data
  2022-07-09  9:48                           ` [PATCH tip v9] " Jason A. Donenfeld
@ 2022-07-09 22:42                             ` H. Peter Anvin
  2022-07-09 23:23                               ` Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: H. Peter Anvin @ 2022-07-09 22:42 UTC (permalink / raw)
  To: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, X86 ML, LKML, Andy Lutomirski

On 7/9/22 02:48, Jason A. Donenfeld wrote:
> Currently the only way x86 can get an early boot RNG seed is via EFI,
> which is generally always used now for physical machines, but is very
> rarely used in VMs, especially VMs that are optimized for starting
> "instantaneously", such as Firecracker's MicroVM. For tiny fast booting
> VMs, EFI is not something you generally need or want.
> 
> Rather, here we want the ability for the image loader or firmware to
> pass a single random seed, exactly as device tree platforms do with the
> "rng-seed" property. Additionally, this is something that bootloaders
> can append, with their own seed file management, which is something
> every other major OS ecosystem has that we do not (yet).
> 
> This patch adds SETUP_RNG_SEED, similar to the other seven setup_data
> entries that are parsed at boot. It also takes care to zero out the seed
> immediately after using, in order to retain forward secrecy. This all
> takes about 7 trivial lines of code.
> 
> Then, on kexec_file_load(), a new fresh seed is generated and passed to
> the next kernel, just as is done on device tree architectures when
> using kexec. And, importantly, I've tested that QEMU is able to properly
> pass SETUP_RNG_SEED as well, making this work for every step of the way.
> This code too is pretty straight forward.
> 
> Together these measures ensure that VMs and nested kexec()'d kernels
> always receive a proper boot time RNG seed at the earliest possible
> stage from their parents:
> 
>     - Host [already has strongly initialized RNG]
>       - QEMU [passes fresh seed in SETUP_RNG_SEED field]
>         - Linux [uses parent's seed and gathers entropy of its own]
>           - kexec [passes this in SETUP_RNG_SEED field]
>             - Linux [uses parent's seed and gathers entropy of its own]
>               - kexec [passes this in SETUP_RNG_SEED field]
>                 - Linux [uses parent's seed and gathers entropy of its own]
>                   - kexec [passes this in SETUP_RNG_SEED field]
> 		   - ...
> 
> I've verified in several scenarios that this works quite well from a
> host kernel to QEMU and down inwards, mixing and matching loaders, with
> every layer providing a seed to the next.
> 
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>

Acked-by: H. Peter Anvin (Intel) <hpa@zytor.com>

> ---
> Changes v8->v9:
> - [hpa] Update SETUP_TYPE_MAX and add SETUP_ENUM_MAX.

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v9] x86/setup: Use rng seeds from setup_data
  2022-07-09 22:42                             ` H. Peter Anvin
@ 2022-07-09 23:23                               ` Jason A. Donenfeld
  0 siblings, 0 replies; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-09 23:23 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, X86 ML, LKML,
	Andy Lutomirski

Hey Peter,

On 7/10/22, H. Peter Anvin <hpa@zytor.com> wrote:
> On 7/9/22 02:48, Jason A. Donenfeld wrote:
>> Currently the only way x86 can get an early boot RNG seed is via EFI,
>> which is generally always used now for physical machines, but is very
>> rarely used in VMs, especially VMs that are optimized for starting
>> "instantaneously", such as Firecracker's MicroVM. For tiny fast booting
>> VMs, EFI is not something you generally need or want.
>>
>> Rather, here we want the ability for the image loader or firmware to
>> pass a single random seed, exactly as device tree platforms do with the
>> "rng-seed" property. Additionally, this is something that bootloaders
>> can append, with their own seed file management, which is something
>> every other major OS ecosystem has that we do not (yet).
>>
>> This patch adds SETUP_RNG_SEED, similar to the other seven setup_data
>> entries that are parsed at boot. It also takes care to zero out the seed
>> immediately after using, in order to retain forward secrecy. This all
>> takes about 7 trivial lines of code.
>>
>> Then, on kexec_file_load(), a new fresh seed is generated and passed to
>> the next kernel, just as is done on device tree architectures when
>> using kexec. And, importantly, I've tested that QEMU is able to properly
>> pass SETUP_RNG_SEED as well, making this work for every step of the way.
>> This code too is pretty straight forward.
>>
>> Together these measures ensure that VMs and nested kexec()'d kernels
>> always receive a proper boot time RNG seed at the earliest possible
>> stage from their parents:
>>
>>     - Host [already has strongly initialized RNG]
>>       - QEMU [passes fresh seed in SETUP_RNG_SEED field]
>>         - Linux [uses parent's seed and gathers entropy of its own]
>>           - kexec [passes this in SETUP_RNG_SEED field]
>>             - Linux [uses parent's seed and gathers entropy of its own]
>>               - kexec [passes this in SETUP_RNG_SEED field]
>>                 - Linux [uses parent's seed and gathers entropy of its
>> own]
>>                   - kexec [passes this in SETUP_RNG_SEED field]
>> 		   - ...
>>
>> I've verified in several scenarios that this works quite well from a
>> host kernel to QEMU and down inwards, mixing and matching loaders, with
>> every layer providing a seed to the next.
>>
>> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
>
> Acked-by: H. Peter Anvin (Intel) <hpa@zytor.com>

Thanks for the ack. In case your ack here is meant to communicate
"good to go for random.git," I thought I should mention: while earlier
versions of this patch were against my random.git tree, this one (and
the previous) is against tip.git, because otherwise there'd be some
annoying conflicts when merging. So if it's not too much trouble, I
think it would make sense to apply this to tip.

Jason

>
>> ---
>> Changes v8->v9:
>> - [hpa] Update SETUP_TYPE_MAX and add SETUP_ENUM_MAX.
>

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-09 22:41                               ` H. Peter Anvin
@ 2022-07-10  9:45                                 ` Borislav Petkov
  2022-07-10 11:11                                   ` Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Borislav Petkov @ 2022-07-10  9:45 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Jason A. Donenfeld, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On Sat, Jul 09, 2022 at 03:41:19PM -0700, H. Peter Anvin wrote:
> In ABI/API terms, that symbol has the semantic of connecting the API version
> to the underlying ABI version; a piece of code that sees an enumeration type
> > SETUP_ENUM_MAX must by definition treat it as an opaque blob. In the
> future, should it become warranted, we may add flags that indicate how
> unaware code should handle them, but I don't think we can engineer that
> right now.

Ok, let's hope it doesn't come to that and userspace behaves... <eyeroll>

So, I'm going to send the below to Linus now so that 5.19 releases fixed
and then queue Jason's patch next week.

Thx.

---

From: Borislav Petkov <bp@suse.de>
Date: Sun, 10 Jul 2022 11:15:47 +0200
Subject: [PATCH] x86/boot: Fix the setup data types max limit

Commit in Fixes forgot to change the SETUP_TYPE_MAX definition which
contains the highest valid setup data type.

Correct that.

Fixes: 5ea98e01ab52 ("x86/boot: Add Confidential Computing type to setup_data")
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lore.kernel.org/r/ddba81dd-cc92-699c-5274-785396a17fb5@zytor.com
---
 arch/x86/include/uapi/asm/bootparam.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index bea5cdcdf532..e02a8a8ef23c 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -15,7 +15,7 @@
 #define SETUP_INDIRECT			(1<<31)
 
 /* SETUP_INDIRECT | max(SETUP_*) */
-#define SETUP_TYPE_MAX			(SETUP_INDIRECT | SETUP_JAILHOUSE)
+#define SETUP_TYPE_MAX			(SETUP_INDIRECT | SETUP_CC_BLOB)
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK	0x07FF
-- 
2.35.1


-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply related	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-10  9:45                                 ` Borislav Petkov
@ 2022-07-10 11:11                                   ` Jason A. Donenfeld
  2022-07-10 12:27                                     ` Borislav Petkov
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-10 11:11 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On 7/10/22, Borislav Petkov <bp@alien8.de> wrote:
> On Sat, Jul 09, 2022 at 03:41:19PM -0700, H. Peter Anvin wrote:
>> In ABI/API terms, that symbol has the semantic of connecting the API
>> version
>> to the underlying ABI version; a piece of code that sees an enumeration
>> type
>> > SETUP_ENUM_MAX must by definition treat it as an opaque blob. In the
>> future, should it become warranted, we may add flags that indicate how
>> unaware code should handle them, but I don't think we can engineer that
>> right now.
>
> Ok, let's hope it doesn't come to that and userspace behaves... <eyeroll>
>
> So, I'm going to send the below to Linus now so that 5.19 releases fixed
> and then queue Jason's patch next week.

Do you want me to rebase mine on top of the 5.19 fixup? Or is that
trivial enough that you'll just do it when applying?

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-10 11:11                                   ` Jason A. Donenfeld
@ 2022-07-10 12:27                                     ` Borislav Petkov
  2022-07-10 17:13                                       ` Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Borislav Petkov @ 2022-07-10 12:27 UTC (permalink / raw)
  To: Jason A. Donenfeld
  Cc: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On Sun, Jul 10, 2022 at 01:11:16PM +0200, Jason A. Donenfeld wrote:
> Do you want me to rebase mine on top of the 5.19 fixup? Or is that
> trivial enough that you'll just do it when applying?

Yeah, I'll take care of it, no worries.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply	[flat|nested] 29+ messages in thread

* Re: [PATCH tip v8] x86/setup: Use rng seeds from setup_data
  2022-07-10 12:27                                     ` Borislav Petkov
@ 2022-07-10 17:13                                       ` Jason A. Donenfeld
  2022-07-10 17:29                                         ` [PATCH tip v10] " Jason A. Donenfeld
  0 siblings, 1 reply; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-10 17:13 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: H. Peter Anvin, Thomas Gleixner, Ingo Molnar, X86 ML, LKML,
	Andy Lutomirski

On Sun, Jul 10, 2022 at 02:27:13PM +0200, Borislav Petkov wrote:
> On Sun, Jul 10, 2022 at 01:11:16PM +0200, Jason A. Donenfeld wrote:
> > Do you want me to rebase mine on top of the 5.19 fixup? Or is that
> > trivial enough that you'll just do it when applying?
> 
> Yeah, I'll take care of it, no worries.

Actually, I need to send another revision anyway, as kernel test bot
just barked at me for something dumb. Incoming...

Jason

^ permalink raw reply	[flat|nested] 29+ messages in thread

* [PATCH tip v10] x86/setup: Use rng seeds from setup_data
  2022-07-10 17:13                                       ` Jason A. Donenfeld
@ 2022-07-10 17:29                                         ` Jason A. Donenfeld
  0 siblings, 0 replies; 29+ messages in thread
From: Jason A. Donenfeld @ 2022-07-10 17:29 UTC (permalink / raw)
  To: bp, x86, linux-kernel, hpa; +Cc: Jason A. Donenfeld

Currently the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
VMs, EFI is not something you generally need or want.

Rather, here we want the ability for the image loader or firmware to
pass a single random seed, exactly as device tree platforms do with the
"rng-seed" property. Additionally, this is something that bootloaders
can append, with their own seed file management, which is something
every other major OS ecosystem has that we do not (yet).

This patch adds SETUP_RNG_SEED, similar to the other seven setup_data
entries that are parsed at boot. It also takes care to zero out the seed
immediately after using, in order to retain forward secrecy. This all
takes about 7 trivial lines of code.

Then, on kexec_file_load(), a new fresh seed is generated and passed to
the next kernel, just as is done on device tree architectures when
using kexec. And, importantly, I've tested that QEMU is able to properly
pass SETUP_RNG_SEED as well, making this work for every step of the way.
This code too is pretty straight forward.

Together these measures ensure that VMs and nested kexec()'d kernels
always receive a proper boot time RNG seed at the earliest possible
stage from their parents:

   - Host [already has strongly initialized RNG]
     - QEMU [passes fresh seed in SETUP_RNG_SEED field]
       - Linux [uses parent's seed and gathers entropy of its own]
         - kexec [passes this in SETUP_RNG_SEED field]
           - Linux [uses parent's seed and gathers entropy of its own]
             - kexec [passes this in SETUP_RNG_SEED field]
               - Linux [uses parent's seed and gathers entropy of its own]
                 - kexec [passes this in SETUP_RNG_SEED field]
		   - ...

I've verified in several scenarios that this works quite well from a
host kernel to QEMU and down inwards, mixing and matching loaders, with
every layer providing a seed to the next.

Acked-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
Changes v9->v10:
- Don't remove IMA_KEXEC ifdef guard.
- Rebase on top of x86/urgent for cb8a4beac39b90cd6.
Changes v8->v9:
- [hpa] Update SETUP_TYPE_MAX and add SETUP_ENUM_MAX.
Changes v7->v8:
- Rebase against tip.
Changes v6->v7:
- [amluto] Add comment about zeroing fields - data for forward secrecy, len in
  case of accidental reset-to-entry-jump bug.
Changes v5->v6:
- [hpa] Rework commit message to be less confusing and not improperly
  mention e820.
Changes v4->v5:
- Populate field when loading bzimages for kexec, just like device tree
  platforms do.
Changes v3->v4:
- Zero out data after using, for forward secrecy.
Changes v2->v3:
- Actually memmap the right area with the random bytes in it. This
  worked before because of page sizes, but the code wasn't right. Now
  it's right.
Changes v1->v2:
- Fix small typo of data_len -> data->len.

 arch/x86/include/uapi/asm/bootparam.h |  6 ++---
 arch/x86/kernel/kexec-bzimage64.c     | 38 ++++++++++++++++++++++++---
 arch/x86/kernel/setup.c               | 10 +++++++
 3 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index be2b9ce52c76..342290624040 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -12,11 +12,11 @@
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
 #define SETUP_IMA			8
+#define SETUP_RNG_SEED			9
+#define SETUP_ENUM_MAX			SETUP_RNG_SEED
 
 #define SETUP_INDIRECT			(1<<31)
-
-/* SETUP_INDIRECT | max(SETUP_*) */
-#define SETUP_TYPE_MAX			(SETUP_INDIRECT | SETUP_CC_BLOB)
+#define SETUP_TYPE_MAX			(SETUP_ENUM_MAX | SETUP_INDIRECT)
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK	0x07FF
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index c63974e94272..b9bdb40364a6 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +111,26 @@ static int setup_e820_entries(struct boot_params *params)
 	return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+setup_rng_seed(struct boot_params *params, unsigned long params_load_addr,
+	       unsigned int rng_seed_setup_data_offset)
+{
+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+	unsigned long setup_data_phys;
+
+	if (!rng_is_initialized())
+		return;
+
+	sd->type = SETUP_RNG_SEED;
+	sd->len = RNG_SEED_LENGTH;
+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+	sd->next = params->hdr.setup_data;
+	params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
 				  unsigned long params_load_addr,
@@ -277,9 +298,16 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 			sizeof(struct efi_setup_data);
 #endif
 
-	/* Setup IMA log buffer state */
-	setup_ima_state(image, params, params_load_addr,
-			setup_data_offset);
+	if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
+		/* Setup IMA log buffer state */
+		setup_ima_state(image, params, params_load_addr,
+				setup_data_offset);
+		setup_data_offset += sizeof(struct setup_data) +
+				     sizeof(struct ima_setup_data);
+	}
+
+	/* Setup RNG seed */
+	setup_rng_seed(params, params_load_addr, setup_data_offset);
 
 	/* Setup EDD info */
 	memcpy(params->eddbuf, boot_params.eddbuf,
@@ -435,7 +463,9 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
 				sizeof(struct setup_data) +
-				sizeof(struct efi_setup_data);
+				sizeof(struct efi_setup_data) +
+				sizeof(struct setup_data) +
+				RNG_SEED_LENGTH;
 
 	if (IS_ENABLED(CONFIG_IMA_KEXEC))
 		kbuf.bufsz += sizeof(struct setup_data) +
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 53f863f28b4c..216fee7144ee 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -24,6 +24,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -418,6 +419,15 @@ static void __init parse_setup_data(void)
 		case SETUP_IMA:
 			add_early_ima_buffer(pa_data);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			/* Zero seed for forward secrecy. */
+			memzero_explicit(data->data, data->len);
+			/* Zero length in case we find ourselves back here by accident. */
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 29+ messages in thread

* [tip: x86/kdump] x86/setup: Use rng seeds from setup_data
  2022-06-30 11:33 [PATCH] x86/setup: Allow passing RNG seeds via e820 setup table Jason A. Donenfeld
  2022-06-30 11:59 ` [PATCH v2] " Jason A. Donenfeld
@ 2022-07-11  9:39 ` tip-bot2 for Jason A. Donenfeld
  1 sibling, 0 replies; 29+ messages in thread
From: tip-bot2 for Jason A. Donenfeld @ 2022-07-11  9:39 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Jason A. Donenfeld, Borislav Petkov, H. Peter Anvin (Intel),
	x86, linux-kernel

The following commit has been merged into the x86/kdump branch of tip:

Commit-ID:     68b8e9713c8ec90af93c16e1de51cca18cefdb56
Gitweb:        https://git.kernel.org/tip/68b8e9713c8ec90af93c16e1de51cca18cefdb56
Author:        Jason A. Donenfeld <Jason@zx2c4.com>
AuthorDate:    Sun, 10 Jul 2022 19:29:21 +02:00
Committer:     Borislav Petkov <bp@suse.de>
CommitterDate: Mon, 11 Jul 2022 09:59:31 +02:00

x86/setup: Use rng seeds from setup_data

Currently, the only way x86 can get an early boot RNG seed is via EFI,
which is generally always used now for physical machines, but is very
rarely used in VMs, especially VMs that are optimized for starting
"instantaneously", such as Firecracker's MicroVM. For tiny fast booting
VMs, EFI is not something you generally need or want.

Rather, the image loader or firmware should be able to pass a single
random seed, exactly as device tree platforms do with the "rng-seed"
property. Additionally, this is something that bootloaders can append,
with their own seed file management, which is something every other
major OS ecosystem has that Linux does not (yet).

Add SETUP_RNG_SEED, similar to the other eight setup_data entries that
are parsed at boot. It also takes care to zero out the seed immediately
after using, in order to retain forward secrecy. This all takes about 7
trivial lines of code.

Then, on kexec_file_load(), a new fresh seed is generated and passed to
the next kernel, just as is done on device tree architectures when
using kexec. And, importantly, I've tested that QEMU is able to properly
pass SETUP_RNG_SEED as well, making this work for every step of the way.
This code too is pretty straight forward.

Together these measures ensure that VMs and nested kexec()'d kernels
always receive a proper boot time RNG seed at the earliest possible
stage from their parents:

   - Host [already has strongly initialized RNG]
     - QEMU [passes fresh seed in SETUP_RNG_SEED field]
       - Linux [uses parent's seed and gathers entropy of its own]
         - kexec [passes this in SETUP_RNG_SEED field]
           - Linux [uses parent's seed and gathers entropy of its own]
             - kexec [passes this in SETUP_RNG_SEED field]
               - Linux [uses parent's seed and gathers entropy of its own]
                 - kexec [passes this in SETUP_RNG_SEED field]
		   - ...

I've verified in several scenarios that this works quite well from a
host kernel to QEMU and down inwards, mixing and matching loaders, with
every layer providing a seed to the next.

  [ bp: Massage commit message. ]

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Link: https://lore.kernel.org/r/20220630113300.1892799-1-Jason@zx2c4.com
---
 arch/x86/include/uapi/asm/bootparam.h |  6 ++--
 arch/x86/kernel/kexec-bzimage64.c     | 38 +++++++++++++++++++++++---
 arch/x86/kernel/setup.c               | 10 +++++++-
 3 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index be2b9ce..3422906 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -12,11 +12,11 @@
 #define SETUP_JAILHOUSE			6
 #define SETUP_CC_BLOB			7
 #define SETUP_IMA			8
+#define SETUP_RNG_SEED			9
+#define SETUP_ENUM_MAX			SETUP_RNG_SEED
 
 #define SETUP_INDIRECT			(1<<31)
-
-/* SETUP_INDIRECT | max(SETUP_*) */
-#define SETUP_TYPE_MAX			(SETUP_INDIRECT | SETUP_CC_BLOB)
+#define SETUP_TYPE_MAX			(SETUP_ENUM_MAX | SETUP_INDIRECT)
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK	0x07FF
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index c63974e..b9bdb40 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -18,6 +18,7 @@
 #include <linux/mm.h>
 #include <linux/efi.h>
 #include <linux/verification.h>
+#include <linux/random.h>
 
 #include <asm/bootparam.h>
 #include <asm/setup.h>
@@ -110,6 +111,26 @@ static int setup_e820_entries(struct boot_params *params)
 	return 0;
 }
 
+enum { RNG_SEED_LENGTH = 32 };
+
+static void
+setup_rng_seed(struct boot_params *params, unsigned long params_load_addr,
+	       unsigned int rng_seed_setup_data_offset)
+{
+	struct setup_data *sd = (void *)params + rng_seed_setup_data_offset;
+	unsigned long setup_data_phys;
+
+	if (!rng_is_initialized())
+		return;
+
+	sd->type = SETUP_RNG_SEED;
+	sd->len = RNG_SEED_LENGTH;
+	get_random_bytes(sd->data, RNG_SEED_LENGTH);
+	setup_data_phys = params_load_addr + rng_seed_setup_data_offset;
+	sd->next = params->hdr.setup_data;
+	params->hdr.setup_data = setup_data_phys;
+}
+
 #ifdef CONFIG_EFI
 static int setup_efi_info_memmap(struct boot_params *params,
 				  unsigned long params_load_addr,
@@ -277,9 +298,16 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params,
 			sizeof(struct efi_setup_data);
 #endif
 
-	/* Setup IMA log buffer state */
-	setup_ima_state(image, params, params_load_addr,
-			setup_data_offset);
+	if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
+		/* Setup IMA log buffer state */
+		setup_ima_state(image, params, params_load_addr,
+				setup_data_offset);
+		setup_data_offset += sizeof(struct setup_data) +
+				     sizeof(struct ima_setup_data);
+	}
+
+	/* Setup RNG seed */
+	setup_rng_seed(params, params_load_addr, setup_data_offset);
 
 	/* Setup EDD info */
 	memcpy(params->eddbuf, boot_params.eddbuf,
@@ -435,7 +463,9 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
 	params_cmdline_sz = ALIGN(params_cmdline_sz, 16);
 	kbuf.bufsz = params_cmdline_sz + ALIGN(efi_map_sz, 16) +
 				sizeof(struct setup_data) +
-				sizeof(struct efi_setup_data);
+				sizeof(struct efi_setup_data) +
+				sizeof(struct setup_data) +
+				RNG_SEED_LENGTH;
 
 	if (IS_ENABLED(CONFIG_IMA_KEXEC))
 		kbuf.bufsz += sizeof(struct setup_data) +
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 53f863f..216fee7 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -24,6 +24,7 @@
 #include <linux/usb/xhci-dbgp.h>
 #include <linux/static_call.h>
 #include <linux/swiotlb.h>
+#include <linux/random.h>
 
 #include <uapi/linux/mount.h>
 
@@ -418,6 +419,15 @@ static void __init parse_setup_data(void)
 		case SETUP_IMA:
 			add_early_ima_buffer(pa_data);
 			break;
+		case SETUP_RNG_SEED:
+			data = early_memremap(pa_data, data_len);
+			add_bootloader_randomness(data->data, data->len);
+			/* Zero seed for forward secrecy. */
+			memzero_explicit(data->data, data->len);
+			/* Zero length in case we find ourselves back here by accident. */
+			memzero_explicit(&data->len, sizeof(data->len));
+			early_memunmap(data, data_len);
+			break;
 		default:
 			break;
 		}

^ permalink raw reply related	[flat|nested] 29+ messages in thread

end of thread, other threads:[~2022-07-11 10:28 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-30 11:33 [PATCH] x86/setup: Allow passing RNG seeds via e820 setup table Jason A. Donenfeld
2022-06-30 11:59 ` [PATCH v2] " Jason A. Donenfeld
2022-06-30 12:09   ` [PATCH v3] " Jason A. Donenfeld
2022-06-30 13:31     ` [PATCH v4] " Jason A. Donenfeld
2022-07-01 17:58       ` [PATCH v5] " Jason A. Donenfeld
2022-07-01 18:25         ` H. Peter Anvin
2022-07-01 18:42           ` Jason A. Donenfeld
2022-07-01 18:52             ` H. Peter Anvin
2022-07-01 18:53               ` Jason A. Donenfeld
2022-07-03  0:44                 ` [PATCH v6] x86/setup: Use rng seeds from setup_data Jason A. Donenfeld
2022-07-07  0:08                   ` [PATCH v7] " Jason A. Donenfeld
2022-07-08 11:39                     ` [PATCH tip v8] " Jason A. Donenfeld
2022-07-09  1:51                       ` H. Peter Anvin
2022-07-09  9:43                         ` Jason A. Donenfeld
2022-07-09  9:48                           ` [PATCH tip v9] " Jason A. Donenfeld
2022-07-09 22:42                             ` H. Peter Anvin
2022-07-09 23:23                               ` Jason A. Donenfeld
2022-07-09  9:49                         ` [PATCH tip v8] " Borislav Petkov
2022-07-09  9:53                           ` Jason A. Donenfeld
2022-07-09 10:21                           ` Borislav Petkov
2022-07-09 21:45                           ` H. Peter Anvin
2022-07-09 21:57                             ` Borislav Petkov
2022-07-09 22:41                               ` H. Peter Anvin
2022-07-10  9:45                                 ` Borislav Petkov
2022-07-10 11:11                                   ` Jason A. Donenfeld
2022-07-10 12:27                                     ` Borislav Petkov
2022-07-10 17:13                                       ` Jason A. Donenfeld
2022-07-10 17:29                                         ` [PATCH tip v10] " Jason A. Donenfeld
2022-07-11  9:39 ` [tip: x86/kdump] " tip-bot2 for Jason A. Donenfeld

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.