On Mon, Sep 19, 2022 at 6:09 PM Ard Biesheuvel <ardb@xxxxxxxxxx> wrote: > > Instead of blindly creating the EFI random seed configuration table if > the RNG protocol is implemented and works, check whether such a EFI > configuration table was provided by an earlier boot stage and if so, > combine its contents with a Linux specific personalization string, and > if available, mix in the output of the RNG protocol as well. > > This can be used for, e.g., systemd-boot, to pass an additional seed to > Linux in a way that can be consumed by the kernel very early. In that > case, the following definitions should be used to pass the seed to the > EFI stub: > > struct linux_efi_random_seed { > u32 size; // of the 'seed' array in bytes > u8 seed[]; > }; > > The memory for the struct must be allocated as EFI_ACPI_RECLAIM_MEMORY > pool memory, and the address of the struct in memory should be installed > as a EFI configuration table using the following GUID: > > LINUX_EFI_RANDOM_SEED_TABLE_GUID 1ce1e5bc-7ceb-42f2-81e5-8aadf180f57b > > Note that doing so is safe even on kernels that were built without this > patch applied, but the seed will simply be overwritten with a seed > derived from the EFI RNG protocol, if available. The recommended seed > size is 32 bytes, anything beyond that is mixed in but not reflected in > the final seed size. > > Suggested-by: "Jason A. Donenfeld" <Jason@xxxxxxxxx> > Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx> > --- > drivers/firmware/efi/libstub/Makefile | 4 + > drivers/firmware/efi/libstub/efistub.h | 2 + > drivers/firmware/efi/libstub/random.c | 79 ++++++++++++-------- > include/linux/efi.h | 2 - > lib/crypto/blake2s-generic.c | 2 + > lib/crypto/blake2s.c | 7 +- > 6 files changed, 60 insertions(+), 36 deletions(-) > > diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile > index d0537573501e..3b3c67001566 100644 > --- a/drivers/firmware/efi/libstub/Makefile > +++ b/drivers/firmware/efi/libstub/Makefile > @@ -55,6 +55,7 @@ KCOV_INSTRUMENT := n > lib-y := efi-stub-helper.o gop.o secureboot.o tpm.o \ > file.o mem.o random.o randomalloc.o pci.o \ > skip_spaces.o lib-cmdline.o lib-ctype.o \ > + libcrypto-blake2s.o libcrypto-blake2s-generic.o \ > alignedmem.o relocate.o vsprintf.o > > # include the stub's generic dependencies from lib/ when building for ARM/arm64 > @@ -63,6 +64,9 @@ efi-deps-y := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c > $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE > $(call if_changed_rule,cc_o_c) > > +$(obj)/libcrypto-%.o: $(srctree)/lib/crypto/%.c FORCE > + $(call if_changed_rule,cc_o_c) > + > lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o fdt.o string.o \ > $(patsubst %.c,lib-%.o,$(efi-deps-y)) > > diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h > index b0ae0a454404..fc32897de5e8 100644 > --- a/drivers/firmware/efi/libstub/efistub.h > +++ b/drivers/firmware/efi/libstub/efistub.h > @@ -873,6 +873,8 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out); > efi_status_t efi_random_alloc(unsigned long size, unsigned long align, > unsigned long *addr, unsigned long random_seed); > > +void efi_random_get_seed(void); > + > efi_status_t check_platform_features(void); > > void *get_efi_config_table(efi_guid_t guid); > diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c > index 183dc5cdb8ed..87fcd73ef615 100644 > --- a/drivers/firmware/efi/libstub/random.c > +++ b/drivers/firmware/efi/libstub/random.c > @@ -5,6 +5,7 @@ > > #include <linux/efi.h> > #include <asm/efi.h> > +#include <crypto/blake2s.h> > > #include "efistub.h" > > @@ -49,60 +50,74 @@ efi_status_t efi_get_random_bytes(unsigned long size, u8 *out) > return efi_call_proto(rng, get_rng, NULL, size, out); > } > > +static char const pstr[] = "Linux EFI Stub RNG Seed Label v1"; > + > /** > * efi_random_get_seed() - provide random seed as configuration table > * > * The EFI_RNG_PROTOCOL is used to read random bytes. These random bytes are > * saved as a configuration table which can be used as entropy by the kernel > * for the initialization of its pseudo random number generator. > - * > - * If the EFI_RNG_PROTOCOL is not available or there are not enough random bytes > - * available, the configuration table will not be installed and an error code > - * will be returned. > - * > - * Return: status code > */ > -efi_status_t efi_random_get_seed(void) > +void efi_random_get_seed(void) > { > efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID; > efi_guid_t rng_algo_raw = EFI_RNG_ALGORITHM_RAW; > efi_guid_t rng_table_guid = LINUX_EFI_RANDOM_SEED_TABLE_GUID; > efi_rng_protocol_t *rng = NULL; > struct linux_efi_random_seed *seed = NULL; > + struct blake2s_state state; > + unsigned int total_len = 0; > efi_status_t status; > > - status = efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng); > - if (status != EFI_SUCCESS) > - return status; > + // grab the EFI RNG protocol, if it exists > + efi_bs_call(locate_protocol, &rng_proto, NULL, (void **)&rng); > > - status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, > - sizeof(*seed) + EFI_RANDOM_SEED_SIZE, > - (void **)&seed); > - if (status != EFI_SUCCESS) > - return status; > + // grab the seed provided by the previous boot stages > + seed = get_efi_config_table(LINUX_EFI_RANDOM_SEED_TABLE_GUID); > + > + // if neither exists, there is little we can do > + if (!seed && !rng) > + return; > + > + blake2s_init(&state, EFI_RANDOM_SEED_SIZE); > + blake2s_update(&state, pstr, sizeof(pstr) - 1); > + > + if (seed) { > + blake2s_update(&state, (void *)&seed->size, sizeof(seed->size)); > + blake2s_update(&state, seed->bits, seed->size); Since this is never freed, and also just for hygiene, add: memzero_explicit(seed, sizeof(seed));