Module Name:    src
Committed By:   tls
Date:           Mon Nov 28 07:56:54 UTC 2011

Modified Files:
        src/share/man/man5: boot.cfg.5
        src/sys/arch/i386/stand/boot: boot2.c
        src/sys/arch/i386/stand/lib: bootmod.h exec.c libi386.h
        src/sys/arch/x86/include: bootinfo.h
        src/sys/arch/x86/x86: x86_machdep.c
        src/sys/dev: rnd.c

Log Message:
Add support for passing saved entropy (random seed file) to the kernel
from the bootloader.  This can fix the problem of poor quality keys
for other kernel modules which call arc4random() early in kernel startup
(NFS startup, in particular, causes this).

We continue to rely on the etc/rc.d/random_seed script to save entropy
to the seed file at shutdown and erase the seed file at startup.

Boot loader support implemented only for i386 and amd64 ports for now but
it should be easy for other ports to do the same or similar.


To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/share/man/man5/boot.cfg.5
cvs rdiff -u -r1.55 -r1.56 src/sys/arch/i386/stand/boot/boot2.c
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/i386/stand/lib/bootmod.h
cvs rdiff -u -r1.48 -r1.49 src/sys/arch/i386/stand/lib/exec.c
cvs rdiff -u -r1.37 -r1.38 src/sys/arch/i386/stand/lib/libi386.h
cvs rdiff -u -r1.18 -r1.19 src/sys/arch/x86/include/bootinfo.h
cvs rdiff -u -r1.56 -r1.57 src/sys/arch/x86/x86/x86_machdep.c
cvs rdiff -u -r1.86 -r1.87 src/sys/dev/rnd.c

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

Modified files:

Index: src/share/man/man5/boot.cfg.5
diff -u src/share/man/man5/boot.cfg.5:1.22 src/share/man/man5/boot.cfg.5:1.23
--- src/share/man/man5/boot.cfg.5:1.22	Thu May 26 04:25:26 2011
+++ src/share/man/man5/boot.cfg.5	Mon Nov 28 07:56:53 2011
@@ -1,4 +1,4 @@
-.\"	$NetBSD: boot.cfg.5,v 1.22 2011/05/26 04:25:26 uebayasi Exp $
+.\"	$NetBSD: boot.cfg.5,v 1.23 2011/11/28 07:56:53 tls Exp $
 .\"
 .\" Copyright (c) 2007 Stephen Borrill
 .\" All rights reserved.
@@ -147,6 +147,15 @@ time limit for the user to choose an opt
 Passes a
 .Xr userconf 4
 command to the kernel at boot time .
+.It Sy rndseed
+Takes the path to a random-seed file as written by the -S flag to
+.Xr rndctl 8
+as an argument.  This file is used to seed the
+kernel entropy pool
+.Xr rnd 9
+very early in kernel startup, so that high quality randomness is
+available to all kernel modules.  This argument should be supplied
+before any "load" commands that may load executable modules.
 .El
 .Sh EXAMPLES
 Here is an example

