Merge patch series "automatically add /chosen/kaslr-seed and deduplicate code"

Tim Harvey <tharvey@gateworks.com> says:

This series will automatically add /chosen/kaslr-seed to the dt if
DM_RNG is enabled
during the boot process.

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).

As this fdt node is added elsewhere create a library function and
use it to deduplicate code. We will provide a parameter to overwrite
the node if present.

For our automatic injection, we will use the first rng device and
not overwrite if already present with a non-zero value (which may
have been populated by an earlier boot stage). This way if a board
specific ft_board_setup() function wants to customize this behavior
it can call fdt_kaslrseed with a rng device index of its choosing and
set overwrite true.

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.
This commit is contained in:
Tom Rini 2024-06-28 17:31:28 -06:00
commit 48641bfab7
6 changed files with 79 additions and 115 deletions

View File

@ -701,11 +701,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, },
};
@ -713,41 +708,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 <address>\" 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

View File

@ -6,12 +6,15 @@
* Copyright 2010-2011 Freescale Semiconductor, Inc.
*/
#include <dm.h>
#include <abuf.h>
#include <env.h>
#include <log.h>
#include <mapmem.h>
#include <net.h>
#include <rng.h>
#include <stdio_dev.h>
#include <dm/device_compat.h>
#include <dm/ofnode.h>
#include <linux/ctype.h>
#include <linux/types.h>
@ -273,6 +276,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
@ -300,6 +344,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));

View File

@ -325,10 +325,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 */
@ -344,35 +340,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;
}

View File

@ -15,56 +15,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 <address>\" command.\n"
"Aborting!\n");
return CMD_RET_FAILURE;
err = CMD_RET_FAILURE;
} else {
if (fdt_kaslrseed(working_fdt, true) < 0)
err = 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;
}
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,

View File

@ -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 */

View File

@ -1346,6 +1346,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));
@ -1362,6 +1366,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));