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.
This commit is contained in:
parent
1dafd61846
commit
a031ce7187
|
@ -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 option.
|
|||
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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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 <jmcneill@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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.c,v 1.56 2011/08/13 21:04:05 christos Ex
|
|||
#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;
|
||||
|
|
121
sys/dev/rnd.c
121
sys/dev/rnd.c
|
@ -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 *addr, int flag,
|
|||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
mutex_spin_enter(&rndpool_mtx);
|
||||
rndpool_add_data(&rnd_pool, rnddata->data,
|
||||
rnddata->len, estimate);
|
||||
mutex_spin_exit(&rndpool_mtx);
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue