From 00afd1ec82161aa7702d184fc6acdad256c44c82 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 18 Jun 2024 14:06:06 -0700 Subject: [PATCH 1/4] Add fdt_kaslrseed function to add kaslr-seed to chosen node If RANDOMIZE_BASE is enabled in the Linux kernel instructing it to randomize the virtual address at which the kernel image is loaded, it expects entropy to be provided by the bootloader by populating /chosen/kaslr-seed with a 64-bit value from source of entropy at boot. Add a fdt_kaslrseed function to accommodate this allowing an existing node to be overwritten if present. For now use the first rng device but it would be good to enhance this in the future to allow some sort of selection or policy in choosing the rng device used. Signed-off-by: Tim Harvey Reviewed-by: Simon Glass Cc: Michal Simek Cc: Andy Yan Cc: Akash Gajjar Cc: Ilias Apalodimas Cc: Simon Glass Cc: Patrick Delaunay Cc: Patrice Chotard Cc: Devarsh Thakkar Cc: Heinrich Schuchardt Cc: Hugo Villeneuve Cc: Marek Vasut Cc: Tom Rini Cc: Chris Morgan Reviewed-by: Caleb Connolly --- boot/fdt_support.c | 44 +++++++++++++++++++++++++++++++++++++++++++ include/fdt_support.h | 10 ++++++++++ 2 files changed, 54 insertions(+) diff --git a/boot/fdt_support.c b/boot/fdt_support.c index 2bd80a9dfb1..b1b2679dea0 100644 --- a/boot/fdt_support.c +++ b/boot/fdt_support.c @@ -7,12 +7,15 @@ */ #include +#include #include #include #include #include #include +#include #include +#include #include #include #include @@ -274,6 +277,47 @@ int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end) return 0; } +int fdt_kaslrseed(void *fdt, bool overwrite) +{ + int len, err, nodeoffset; + struct udevice *dev; + const u64 *orig; + u64 data = 0; + + err = fdt_check_header(fdt); + if (err < 0) + return err; + + /* find or create "/chosen" node. */ + nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen"); + if (nodeoffset < 0) + return nodeoffset; + + /* return without error if we are not overwriting and existing non-zero node */ + orig = fdt_getprop(fdt, nodeoffset, "kaslr-seed", &len); + if (orig && len == sizeof(*orig)) + data = fdt64_to_cpu(*orig); + if (data && !overwrite) { + debug("not overwriting existing kaslr-seed\n"); + return 0; + } + err = uclass_get_device(UCLASS_RNG, 0, &dev); + if (err) { + printf("No RNG device\n"); + return err; + } + err = dm_rng_read(dev, &data, sizeof(data)); + if (err) { + dev_err(dev, "dm_rng_read failed: %d\n", err); + return err; + } + err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", &data, sizeof(data)); + if (err < 0) + printf("WARNING: could not set kaslr-seed %s.\n", fdt_strerror(err)); + + return err; +} + /** * board_fdt_chosen_bootargs - boards may override this function to use * alternative kernel command line arguments diff --git a/include/fdt_support.h b/include/fdt_support.h index 4b71b8948d9..741e2360c22 100644 --- a/include/fdt_support.h +++ b/include/fdt_support.h @@ -463,4 +463,14 @@ void fdt_fixup_board_enet(void *blob); #ifdef CONFIG_CMD_PSTORE void fdt_fixup_pstore(void *blob); #endif + +/** + * fdt_kaslrseed() - create a 'kaslr-seed' node in chosen + * + * @blob: fdt blob + * @overwrite: do not overwrite existing non-zero node unless true + * Return: 0 if OK, -ve on error + */ +int fdt_kaslrseed(void *blob, bool overwrite); + #endif /* ifndef __FDT_SUPPORT_H */ From ea955eea4f662b7e37d74228fed0c9147e6dba88 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 18 Jun 2024 14:06:07 -0700 Subject: [PATCH 2/4] fdt: automatically add /chosen/kaslr-seed if DM_RNG is enabled If RANDOMIZE_BASE is enabled in the Linux kernel instructing it to randomize the virtual address at which the kernel image is loaded, it expects entropy to be provided by the bootloader by populating /chosen/kaslr-seed with a 64-bit value from source of entropy at boot. If we have DM_RNG enabled populate this value automatically when fdt_chosen is called. We skip this if ARMV8_SEC_FIRMWARE_SUPPORT is enabled as its implementation uses a different source of entropy that is not yet implemented as DM_RNG. We also skip this if MEASURED_BOOT is enabled as in that case any modifications to the dt will cause measured boot to fail (although there are many other places the dt is altered). Note that the Kernel's EFI STUB only relies on EFI_RNG_PROTOCOL for randomization and completely ignores the kaslr-seed for its own randomness needs (i.e the randomization of the physical placement of the kernel). It gets weeded out from the DTB that gets handed over via efi_install_fdt() as it would also mess up the measured boot DTB TPM measurements as well. Signed-off-by: Tim Harvey Reviewed-by: Simon Glass Cc: Michal Simek Cc: Andy Yan Cc: Akash Gajjar Cc: Ilias Apalodimas Cc: Simon Glass Cc: Patrick Delaunay Cc: Patrice Chotard Cc: Devarsh Thakkar Cc: Heinrich Schuchardt Cc: Hugo Villeneuve Cc: Marek Vasut Cc: Tom Rini Cc: Chris Morgan --- boot/fdt_support.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/boot/fdt_support.c b/boot/fdt_support.c index b1b2679dea0..4559adcd5e2 100644 --- a/boot/fdt_support.c +++ b/boot/fdt_support.c @@ -345,6 +345,15 @@ int fdt_chosen(void *fdt) if (nodeoffset < 0) return nodeoffset; + /* if DM_RNG enabled automatically inject kaslr-seed node unless: + * CONFIG_MEASURED_BOOT enabled: as dt modifications break measured boot + * CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT enabled: as that implementation does not use dm yet + */ + if (IS_ENABLED(CONFIG_DM_RNG) && + !IS_ENABLED(CONFIG_MEASURED_BOOT) && + !IS_ENABLED(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)) + fdt_kaslrseed(fdt, false); + if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) { err = fdt_setprop(fdt, nodeoffset, "rng-seed", abuf_data(&buf), abuf_size(&buf)); From 909321bc6b527d2464c24e94185a3585c105f5f7 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 18 Jun 2024 14:06:08 -0700 Subject: [PATCH 3/4] use fdt_kaslrseed function to de-duplicate code Use the fdt_kaslrseed function to deduplicate code doing the same thing. Note that the kalsrseed command (CMD_KASLRSEED) is likely pointless now but left in place in case boot scripts exist that rely on this command existing and returning success. An informational message is printed to alert users of this command that it is likely no longer needed. Note that the Kernel's EFI STUB only relies on EFI_RNG_PROTOCOL for randomization and completely ignores the kaslr-seed for its own randomness needs (i.e the randomization of the physical placement of the kernel). It gets weeded out from the DTB that gets handed over via efi_install_fdt() as it would also mess up the measured boot DTB TPM measurements as well. Signed-off-by: Tim Harvey Reviewed-by: Simon Glass Cc: Michal Simek Cc: Andy Yan Cc: Akash Gajjar Cc: Ilias Apalodimas Cc: Simon Glass Cc: Patrick Delaunay Cc: Patrice Chotard Cc: Devarsh Thakkar Cc: Heinrich Schuchardt Cc: Hugo Villeneuve Cc: Marek Vasut Cc: Tom Rini Cc: Chris Morgan Acked-by: Michal Simek --- board/xilinx/common/board.c | 40 ------------------------------ boot/pxe_utils.c | 34 +------------------------ cmd/kaslrseed.c | 49 ++++++------------------------------- 3 files changed, 8 insertions(+), 115 deletions(-) diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index b47d2d23f91..098738017ba 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -702,11 +702,6 @@ phys_addr_t board_get_usable_ram_top(phys_size_t total_size) #define MAX_RAND_SIZE 8 int ft_board_setup(void *blob, struct bd_info *bd) { - size_t n = MAX_RAND_SIZE; - struct udevice *dev; - u8 buf[MAX_RAND_SIZE]; - int nodeoffset, ret; - static const struct node_info nodes[] = { { "arm,pl353-nand-r2p1", MTD_DEV_TYPE_NAND, }, }; @@ -714,41 +709,6 @@ int ft_board_setup(void *blob, struct bd_info *bd) if (IS_ENABLED(CONFIG_FDT_FIXUP_PARTITIONS) && IS_ENABLED(CONFIG_NAND_ZYNQ)) fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes)); - if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) { - debug("No RNG device\n"); - return 0; - } - - if (dm_rng_read(dev, buf, n)) { - debug("Reading RNG failed\n"); - return 0; - } - - if (!blob) { - debug("No FDT memory address configured. Please configure\n" - "the FDT address via \"fdt addr
\" command.\n" - "Aborting!\n"); - return 0; - } - - ret = fdt_check_header(blob); - if (ret < 0) { - debug("fdt_chosen: %s\n", fdt_strerror(ret)); - return ret; - } - - nodeoffset = fdt_find_or_add_subnode(blob, 0, "chosen"); - if (nodeoffset < 0) { - debug("Reading chosen node failed\n"); - return nodeoffset; - } - - ret = fdt_setprop(blob, nodeoffset, "kaslr-seed", buf, sizeof(buf)); - if (ret < 0) { - debug("Unable to set kaslr-seed on chosen node: %s\n", fdt_strerror(ret)); - return ret; - } - return 0; } #endif diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 5c1c962ff4c..38ca9b81a42 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -324,10 +324,6 @@ static void label_boot_kaslrseed(void) #if CONFIG_IS_ENABLED(DM_RNG) ulong fdt_addr; struct fdt_header *working_fdt; - size_t n = 0x8; - struct udevice *dev; - u64 *buf; - int nodeoffset; int err; /* Get the main fdt and map it */ @@ -343,35 +339,7 @@ static void label_boot_kaslrseed(void) if (err <= 0) return; - if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) { - printf("No RNG device\n"); - return; - } - - nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen"); - if (nodeoffset < 0) { - printf("Reading chosen node failed\n"); - return; - } - - buf = malloc(n); - if (!buf) { - printf("Out of memory\n"); - return; - } - - if (dm_rng_read(dev, buf, n)) { - printf("Reading RNG failed\n"); - goto err; - } - - err = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, sizeof(buf)); - if (err < 0) { - printf("Unable to set kaslr-seed on chosen node: %s\n", fdt_strerror(err)); - goto err; - } -err: - free(buf); + fdt_kaslrseed(working_fdt, true); #endif return; } diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c index 9acb8e16386..645cab2e74f 100644 --- a/cmd/kaslrseed.c +++ b/cmd/kaslrseed.c @@ -16,56 +16,21 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - size_t n = 0x8; - struct udevice *dev; - u64 *buf; - int nodeoffset; - int ret = CMD_RET_SUCCESS; + int err = CMD_RET_SUCCESS; - if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) { - printf("No RNG device\n"); - return CMD_RET_FAILURE; - } - - buf = malloc(n); - if (!buf) { - printf("Out of memory\n"); - return CMD_RET_FAILURE; - } - - if (dm_rng_read(dev, buf, n)) { - printf("Reading RNG failed\n"); - return CMD_RET_FAILURE; - } + printf("Notice: a /chosen/kaslr-seed is automatically added to the device-tree when booted via booti/bootm/bootz therefore using this command is likely no longer needed\n"); if (!working_fdt) { printf("No FDT memory address configured. Please configure\n" "the FDT address via \"fdt addr
\" command.\n" "Aborting!\n"); - return CMD_RET_FAILURE; - } - - ret = fdt_check_header(working_fdt); - if (ret < 0) { - printf("fdt_chosen: %s\n", fdt_strerror(ret)); - return CMD_RET_FAILURE; - } - - nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen"); - if (nodeoffset < 0) { - printf("Reading chosen node failed\n"); - return CMD_RET_FAILURE; + err = CMD_RET_FAILURE; + } else { + if (fdt_kaslrseed(working_fdt, true) < 0) + err = CMD_RET_FAILURE; } - ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, sizeof(buf)); - if (ret < 0) { - printf("Unable to set kaslr-seed on chosen node: %s\n", fdt_strerror(ret)); - return CMD_RET_FAILURE; - } - - free(buf); - - return ret; + return cmd_process_error(cmdtp, err); } U_BOOT_LONGHELP(kaslrseed, From f485a9966112ea8db9a8568adabf606f0f34e010 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 18 Jun 2024 14:06:09 -0700 Subject: [PATCH 4/4] test: cmd: fdt: fix chosen test for DM_RNG Now that kaslr-seed is automatically added to the chosen node if DM_RNG is enabled, adjust the test to expect this. Take care not to expect kaslr-seed for CONFIG_MEASURED_BOOT and CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT as we do not add it for those. Signed-off-by: Tim Harvey Cc: Michal Simek Cc: Andy Yan Cc: Akash Gajjar Cc: Ilias Apalodimas Cc: Simon Glass Cc: Patrick Delaunay Cc: Patrice Chotard Cc: Devarsh Thakkar Cc: Heinrich Schuchardt Cc: Hugo Villeneuve Cc: Marek Vasut Cc: Tom Rini Cc: Chris Morgan --- test/cmd/fdt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/cmd/fdt.c b/test/cmd/fdt.c index 54708552175..5cda1ef382a 100644 --- a/test/cmd/fdt.c +++ b/test/cmd/fdt.c @@ -1347,6 +1347,10 @@ static int fdt_test_chosen(struct unit_test_state *uts) ut_assert_nextlinen("\tu-boot,version = "); /* Ignore the version string */ if (env_bootargs) ut_assert_nextline("\tbootargs = \"%s\";", env_bootargs); + if (IS_ENABLED(CONFIG_DM_RNG) && + !IS_ENABLED(CONFIG_MEASURED_BOOT) && + !IS_ENABLED(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)) + ut_assert_nextlinen("\tkaslr-seed = "); ut_assert_nextline("};"); ut_assertok(ut_check_console_end(uts)); @@ -1363,6 +1367,10 @@ static int fdt_test_chosen(struct unit_test_state *uts) ut_assert_nextlinen("\tu-boot,version = "); /* Ignore the version string */ if (env_bootargs) ut_assert_nextline("\tbootargs = \"%s\";", env_bootargs); + if (IS_ENABLED(CONFIG_DM_RNG) && + !IS_ENABLED(CONFIG_MEASURED_BOOT) && + !IS_ENABLED(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)) + ut_assert_nextlinen("\tkaslr-seed = "); ut_assert_nextline("};"); ut_assertok(ut_check_console_end(uts));