Module Name:    src
Committed By:   riastradh
Date:           Wed Dec 18 21:46:03 UTC 2019

Modified Files:
        src/sys/arch/evbarm/fdt: fdt_machdep.c
        src/sys/stand/efiboot: boot.c efiboot.h efifdt.c efifdt.h exec.c
            version

Log Message:
Implement rndseed support in efiboot and fdt arm.

The EFI environment variable `rndseed' specifies the path to the
random seed.  It is loaded only for fdt platforms at the moment.

Since the rndseed (an rndsave_t object as defined in <sys/rndio.h>)
is 536 bytes long (for hysterical raisins), and to avoid having to
erase parts of the fdt tree, we load it into a physical page whose
address is passed in the fdt tree, rather than passing the content of
the file as an fdt node directly; the kernel then reserves the page
from uvm, and maps it into kva to call rnd_seed.

For now, the only kernel that does use efiboot with fdt is evbarm,
which knows to handle the rndseed.  Any new kernels that use efiboot
with fdt must do the same; otherwise uvm may hand out the page with
the secret key on it for a normal page allocation in the kernel --
which should be OK if there are no kernel memory disclosure bugs, but
would lead to worse consequences than simply loading the seed late in
userland with /etc/rc.d/random_seed otherwise.

ok jmcneill


To generate a diff of this commit:
cvs rdiff -u -r1.64 -r1.65 src/sys/arch/evbarm/fdt/fdt_machdep.c
cvs rdiff -u -r1.18 -r1.19 src/sys/stand/efiboot/boot.c
cvs rdiff -u -r1.10 -r1.11 src/sys/stand/efiboot/efiboot.h
cvs rdiff -u -r1.19 -r1.20 src/sys/stand/efiboot/efifdt.c
cvs rdiff -u -r1.6 -r1.7 src/sys/stand/efiboot/efifdt.h
cvs rdiff -u -r1.11 -r1.12 src/sys/stand/efiboot/exec.c
cvs rdiff -u -r1.13 -r1.14 src/sys/stand/efiboot/version

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/evbarm/fdt/fdt_machdep.c
diff -u src/sys/arch/evbarm/fdt/fdt_machdep.c:1.64 src/sys/arch/evbarm/fdt/fdt_machdep.c:1.65
--- src/sys/arch/evbarm/fdt/fdt_machdep.c:1.64	Tue Jul 16 14:41:45 2019
+++ src/sys/arch/evbarm/fdt/fdt_machdep.c	Wed Dec 18 21:46:03 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: fdt_machdep.c,v 1.64 2019/07/16 14:41:45 skrll Exp $ */
+/* $NetBSD: fdt_machdep.c,v 1.65 2019/12/18 21:46:03 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2015-2017 Jared McNeill <jmcne...@invisible.ca>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.64 2019/07/16 14:41:45 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fdt_machdep.c,v 1.65 2019/12/18 21:46:03 riastradh Exp $");
 
 #include "opt_machdep.h"
 #include "opt_bootconfig.h"
@@ -64,6 +64,7 @@ __KERNEL_RCSID(0, "$NetBSD: fdt_machdep.
 #include <sys/disk.h>
 #include <sys/md5.h>
 #include <sys/pserialize.h>
+#include <sys/rnd.h>
 
 #include <net/if.h>
 #include <net/if_dl.h>
@@ -117,6 +118,7 @@ u_long uboot_args[4] __attribute__((__se
 const uint8_t *fdt_addr_r __attribute__((__section__(".data")));
 
 static uint64_t initrd_start, initrd_end;
+static uint64_t rndseed_start, rndseed_end;
 
 #include <libfdt.h>
 #include <dev/fdt/fdtvar.h>
@@ -311,6 +313,10 @@ fdt_build_bootconfig(uint64_t mem_start,
 	if (initrd_size > 0)
 		fdt_memory_remove_range(initrd_start, initrd_size);
 
+	const uint64_t rndseed_size = rndseed_end - rndseed_start;
+	if (rndseed_size > 0)
+		fdt_memory_remove_range(rndseed_start, rndseed_size);
+
 	const int framebuffer = OF_finddevice("/chosen/framebuffer");
 	if (framebuffer >= 0) {
 		for (index = 0;
@@ -390,6 +396,65 @@ fdt_setup_initrd(void)
 #endif
 }
 
+static void
+fdt_probe_rndseed(uint64_t *pstart, uint64_t *pend)
+{
+	int chosen, len;
+	const void *start_data, *end_data;
+
+	*pstart = *pend = 0;
+	chosen = OF_finddevice("/chosen");
+	if (chosen < 0)
+		return;
+
+	start_data = fdtbus_get_prop(chosen, "netbsd,rndseed-start", &len);
+	end_data = fdtbus_get_prop(chosen, "netbsd,rndseed-end", NULL);
+	if (start_data == NULL || end_data == NULL)
+		return;
+
+	switch (len) {
+	case 4:
+		*pstart = be32dec(start_data);
+		*pend = be32dec(end_data);
+		break;
+	case 8:
+		*pstart = be64dec(start_data);
+		*pend = be64dec(end_data);
+		break;
+	default:
+		printf("Unsupported len %d for /chosen/rndseed-start\n", len);
+		return;
+	}
+}
+
+static void
+fdt_setup_rndseed(void)
+{
+	const uint64_t rndseed_size = rndseed_end - rndseed_start;
+	const paddr_t startpa = trunc_page(rndseed_start);
+	const paddr_t endpa = round_page(rndseed_end);
+	paddr_t pa;
+	vaddr_t va;
+	void *rndseed;
+
+	if (rndseed_size == 0)
+		return;
+
+	va = uvm_km_alloc(kernel_map, endpa - startpa, 0,
+	    UVM_KMF_VAONLY | UVM_KMF_NOWAIT);
+	if (va == 0) {
+		printf("Failed to allocate VA for rndseed\n");
+		return;
+	}
+	rndseed = (void *)va;
+
+	for (pa = startpa; pa < endpa; pa += PAGE_SIZE, va += PAGE_SIZE)
+		pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE, 0);
+	pmap_update(pmap_kernel());
+
+	rnd_seed(rndseed, rndseed_size);
+}
+
 #ifdef EFI_RUNTIME
 static void
 fdt_map_efi_runtime(const char *prop, enum arm_efirt_mem_type type)
@@ -518,6 +583,9 @@ initarm(void *arg)
 	/* Parse ramdisk info */
 	fdt_probe_initrd(&initrd_start, &initrd_end);
 
+	/* Parse rndseed */
+	fdt_probe_rndseed(&rndseed_start, &rndseed_end);
+
 	/*
 	 * Populate bootconfig structure for the benefit of
 	 * dodumpsys
@@ -629,6 +697,13 @@ consinit(void)
 }
 
 void
+cpu_startup_hook(void)
+{
+
+	fdt_setup_rndseed();
+}
+
+void
 delay(u_int us)
 {
 	const struct arm_platform *plat = arm_fdt_platform();

Index: src/sys/stand/efiboot/boot.c
diff -u src/sys/stand/efiboot/boot.c:1.18 src/sys/stand/efiboot/boot.c:1.19
--- src/sys/stand/efiboot/boot.c:1.18	Sun Apr 21 22:30:41 2019
+++ src/sys/stand/efiboot/boot.c	Wed Dec 18 21:46:03 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot.c,v 1.18 2019/04/21 22:30:41 thorpej Exp $	*/
+/*	$NetBSD: boot.c,v 1.19 2019/12/18 21:46:03 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -75,6 +75,7 @@ static char dtb_path[255];
 static char efibootplist_path[255];
 static char netbsd_path[255];
 static char netbsd_args[255];
+static char rndseed_path[255];
 
 #define	DEFTIMEOUT	5
 #define DEFFILENAME	names[0]
@@ -87,6 +88,7 @@ void	command_dev(char *);
 void	command_dtb(char *);
 void	command_plist(char *);
 void	command_initrd(char *);
+void	command_rndseed(char *);
 void	command_ls(char *);
 void	command_mem(char *);
 void	command_printenv(char *);
@@ -103,6 +105,7 @@ const struct boot_command commands[] = {
 	{ "dtb",	command_dtb,		"dtb [dev:][filename]" },
 	{ "plist",	command_plist,		"plist [dev:][filename]" },
 	{ "initrd",	command_initrd,		"initrd [dev:][filename]" },
+	{ "rndseed",	command_rndseed,	"rndseed [dev:][filename]" },
 	{ "ls",		command_ls,		"ls [hdNn:/path]" },
 	{ "mem",	command_mem,		"mem" },
 	{ "printenv",	command_printenv,	"printenv [key]" },
@@ -182,6 +185,12 @@ command_initrd(char *arg)
 }
 
 void
+command_rndseed(char *arg)
+{
+	set_rndseed_path(arg);
+}
+
+void
 command_ls(char *arg)
 {
 	ls(arg);
@@ -348,6 +357,21 @@ char *get_efibootplist_path(void)
 }
 
 int
+set_rndseed_path(const char *arg)
+{
+	if (strlen(arg) + 1 > sizeof(rndseed_path))
+		return ERANGE;
+	strcpy(rndseed_path, arg);
+	return 0;
+}
+
+char *
+get_rndseed_path(void)
+{
+	return rndseed_path;
+}
+
+int
 set_bootfile(const char *arg)
 {
 	if (strlen(arg) + 1 > sizeof(netbsd_path))
@@ -437,6 +461,15 @@ read_env(void)
 		set_bootargs(s);
 		FreePool(s);
 	}
+
+	s = efi_env_get("rndseed");
+	if (s) {
+#ifdef EFIBOOT_DEBUG
+		printf(">> Setting rndseed path to '%s' from environment\n", s);
+#endif
+		set_rndseed_path(s);
+		FreePool(s);
+	}
 }
 
 void

Index: src/sys/stand/efiboot/efiboot.h
diff -u src/sys/stand/efiboot/efiboot.h:1.10 src/sys/stand/efiboot/efiboot.h:1.11
--- src/sys/stand/efiboot/efiboot.h:1.10	Sun Apr 21 22:30:41 2019
+++ src/sys/stand/efiboot/efiboot.h	Wed Dec 18 21:46:03 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: efiboot.h,v 1.10 2019/04/21 22:30:41 thorpej Exp $	*/
+/*	$NetBSD: efiboot.h,v 1.11 2019/12/18 21:46:03 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org>
@@ -64,6 +64,8 @@ int set_dtb_path(const char *);
 char *get_dtb_path(void);
 int set_efibootplist_path(const char *);
 char *get_efibootplist_path(void);
+int set_rndseed_path(const char *);
+char *get_rndseed_path(void);
 
 /* console.c */
 int ischar(void);

Index: src/sys/stand/efiboot/efifdt.c
diff -u src/sys/stand/efiboot/efifdt.c:1.19 src/sys/stand/efiboot/efifdt.c:1.20
--- src/sys/stand/efiboot/efifdt.c:1.19	Fri Aug 30 00:01:33 2019
+++ src/sys/stand/efiboot/efifdt.c	Wed Dec 18 21:46:03 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: efifdt.c,v 1.19 2019/08/30 00:01:33 jmcneill Exp $ */
+/* $NetBSD: efifdt.c,v 1.20 2019/12/18 21:46:03 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2019 Jason R. Thorpe
@@ -383,3 +383,25 @@ efi_fdt_initrd(u_long initrd_addr, u_lon
 	fdt_setprop_u64(fdt_data, chosen, "linux,initrd-start", initrd_addr);
 	fdt_setprop_u64(fdt_data, chosen, "linux,initrd-end", initrd_addr + initrd_size);
 }
+
+void
+efi_fdt_rndseed(u_long rndseed_addr, u_long rndseed_size)
+{
+	int chosen;
+
+	if (rndseed_size == 0)
+		return;
+
+	chosen = fdt_path_offset(fdt_data, FDT_CHOSEN_NODE_PATH);
+	if (chosen < 0)
+		chosen = fdt_add_subnode(fdt_data,
+		    fdt_path_offset(fdt_data, "/"),
+		    FDT_CHOSEN_NODE_NAME);
+	if (chosen < 0)
+		panic("FDT: Failed to create " FDT_CHOSEN_NODE_PATH " node");
+
+	fdt_setprop_u64(fdt_data, chosen, "netbsd,rndseed-start",
+	    rndseed_addr);
+	fdt_setprop_u64(fdt_data, chosen, "netbsd,rndseed-end",
+	    rndseed_addr + rndseed_size);
+}

Index: src/sys/stand/efiboot/efifdt.h
diff -u src/sys/stand/efiboot/efifdt.h:1.6 src/sys/stand/efiboot/efifdt.h:1.7
--- src/sys/stand/efiboot/efifdt.h:1.6	Wed Jul 24 11:40:36 2019
+++ src/sys/stand/efiboot/efifdt.h	Wed Dec 18 21:46:03 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: efifdt.h,v 1.6 2019/07/24 11:40:36 jmcneill Exp $ */
+/* $NetBSD: efifdt.h,v 1.7 2019/12/18 21:46:03 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2018 Jared McNeill <jmcne...@invisible.ca>
@@ -37,5 +37,6 @@ int efi_fdt_overlay_apply(void *, int *)
 void efi_fdt_show(void);
 void efi_fdt_bootargs(const char *);
 void efi_fdt_initrd(u_long, u_long);
+void efi_fdt_rndseed(u_long, u_long);
 void efi_fdt_init(u_long, u_long);
 void efi_fdt_fini(void);

Index: src/sys/stand/efiboot/exec.c
diff -u src/sys/stand/efiboot/exec.c:1.11 src/sys/stand/efiboot/exec.c:1.12
--- src/sys/stand/efiboot/exec.c:1.11	Wed Jul 24 11:40:36 2019
+++ src/sys/stand/efiboot/exec.c	Wed Dec 18 21:46:03 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: exec.c,v 1.11 2019/07/24 11:40:36 jmcneill Exp $ */
+/* $NetBSD: exec.c,v 1.12 2019/12/18 21:46:03 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2019 Jason R. Thorpe
@@ -39,8 +39,8 @@ u_long load_offset = 0;
 #define	FDT_SPACE	(4 * 1024 * 1024)
 #define	FDT_ALIGN	((2 * 1024 * 1024) - 1)
 
-static EFI_PHYSICAL_ADDRESS initrd_addr, dtb_addr;
-static u_long initrd_size = 0, dtb_size = 0;
+static EFI_PHYSICAL_ADDRESS initrd_addr, dtb_addr, rndseed_addr;
+static u_long initrd_size = 0, dtb_size = 0, rndseed_size = 0;
 
 static int
 load_file(const char *path, u_long extra, bool quiet_errors,
@@ -326,9 +326,19 @@ exec_netbsd(const char *fname, const cha
 	}
 
 	if (efi_fdt_size() > 0) {
+		/*
+		 * Load the rndseed as late as possible -- after we
+		 * have committed to using fdt and executing this
+		 * kernel -- so that it doesn't hang around in memory
+		 * if we have to bail or the kernel won't use it.
+		 */
+		load_file(get_rndseed_path(), 0, false,
+		    &rndseed_addr, &rndseed_size);
+
 		efi_fdt_init((marks[MARK_END] + FDT_ALIGN) & ~FDT_ALIGN, FDT_ALIGN + 1);
 		load_fdt_overlays();
 		efi_fdt_initrd(initrd_addr, initrd_size);
+		efi_fdt_rndseed(rndseed_addr, rndseed_size);
 		efi_fdt_bootargs(args);
 #ifdef EFIBOOT_ACPI
 		if (efi_acpi_available())

Index: src/sys/stand/efiboot/version
diff -u src/sys/stand/efiboot/version:1.13 src/sys/stand/efiboot/version:1.14
--- src/sys/stand/efiboot/version:1.13	Sat Nov 30 13:02:18 2019
+++ src/sys/stand/efiboot/version	Wed Dec 18 21:46:03 2019
@@ -1,4 +1,4 @@
-$NetBSD: version,v 1.13 2019/11/30 13:02:18 jmcneill Exp $
+$NetBSD: version,v 1.14 2019/12/18 21:46:03 riastradh Exp $
 
 NOTE ANY CHANGES YOU MAKE TO THE EFI BOOTLOADER HERE.  The format of this
 file is important - make sure the entries are appended on end, last item
@@ -17,3 +17,4 @@ is taken as the current.
 1.10:	Add support for EFI GOP framebuffers in ACPI mode.
 1.11:	Add full UEFI memory map to /chosen node.
 1.12:	Derive ACPI model string from SMBIOS.
+1.13:	Add rndseed support.

Reply via email to