Index: src/sys/arch/i386/stand/boot/boot2.c
diff -u src/sys/arch/i386/stand/boot/boot2.c:1.55 src/sys/arch/i386/stand/boot/boot2.c:1.56
--- src/sys/arch/i386/stand/boot/boot2.c:1.55	Thu Jun 23 12:07:00 2011
+++ src/sys/arch/i386/stand/boot/boot2.c	Mon Nov 28 07:56:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: boot2.c,v 1.55 2011/06/23 12:07:00 mrg Exp $	*/
+/*	$NetBSD: boot2.c,v 1.56 2011/11/28 07:56:54 tls Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -136,6 +136,7 @@ const struct bootblk_command commands[] 
 	{ "multiboot",	command_multiboot },
 	{ "vesa",	command_vesa },
 	{ "splash",	splash_add },
+	{ "rndseed",	rnd_add },
 	{ "userconf",	userconf_add },
 	{ NULL,		NULL },
 };
@@ -397,6 +398,7 @@ command_help(char *arg)
 	       "load {path_to_module}\n"
 	       "multiboot [xdNx:][filename] [<args>]\n"
 	       "userconf {command}\n"
+	       "rndseed {path_to_rndseed_file}\n"
 	       "help|?\n"
 	       "quit\n");
 }

Index: src/sys/arch/i386/stand/lib/bootmod.h
diff -u src/sys/arch/i386/stand/lib/bootmod.h:1.4 src/sys/arch/i386/stand/lib/bootmod.h:1.5
--- src/sys/arch/i386/stand/lib/bootmod.h:1.4	Sun Feb  6 23:16:05 2011
+++ src/sys/arch/i386/stand/lib/bootmod.h	Mon Nov 28 07:56:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: bootmod.h,v 1.4 2011/02/06 23:16:05 jmcneill Exp $	*/
+/*	$NetBSD: bootmod.h,v 1.5 2011/11/28 07:56:54 tls Exp $	*/
 
 /*-
  * Copyright (c) 2008 Jared D. McNeill <jmcne...@invisible.ca>
@@ -35,6 +35,7 @@ typedef struct boot_module {
 	uint8_t			bm_type;
 #define	BM_TYPE_KMOD		0x00
 #define	BM_TYPE_IMAGE		0x01
+#define BM_TYPE_RND		0x02
 	struct boot_module	*bm_next;
 } boot_module_t;
 

Index: src/sys/arch/i386/stand/lib/exec.c
diff -u src/sys/arch/i386/stand/lib/exec.c:1.48 src/sys/arch/i386/stand/lib/exec.c:1.49
--- src/sys/arch/i386/stand/lib/exec.c:1.48	Sun Jul 17 20:54:41 2011
+++ src/sys/arch/i386/stand/lib/exec.c	Mon Nov 28 07:56:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec.c,v 1.48 2011/07/17 20:54:41 joerg Exp $	 */
+/*	$NetBSD: exec.c,v 1.49 2011/11/28 07:56:54 tls Exp $	 */
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -171,6 +171,12 @@ splash_add(char *name)
 	return module_add_common(name, BM_TYPE_IMAGE);
 }
 
+void
+rnd_add(char *name)
+{
+	return module_add_common(name, BM_TYPE_RND);
+}
+
 static void
 module_add_common(char *name, uint8_t type)
 {
@@ -579,8 +585,19 @@ module_init(const char *kernel_path)
 			strncpy(bi->path, bm->bm_path, sizeof(bi->path) - 1);
 			bi->base = image_end;
 			bi->len = len;
-			bi->type = bm->bm_type == BM_TYPE_KMOD ?
-			    BI_MODULE_ELF : BI_MODULE_IMAGE;
+			switch (bm->bm_type) {
+			    case BM_TYPE_KMOD:
+				bi->type = BI_MODULE_ELF;
+				break;
+			    case BM_TYPE_IMAGE:
+				bi->type = BI_MODULE_IMAGE;
+				break;
+			    case BM_TYPE_RND:
+			    default:
+				/* safest -- rnd checks the sha1 */
+				bi->type = BI_MODULE_RND;
+				break;
+			}
 			if ((howto & AB_SILENT) == 0)
 				printf(" \n");
 		}

Index: src/sys/arch/i386/stand/lib/libi386.h
diff -u src/sys/arch/i386/stand/lib/libi386.h:1.37 src/sys/arch/i386/stand/lib/libi386.h:1.38
--- src/sys/arch/i386/stand/lib/libi386.h:1.37	Thu Jun 16 13:27:59 2011
+++ src/sys/arch/i386/stand/lib/libi386.h	Mon Nov 28 07:56:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: libi386.h,v 1.37 2011/06/16 13:27:59 joerg Exp $	*/
+/*	$NetBSD: libi386.h,v 1.38 2011/11/28 07:56:54 tls Exp $	*/
 
 /*
  * Copyright (c) 1996
@@ -138,6 +138,7 @@ extern int doserrno;	/* in dos_file.S */
 
 void module_add(char *);
 void splash_add(char *);
+void rnd_add(char *);
 void userconf_add(char *);
 
 struct btinfo_framebuffer;

