[PATCH] fdt_support: add optional board_rng_seed() hook
Simon Glass
sjg at chromium.org
Tue Aug 23 15:38:16 CEST 2022
?Hi,
On Mon, 22 Aug 2022 at 01:34, Rasmus Villemoes
<rasmus.villemoes at prevas.dk> wrote:
>
> A recurring theme on LKML is the boot process deadlocking due to some
> process blocking waiting for random numbers, while the kernel's
> Cryptographic Random Number Generator (crng) is not initalized yet,
> but that very blocking means no activity happens that would generate
> the entropy necessary to finalize seeding the crng.
>
> This is not a problem on boards that have a good hwrng (when the
> kernel is configured to trust it), whether in the CPU or in a TPM or
> elsewhere. However, that's far from all boards out there. Moreover,
> there are consumers in the kernel that try to obtain random numbers
> very early, before the kernel has had any chance to initialize any
> hwrng or other peripherals.
>
> Allow a board to provide a board_rng_seed() function, which is
> responsible for providing a value to be put into the rng-seed property
> under the /chosen node.
>
> The board code is responsible for how to actually obtain those
> bytes.
>
> - One possibility is for the board to load a seed "file" from
> somewhere (it need not be a file in a filesystem of course), and
> then ensure that that the same seed file does not get used on
> subsequent boots.
>
> * One way to do that is to delete the file, or otherwise mark it as
> invalid, then rely on userspace to create a new one, and living
> with the possibility of not finding a seed file during some boots.
>
> * Another is to use the scheme used by systemd-boot and create a new
> seed file immediately, but in a way that the seed passed to the
> kernel and the new (i.e. next) seed cannot be deduced from each
> other, see the explanation at
> https://lore.kernel.org/lkml/20190929090512.GB13049@gardel-login/
> and the current code at
> https://github.com/systemd/systemd/blob/main/src/boot/efi/random-seed.c
>
> - The board may have an hwrng from which some bytes can be read; while
> the kernel can also do that, doing it in U-Boot and providing a seed
> ensures that even very early users in the kernel get good random
> numbers.
>
> - If the board has a sensor of some sort (temperature, humidity, GPS,
> RTC, whatever), mixing in a reading of that doesn't hurt.
>
> - etc. etc.
>
> These can of course be combined.
>
> The rng-seed property is mixed into the pool used by the linux
> kernel's CRNG very early during boot. Whether it then actually
> contributes towards the kernel considering the CRNG initialized
> depends on whether the kernel has been configured with
> CONFIG_RANDOM_TRUST_BOOTLOADER (nowadays overridable via the
> random.trust_bootloader command line option). But that's for the BSP
> developer to ultimately decide.
>
> So, if the board needs to have all that logic, why not also just have
> it do the actual population of /chosen/rng-seed in ft_board_setup(),
> which is not that many extra lines of code?
>
> I considered that, but decided handling this logically belongs in
> fdt_chosen(). Also, apart from saving the board code from the few
> lines of boilerplate, doing it in ft_board_setup() is too late for at
> least some use cases. For example, I want to allow the board logic to
> decide
>
> ok, let's pass back this buffer and use that as seed, but also let's
> set random.trust_bootloader=n so no entropy is credited.
>
> This requires the rng-seed handling to happen before bootargs
> handling. For example, during the very first boot, the board might not
> have a proper seed file, but the board could still return (a hash of)
> some CPU serial# or whatnot, so that at least no two boards ever get
> the same seed - the kernel always mixes in the value passed in
> rng-seed, but if it is not "trusted", the kernel would still go
> through the same motions as it would if no rng-seed was passed before
> considering its CRNG initialized. I.e., by returning that
> unique-to-this-board value and setting random.trust_bootloader=n, the
> board would be no worse off than if board_rng_seed() returned nothing
> at all.
>
> Signed-off-by: Rasmus Villemoes <rasmus.villemoes at prevas.dk>
> ---
> common/Kconfig | 14 ++++++++++++++
> common/fdt_support.c | 13 +++++++++++++
> include/fdt_support.h | 13 +++++++++++++
> 3 files changed, 40 insertions(+)
>
> diff --git a/common/Kconfig b/common/Kconfig
> index e7914ca750..ebee856e56 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -768,6 +768,20 @@ config TPL_STACKPROTECTOR
> bool "Stack Protector buffer overflow detection for TPL"
> depends on STACKPROTECTOR && TPL
>
> +config BOARD_RNG_SEED
> + bool "Provide /chosen/rng-seed property to the linux kernel"
> + help
> + Selecting this option requires the board to define a
> + board_rng_seed() function, which should return a buffer
> + which will be used to populate the /chosen/rng-seed property
> + in the device tree for the OS being booted.
> +
> + It is up to the board code (and more generally the whole
> + BSP) where and how to store (or generate) such a seed, how
> + to ensure a given seed is only used once, how to create a
> + new seed for use on subsequent boots, and whether or not the
> + kernel should account any entropy from the given seed.
> +
> endmenu
>
> menu "Update support"
> diff --git a/common/fdt_support.c b/common/fdt_support.c
> index 8c18af2ce1..baf7fb7065 100644
> --- a/common/fdt_support.c
> +++ b/common/fdt_support.c
> @@ -7,6 +7,7 @@
> */
>
> #include <common.h>
> +#include <abuf.h>
> #include <env.h>
> #include <log.h>
> #include <mapmem.h>
> @@ -279,6 +280,7 @@ __weak char *board_fdt_chosen_bootargs(void)
>
> int fdt_chosen(void *fdt)
> {
> + struct abuf buf = {};
> int nodeoffset;
> int err;
> char *str; /* used to set string properties */
> @@ -294,6 +296,17 @@ int fdt_chosen(void *fdt)
> if (nodeoffset < 0)
> return nodeoffset;
>
> + if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) {
> + err = fdt_setprop(fdt, nodeoffset, "rng-seed",
> + abuf_data(&buf), abuf_size(&buf));
> + abuf_uninit(&buf);
> + if (err < 0) {
> + printf("WARNING: could not set rng-seed %s.\n",
> + fdt_strerror(err));
> + return err;
> + }
> + }
> +
> str = board_fdt_chosen_bootargs();
>
> if (str) {
> diff --git a/include/fdt_support.h b/include/fdt_support.h
> index ac76939e81..b8380716f3 100644
> --- a/include/fdt_support.h
> +++ b/include/fdt_support.h
> @@ -11,6 +11,7 @@
>
> #include <asm/u-boot.h>
> #include <linux/libfdt.h>
> +#include <abuf.h>
>
> /**
> * arch_fixup_fdt() - Write arch-specific information to fdt
> @@ -186,6 +187,18 @@ int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name);
> */
> int ft_board_setup(void *blob, struct bd_info *bd);
>
> +/**
> + * board_rng_seed() - Provide a seed to be passed via /chosen/rng-seed
> + *
> + * This function is called if CONFIG_BOARD_RNG_SEED is set, and must
> + * be provided by the board. It should return, via @buf, some suitable
> + * seed value to pass to the kernel.
> + *
> + * @param buf A struct abuf for returning the seed and its size.
> + * @return 0 if ok, negative on error.
> + */
> +int board_rng_seed(struct abuf *buf);
Instead of yet another hook, can we use EVT_FT_FIXUP? An even better
option might be to use EVT_FT_FIXUP and then call a UCLASS_BOARD
method to obtain the information.
> +
> /**
> * board_fdt_chosen_bootargs() - Arbitrarily amend fdt kernel command line
> *
> --
> 2.31.1
>
Regards,
Simon
More information about the U-Boot
mailing list