Index: src/sys/arch/x86/include/bootinfo.h
diff -u src/sys/arch/x86/include/bootinfo.h:1.18 src/sys/arch/x86/include/bootinfo.h:1.19
--- src/sys/arch/x86/include/bootinfo.h:1.18	Thu May 26 04:25:28 2011
+++ src/sys/arch/x86/include/bootinfo.h	Mon Nov 28 07:56:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: bootinfo.h,v 1.18 2011/05/26 04:25:28 uebayasi Exp $	*/
+/*	$NetBSD: bootinfo.h,v 1.19 2011/11/28 07:56:54 tls Exp $	*/
 
 /*
  * Copyright (c) 1997
@@ -175,6 +175,7 @@ struct bi_modulelist_entry {
 #define	BI_MODULE_NONE		0x00
 #define	BI_MODULE_ELF		0x01
 #define	BI_MODULE_IMAGE		0x02
+#define BI_MODULE_RND		0x03
 
 struct btinfo_modulelist {
 	struct btinfo_common common;

Index: src/sys/arch/x86/x86/x86_machdep.c
diff -u src/sys/arch/x86/x86/x86_machdep.c:1.56 src/sys/arch/x86/x86/x86_machdep.c:1.57
--- src/sys/arch/x86/x86/x86_machdep.c:1.56	Sat Aug 13 21:04:05 2011
+++ src/sys/arch/x86/x86/x86_machdep.c	Mon Nov 28 07:56:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: x86_machdep.c,v 1.56 2011/08/13 21:04:05 christos Exp $	*/
+/*	$NetBSD: x86_machdep.c,v 1.57 2011/11/28 07:56:54 tls Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2006, 2007 YAMAMOTO Takashi,
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.56 2011/08/13 21:04:05 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.57 2011/11/28 07:56:54 tls Exp $");
 
 #include "opt_modular.h"
 #include "opt_physmem.h"
@@ -50,6 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: x86_machdep.
 #include <sys/module.h>
 #include <sys/sysctl.h>
 #include <sys/extent.h>
+#include <sys/rnd.h>
 
 #include <x86/cpuvar.h>
 #include <x86/cputypes.h>
@@ -173,6 +174,14 @@ module_init_md(void)
 			    (void *)((uintptr_t)bi->base + KERNBASE), bi->len);
 #endif
 			break;
+		case BI_MODULE_RND:
+			aprint_debug("Random seed data path=%s len=%d pa=%x\n",
+				     bi->path, bi->len, bi->base);
+			KASSERT(trunc_page(bi->base) == bi->base);
+			rnd_seed(
+			    (void *)((uintptr_t)bi->base + KERNBASE),
+			     bi->len);
+			break;
 		default:
 			aprint_debug("Skipping non-ELF module\n");
 			break;

Index: src/sys/dev/rnd.c
diff -u src/sys/dev/rnd.c:1.86 src/sys/dev/rnd.c:1.87
--- src/sys/dev/rnd.c:1.86	Wed Nov 23 10:47:48 2011
+++ src/sys/dev/rnd.c	Mon Nov 28 07:56:54 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: rnd.c,v 1.86 2011/11/23 10:47:48 tls Exp $	*/
+/*	$NetBSD: rnd.c,v 1.87 2011/11/28 07:56:54 tls Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rnd.c,v 1.86 2011/11/23 10:47:48 tls Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rnd.c,v 1.87 2011/11/28 07:56:54 tls Exp $");
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
@@ -184,6 +184,7 @@ static int		rnd_tested = 0;
 
 LIST_HEAD(, krndsource)	rnd_sources;
 
+static rndsave_t	*boot_rsp;
 /*
  * Generate a 32-bit counter.  This should be more machine dependent,
  * using cycle counters and the like when possible.
@@ -406,6 +407,23 @@ rnd_init(void)
 	printf("rnd: initialised (%u)%s", RND_POOLBITS,
 	       c ? " with counter\n" : "\n");
 #endif
+	if (boot_rsp != NULL) {
+		mutex_spin_enter(&rndpool_mtx);
+			rndpool_add_data(&rnd_pool, boot_rsp->data,
+					 sizeof(boot_rsp->data),
+					 MIN(boot_rsp->entropy,
+					     RND_POOLBITS / 2));
+		if (rndpool_get_entropy_count(&rnd_pool) >
+		    RND_ENTROPY_THRESHOLD * 8) {
+                	rnd_have_entropy = 1;
+		}
+                mutex_spin_exit(&rndpool_mtx);
+#ifdef RND_VERBOSE
+		printf("rnd: seeded with %d bits\n",
+		       MIN(boot_rsp->entropy, RND_POOLBITS / 2));
+#endif
+		memset(boot_rsp, 0, sizeof(*boot_rsp));
+	}
 }
 
 int
@@ -748,32 +766,41 @@ rndioctl(dev_t dev, u_long cmd, void *ad
 		break;
 
 	case RNDADDDATA:
-		rnddata = (rnddata_t *)addr;
+		/*
+		 * Don't seed twice if our bootloader has
+		 * seed loading support.
+		 */
+		if (!boot_rsp) {
+			rnddata = (rnddata_t *)addr;
 
-		if (rnddata->len > sizeof(rnddata->data))
-			return EINVAL;
+			if (rnddata->len > sizeof(rnddata->data))
+				return EINVAL;
 
-		if (estimate_ok) {
-			/*
-			 * Do not accept absurd entropy estimates, and
-			 * do not flood the pool with entropy such that
-			 * new samples are discarded henceforth.
-			 */
-			estimate = MIN((rnddata->len * NBBY) / 2,
-				       MIN(rnddata->entropy,
-					   RND_POOLWORDS * sizeof(int) *
-					   NBBY / 2));
-		} else {
-			estimate = 0;
-		}
-
-		mutex_spin_enter(&rndpool_mtx);
-		rndpool_add_data(&rnd_pool, rnddata->data, rnddata->len,
-				 estimate);
-		mutex_spin_exit(&rndpool_mtx);
+			if (estimate_ok) {
+				/*
+				 * Do not accept absurd entropy estimates, and
+				 * do not flood the pool with entropy such that
+				 * new samples are discarded henceforth.
+				 */
+				estimate = MIN((rnddata->len * NBBY) / 2,
+					       MIN(rnddata->entropy,
+						   RND_POOLBITS / 2));
+			} else {
+				estimate = 0;
+			}
 
-		rnd_wakeup_readers();
+			mutex_spin_enter(&rndpool_mtx);
+			rndpool_add_data(&rnd_pool, rnddata->data,
+					 rnddata->len, estimate);
+			mutex_spin_exit(&rndpool_mtx);
 
+			rnd_wakeup_readers();
+		}
+#ifdef RND_VERBOSE
+		else {
+			printf("rnd: already seeded by boot loader\n");
+		}
+#endif
 		break;
 
 	default:
@@ -1441,3 +1468,47 @@ rndsink_detach(rndsink_t *rs)
 	}
 	mutex_spin_exit(&rndpool_mtx);
 }
+
+void
+rnd_seed(void *base, size_t len)
+{
+	SHA1_CTX s;
+	uint8_t digest[SHA1_DIGEST_LENGTH];
+
+	if (len != sizeof(*boot_rsp)) {
+		aprint_error("rnd: bad seed length %d\n", (int)len);
+		return;
+	}
+
+	boot_rsp = (rndsave_t *)base;
+	SHA1Init(&s);
+	SHA1Update(&s, (uint8_t *)&boot_rsp->entropy,
+		   sizeof(boot_rsp->entropy));
+	SHA1Update(&s, boot_rsp->data, sizeof(boot_rsp->data));
+	SHA1Final(digest, &s);
+
+	if (memcmp(digest, boot_rsp->digest, sizeof(digest))) {
+		aprint_error("rnd: bad seed checksum\n");
+		return;
+	}
+
+	/*
+	 * It's not really well-defined whether bootloader-supplied
+	 * modules run before or after rnd_init().  Handle both cases.
+	 */
+	if (rnd_ready) {
+#ifdef RND_VERBOSE
+		printf("rnd: ready, feeding in seed data directly.\n");
+#endif
+		mutex_spin_enter(&rndpool_mtx);
+		rndpool_add_data(&rnd_pool, boot_rsp->data,
+				 sizeof(boot_rsp->data),
+				 MIN(boot_rsp->entropy, RND_POOLBITS / 2));
+		memset(boot_rsp, 0, sizeof(*boot_rsp));
+		mutex_spin_exit(&rndpool_mtx);
+	} else {
+#ifdef RND_VERBOSE
+		printf("rnd: not ready, deferring seed feed.\n");
+#endif
+	}
+}

Reply via email to