* Add random_adaptors.[ch] which is basically a store of random_adaptor's.

random_adaptor is basically an adapter that plugs in to random(4).
  random_adaptor can only be plugged in to random(4) very early in bootup.
  Unplugging random_adaptor from random(4) is not supported, and is probably a
  bad idea anyway, due to potential loss of entropy pools.
  We currently have 3 random_adaptors:
  + yarrow
  + rdrand (ivy.c)
  + nehemeiah

* Remove platform dependent logic from probe.c, and move it into
  corresponding registration routines of each random_adaptor provider.
  probe.c doesn't do anything other than picking a specific random_adaptor
  from a list of registered ones.

* If the kernel doesn't have any random_adaptor adapters present then the
  creation of /dev/random is postponed until next random_adaptor is kldload'ed.

* Fix randomdev_soft.c to refer to its own random_adaptor, instead of a
  system wide one.

Submitted by: arthurmesh@gmail.com, obrien
Obtained from: Juniper Networks
Reviewed by: so (des)
This commit is contained in:
David E. O'Brien 2013-08-09 15:31:50 +00:00
parent e946b94934
commit 5711939b63
13 changed files with 410 additions and 107 deletions

View File

@ -23,7 +23,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd September 7, 2012 .Dd August 7, 2013
.Dt RANDOM 4 .Dt RANDOM 4
.Os .Os
.Sh NAME .Sh NAME
@ -43,6 +43,13 @@ The device will probe for
certain hardware entropy sources, certain hardware entropy sources,
and use these in preference to the fallback, and use these in preference to the fallback,
which is a generator implemented in software. which is a generator implemented in software.
If the kernel environment MIB's
.Va hw.nehemiah_rng_enable
or
.Va hw.ivy_rng_enable
are set to
.Dq Li 0 ,
the associated hardware entropy source will be ignored.
.Pp .Pp
If the device is using If the device is using
the software generator, the software generator,
@ -74,6 +81,7 @@ device, use the command line:
.Pp .Pp
which results in something like: which results in something like:
.Bd -literal -offset indent .Bd -literal -offset indent
kern.random.adaptors: yarrow
kern.random.sys.seeded: 1 kern.random.sys.seeded: 1
kern.random.sys.harvest.ethernet: 1 kern.random.sys.harvest.ethernet: 1
kern.random.sys.harvest.point_to_point: 1 kern.random.sys.harvest.point_to_point: 1
@ -89,7 +97,9 @@ kern.random.yarrow.slowoverthresh: 2
(These would not be seen if a (These would not be seen if a
hardware generator is present.) hardware generator is present.)
.Pp .Pp
All settings are read/write. Other than
.Dl kern.random.adaptors
all settings are read/write.
.Pp .Pp
The The
.Va kern.random.sys.seeded .Va kern.random.sys.seeded

View File

@ -2032,6 +2032,7 @@ rt2860.fw optional rt2860fw | ralfw \
dev/random/harvest.c standard dev/random/harvest.c standard
dev/random/hash.c optional random dev/random/hash.c optional random
dev/random/probe.c optional random dev/random/probe.c optional random
dev/random/random_adaptors.c standard
dev/random/randomdev.c optional random dev/random/randomdev.c optional random
dev/random/randomdev_soft.c optional random dev/random/randomdev_soft.c optional random
dev/random/yarrow.c optional random dev/random/yarrow.c optional random

View File

@ -1,4 +1,5 @@
/*- /*-
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org> * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
* All rights reserved. * All rights reserved.
* *
@ -28,16 +29,19 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include "opt_cpu.h"
#ifdef RDRAND_RNG
#include <sys/param.h> #include <sys/param.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/kernel.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/selinfo.h> #include <sys/selinfo.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h> #include <dev/random/randomdev.h>
#define RETRY_COUNT 10 #define RETRY_COUNT 10
@ -46,7 +50,7 @@ static void random_ivy_init(void);
static void random_ivy_deinit(void); static void random_ivy_deinit(void);
static int random_ivy_read(void *, int); static int random_ivy_read(void *, int);
struct random_systat random_ivy = { struct random_adaptor random_ivy = {
.ident = "Hardware, Intel IvyBridge+ RNG", .ident = "Hardware, Intel IvyBridge+ RNG",
.init = random_ivy_init, .init = random_ivy_init,
.deinit = random_ivy_deinit, .deinit = random_ivy_deinit,
@ -114,4 +118,28 @@ random_ivy_read(void *buf, int c)
return (c - count); return (c - count);
} }
static int
rdrand_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
if (cpu_feature2 & CPUID2_RDRAND) {
random_adaptor_register("rdrand", &random_ivy);
EVENTHANDLER_INVOKE(random_adaptor_attach, &random_ivy);
return (0);
} else {
#ifndef KLD_MODULE
if (bootverbose)
#endif #endif
printf(
"%s: RDRAND feature is not present on this CPU\n",
random_ivy.ident);
return (0);
}
}
return (EINVAL);
}
RANDOM_ADAPTOR_MODULE(random_rdrand, rdrand_modevent, 1);

View File

@ -1,4 +1,5 @@
/*- /*-
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* Copyright (c) 2004 Mark R V Murray * Copyright (c) 2004 Mark R V Murray
* All rights reserved. * All rights reserved.
* *
@ -28,19 +29,20 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include "opt_cpu.h"
#ifdef PADLOCK_RNG
#include <sys/param.h> #include <sys/param.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/module.h>
#include <sys/selinfo.h> #include <sys/selinfo.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/kernel.h>
#include <machine/pcb.h> #include <machine/pcb.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h> #include <dev/random/randomdev.h>
#define RANDOM_BLOCK_SIZE 256 #define RANDOM_BLOCK_SIZE 256
@ -50,7 +52,7 @@ static void random_nehemiah_init(void);
static void random_nehemiah_deinit(void); static void random_nehemiah_deinit(void);
static int random_nehemiah_read(void *, int); static int random_nehemiah_read(void *, int);
struct random_systat random_nehemiah = { struct random_adaptor random_nehemiah = {
.ident = "Hardware, VIA Nehemiah", .ident = "Hardware, VIA Nehemiah",
.init = random_nehemiah_init, .init = random_nehemiah_init,
.deinit = random_nehemiah_deinit, .deinit = random_nehemiah_deinit,
@ -208,4 +210,29 @@ random_nehemiah_read(void *buf, int c)
return (c); return (c);
} }
static int
nehemiah_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
if (via_feature_rng & VIA_HAS_RNG) {
random_adaptor_register("nehemiah", &random_nehemiah);
EVENTHANDLER_INVOKE(random_adaptor_attach,
&random_nehemiah);
return (0);
} else {
#ifndef KLD_MODULE
if (bootverbose)
#endif #endif
printf(
"%s: VIA RNG feature is not present on this CPU\n",
random_nehemiah.ident);
return (0);
}
}
return (EINVAL);
}
RANDOM_ADAPTOR_MODULE(nehemiah, nehemiah_modevent, 1);

View File

@ -28,66 +28,35 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#if defined(__amd64__) || (defined(__i386__) && !defined(PC98)) #if defined(__amd64__) || defined(__i386__)
#include "opt_cpu.h" #include "opt_cpu.h"
#endif #endif
#include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/kernel.h> #include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/random.h>
#include <sys/selinfo.h> #include <sys/selinfo.h>
#include <sys/sysctl.h>
#if defined(__amd64__) || (defined(__i386__) && !defined(PC98))
#include <machine/cpufunc.h>
#include <machine/cputypes.h>
#include <machine/md_var.h>
#include <machine/specialreg.h>
#endif
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h> #include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
#if defined(__amd64__) || (defined(__i386__) && !defined(PC98))
#ifdef PADLOCK_RNG
extern struct random_systat random_nehemiah;
#endif
#ifdef RDRAND_RNG
extern struct random_systat random_ivy;
#endif
#endif
void void
random_ident_hardware(struct random_systat **systat) random_ident_hardware(struct random_adaptor **adaptor)
{ {
struct random_adaptor *tmp;
int enable;
/* Set default to software */ /* Set default to software (yarrow) */
*systat = &random_yarrow; *adaptor = random_adaptor_get("yarrow");
/* Then go looking for hardware */ /* Then go looking for hardware */
#if defined(__amd64__) || (defined(__i386__) && !defined(PC98)) enable = 1;
#ifdef PADLOCK_RNG TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable);
if (via_feature_rng & VIA_HAS_RNG) { if (enable && (tmp = random_adaptor_get("nehemiah")))
int enable; *adaptor = tmp;
enable = 1; enable = 1;
TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable); TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable);
if (enable) if (enable && (tmp = random_adaptor_get("rdrand")))
*systat = &random_nehemiah; *adaptor = tmp;
}
#endif
#ifdef RDRAND_RNG
if (cpu_feature2 & CPUID2_RDRAND) {
int enable;
enable = 1;
TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable);
if (enable)
*systat = &random_ivy;
}
#endif
#endif
} }

View File

@ -0,0 +1,138 @@
/*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* Copyright (c) 2013 David E. O'Brien <obrien@NUXI.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/param.h>
__FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/selinfo.h>
#include <sys/sysctl.h>
#include <sys/sx.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/libkern.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h>
LIST_HEAD(adaptors_head, random_adaptors);
static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors);
static struct sx adaptors_lock; /* need a sleepable lock */
/* List for the dynamic sysctls */
static struct sysctl_ctx_list random_clist;
MALLOC_DEFINE(M_RANDOM_ADAPTORS, "random_adaptors", "Random adaptors buffers");
int
random_adaptor_register(const char *name, struct random_adaptor *rsp)
{
struct random_adaptors *rpp;
KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__));
rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS, M_WAITOK);
rpp->name = name;
rpp->rsp = rsp;
sx_xlock(&adaptors_lock);
LIST_INSERT_HEAD(&adaptors, rpp, entries);
sx_xunlock(&adaptors_lock);
return (0);
}
struct random_adaptor *
random_adaptor_get(const char *name)
{
struct random_adaptors *rpp;
struct random_adaptor *rsp;
rsp = NULL;
sx_slock(&adaptors_lock);
LIST_FOREACH(rpp, &adaptors, entries)
if (strcmp(rpp->name, name) == 0)
rsp = rpp->rsp;
sx_sunlock(&adaptors_lock);
return (rsp);
}
static void
random_adaptors_deinit(void *unused)
{
sx_destroy(&adaptors_lock);
sysctl_ctx_free(&random_clist);
}
static int
random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS)
{
struct random_adaptors *rpp;
int error;
error = 0;
sx_slock(&adaptors_lock);
if (LIST_EMPTY(&adaptors))
error = SYSCTL_OUT(req, "", strlen(""));
LIST_FOREACH(rpp, &adaptors, entries) {
if (0 != SYSCTL_OUT(req, rpp->name, strlen(rpp->name)))
break;
}
sx_sunlock(&adaptors_lock);
return (error);
}
static void
random_adaptors_init(void *unused)
{
SYSCTL_PROC(_kern_random, OID_AUTO, adaptors,
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
NULL, 0, random_sysctl_adaptors_handler, "",
"Random Number Generator adaptors");
sx_init(&adaptors_lock, "random_adaptors");
}
SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator");
SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST, random_adaptors_init,
NULL);
SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_FIRST,
random_adaptors_deinit, NULL);

View File

@ -0,0 +1,66 @@
/*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef __RANDOM_ADAPTORS_H__
#define __RANDOM_ADAPTORS_H__
#include <sys/eventhandler.h>
struct random_adaptors {
LIST_ENTRY(random_adaptors) entries; /* list of providers */
const char *name; /* name of random adaptor */
struct random_adaptor *rsp;
};
struct random_adaptor *random_adaptor_get(const char *);
int random_adaptor_register(const char *, struct random_adaptor *);
/*
* random_adaptor's should be registered prior to
* random module (SI_SUB_DRIVERS/SI_ORDER_MIDDLE)
*/
#define RANDOM_ADAPTOR_MODULE(name, modevent, ver) \
static moduledata_t name##_mod = { \
#name, \
modevent, \
0 \
}; \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, \
SI_ORDER_SECOND); \
MODULE_VERSION(name, ver); \
MODULE_DEPEND(name, random, 1, 1, 1);
typedef void (*random_adaptor_attach_hook)(void *, struct random_adaptor *);
EVENTHANDLER_DECLARE(random_adaptor_attach, random_adaptor_attach_hook);
/* kern.random sysctls */
#ifdef SYSCTL_DECL /* from sysctl.h */
SYSCTL_DECL(_kern_random);
#endif /* SYSCTL_DECL */
#endif /* __RANDOM_ADAPTORS_H__ */

View File

@ -1,4 +1,5 @@
/*- /*-
* Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
* Copyright (c) 2000-2004 Mark R V Murray * Copyright (c) 2000-2004 Mark R V Murray
* All rights reserved. * All rights reserved.
* *
@ -70,12 +71,15 @@ static struct cdevsw random_cdevsw = {
.d_name = "random", .d_name = "random",
}; };
struct random_systat *random_systat; static struct random_adaptor *random_adaptor;
static eventhandler_tag attach_tag;
static int random_inited;
/* For use with make_dev(9)/destroy_dev(9). */ /* For use with make_dev(9)/destroy_dev(9). */
static struct cdev *random_dev; static struct cdev *random_dev;
/* Used to fake out unused random calls in random_systat */ /* Used to fake out unused random calls in random_adaptor */
void void
random_null_func(void) random_null_func(void)
{ {
@ -88,8 +92,8 @@ random_close(struct cdev *dev __unused, int flags, int fmt __unused,
{ {
if ((flags & FWRITE) && (priv_check(td, PRIV_RANDOM_RESEED) == 0) if ((flags & FWRITE) && (priv_check(td, PRIV_RANDOM_RESEED) == 0)
&& (securelevel_gt(td->td_ucred, 0) == 0)) { && (securelevel_gt(td->td_ucred, 0) == 0)) {
(*random_systat->reseed)(); (*random_adaptor->reseed)();
random_systat->seeded = 1; random_adaptor->seeded = 1;
arc4rand(NULL, 0, 1); /* Reseed arc4random as well. */ arc4rand(NULL, 0, 1); /* Reseed arc4random as well. */
} }
@ -104,8 +108,8 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag)
void *random_buf; void *random_buf;
/* Blocking logic */ /* Blocking logic */
if (!random_systat->seeded) if (!random_adaptor->seeded)
error = (*random_systat->block)(flag); error = (*random_adaptor->block)(flag);
/* The actual read */ /* The actual read */
if (!error) { if (!error) {
@ -114,7 +118,7 @@ random_read(struct cdev *dev __unused, struct uio *uio, int flag)
while (uio->uio_resid > 0 && !error) { while (uio->uio_resid > 0 && !error) {
c = MIN(uio->uio_resid, PAGE_SIZE); c = MIN(uio->uio_resid, PAGE_SIZE);
c = (*random_systat->read)(random_buf, c); c = (*random_adaptor->read)(random_buf, c);
error = uiomove(random_buf, c, uio); error = uiomove(random_buf, c, uio);
} }
@ -139,7 +143,7 @@ random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused)
error = uiomove(random_buf, c, uio); error = uiomove(random_buf, c, uio);
if (error) if (error)
break; break;
(*random_systat->write)(random_buf, c); (*random_adaptor->write)(random_buf, c);
} }
free(random_buf, M_TEMP); free(random_buf, M_TEMP);
@ -172,14 +176,37 @@ random_poll(struct cdev *dev __unused, int events, struct thread *td)
int revents = 0; int revents = 0;
if (events & (POLLIN | POLLRDNORM)) { if (events & (POLLIN | POLLRDNORM)) {
if (random_systat->seeded) if (random_adaptor->seeded)
revents = events & (POLLIN | POLLRDNORM); revents = events & (POLLIN | POLLRDNORM);
else else
revents = (*random_systat->poll) (events,td); revents = (*random_adaptor->poll) (events,td);
} }
return (revents); return (revents);
} }
static void
random_initialize(void *p, struct random_adaptor *s)
{
if (random_inited) {
printf("random: <%s> already initialized\n",
random_adaptor->ident);
return;
}
random_adaptor = s;
(s->init)();
printf("random: <%s> initialized\n", s->ident);
random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw,
RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random");
make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */
/* mark random(4) as initialized, to avoid being called again */
random_inited = 1;
}
/* ARGSUSED */ /* ARGSUSED */
static int static int
random_modevent(module_t mod __unused, int type, void *data __unused) random_modevent(module_t mod __unused, int type, void *data __unused)
@ -188,23 +215,29 @@ random_modevent(module_t mod __unused, int type, void *data __unused)
switch (type) { switch (type) {
case MOD_LOAD: case MOD_LOAD:
random_ident_hardware(&random_systat); random_ident_hardware(&random_adaptor);
(*random_systat->init)();
if (bootverbose) if (random_adaptor == NULL) {
printf("random: <entropy source, %s>\n", printf(
random_systat->ident); "random: No random adaptor attached, postponing initialization\n");
attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach,
random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, random_initialize, NULL, EVENTHANDLER_PRI_ANY);
RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0666, "random"); } else {
make_dev_alias(random_dev, "urandom"); /* XXX Deprecated */ random_initialize(NULL, random_adaptor);
}
break; break;
case MOD_UNLOAD: case MOD_UNLOAD:
(*random_systat->deinit)(); if (random_adaptor != NULL) {
(*random_adaptor->deinit)();
destroy_dev(random_dev); destroy_dev(random_dev);
}
/* Unregister the event handler */
if (attach_tag != NULL) {
EVENTHANDLER_DEREGISTER(random_adaptor_attach,
attach_tag);
}
break; break;

View File

@ -38,7 +38,7 @@ typedef void random_write_func_t(void *, int);
typedef int random_poll_func_t(int, struct thread *); typedef int random_poll_func_t(int, struct thread *);
typedef void random_reseed_func_t(void); typedef void random_reseed_func_t(void);
struct random_systat { struct random_adaptor {
struct selinfo rsel; struct selinfo rsel;
const char *ident; const char *ident;
int seeded; int seeded;
@ -51,7 +51,5 @@ struct random_systat {
random_reseed_func_t *reseed; random_reseed_func_t *reseed;
}; };
extern struct random_systat *random_systat; extern void random_ident_hardware(struct random_adaptor **);
extern void random_ident_hardware(struct random_systat **);
extern void random_null_func(void); extern void random_null_func(void);

View File

@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kthread.h> #include <sys/kthread.h>
#include <sys/lock.h> #include <sys/lock.h>
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/poll.h> #include <sys/poll.h>
#include <sys/proc.h> #include <sys/proc.h>
@ -50,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <machine/bus.h> #include <machine/bus.h>
#include <machine/cpu.h> #include <machine/cpu.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev.h> #include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h> #include <dev/random/randomdev_soft.h>
@ -63,7 +65,7 @@ static int random_yarrow_poll(int event,struct thread *td);
static int random_yarrow_block(int flag); static int random_yarrow_block(int flag);
static void random_yarrow_flush_reseed(void); static void random_yarrow_flush_reseed(void);
struct random_systat random_yarrow = { struct random_adaptor random_yarrow = {
.ident = "Software, Yarrow", .ident = "Software, Yarrow",
.init = random_yarrow_init, .init = random_yarrow_init,
.deinit = random_yarrow_deinit, .deinit = random_yarrow_deinit,
@ -103,7 +105,7 @@ static int random_kthread_control = 0;
static struct proc *random_kthread_proc; static struct proc *random_kthread_proc;
/* List for the dynamic sysctls */ /* List for the dynamic sysctls */
struct sysctl_ctx_list random_clist; static struct sysctl_ctx_list random_clist;
/* ARGSUSED */ /* ARGSUSED */
static int static int
@ -120,25 +122,20 @@ random_yarrow_init(void)
{ {
int error, i; int error, i;
struct harvest *np; struct harvest *np;
struct sysctl_oid *random_o, *random_sys_o, *random_sys_harvest_o; struct sysctl_oid *random_sys_o, *random_sys_harvest_o;
enum esource e; enum esource e;
random_o = SYSCTL_ADD_NODE(&random_clist, random_yarrow_init_alg(&random_clist);
SYSCTL_STATIC_CHILDREN(_kern),
OID_AUTO, "random", CTLFLAG_RW, 0,
"Software Random Number Generator");
random_yarrow_init_alg(&random_clist, random_o);
random_sys_o = SYSCTL_ADD_NODE(&random_clist, random_sys_o = SYSCTL_ADD_NODE(&random_clist,
SYSCTL_CHILDREN(random_o), SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "sys", CTLFLAG_RW, 0, OID_AUTO, "sys", CTLFLAG_RW, 0,
"Entropy Device Parameters"); "Entropy Device Parameters");
SYSCTL_ADD_PROC(&random_clist, SYSCTL_ADD_PROC(&random_clist,
SYSCTL_CHILDREN(random_sys_o), SYSCTL_CHILDREN(random_sys_o),
OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW, OID_AUTO, "seeded", CTLTYPE_INT | CTLFLAG_RW,
&random_systat->seeded, 1, random_check_boolean, "I", &random_yarrow.seeded, 1, random_check_boolean, "I",
"Seeded State"); "Seeded State");
random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist, random_sys_harvest_o = SYSCTL_ADD_NODE(&random_clist,
@ -362,10 +359,10 @@ random_yarrow_write(void *buf, int count)
void void
random_yarrow_unblock(void) random_yarrow_unblock(void)
{ {
if (!random_systat->seeded) { if (!random_yarrow.seeded) {
random_systat->seeded = 1; random_yarrow.seeded = 1;
selwakeuppri(&random_systat->rsel, PUSER); selwakeuppri(&random_yarrow.rsel, PUSER);
wakeup(random_systat); wakeup(&random_yarrow);
} }
(void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE, (void)atomic_cmpset_int(&arc4rand_iniseed_state, ARC4_ENTR_NONE,
ARC4_ENTR_HAVE); ARC4_ENTR_HAVE);
@ -377,10 +374,10 @@ random_yarrow_poll(int events, struct thread *td)
int revents = 0; int revents = 0;
mtx_lock(&random_reseed_mtx); mtx_lock(&random_reseed_mtx);
if (random_systat->seeded) if (random_yarrow.seeded)
revents = events & (POLLIN | POLLRDNORM); revents = events & (POLLIN | POLLRDNORM);
else else
selrecord(td, &random_systat->rsel); selrecord(td, &random_yarrow.rsel);
mtx_unlock(&random_reseed_mtx); mtx_unlock(&random_reseed_mtx);
return revents; return revents;
@ -394,12 +391,12 @@ random_yarrow_block(int flag)
mtx_lock(&random_reseed_mtx); mtx_lock(&random_reseed_mtx);
/* Blocking logic */ /* Blocking logic */
while (!random_systat->seeded && !error) { while (!random_yarrow.seeded && !error) {
if (flag & O_NONBLOCK) if (flag & O_NONBLOCK)
error = EWOULDBLOCK; error = EWOULDBLOCK;
else { else {
printf("Entropy device is blocking.\n"); printf("Entropy device is blocking.\n");
error = msleep(random_systat, error = msleep(&random_yarrow,
&random_reseed_mtx, &random_reseed_mtx,
PUSER | PCATCH, "block", 0); PUSER | PCATCH, "block", 0);
} }
@ -420,3 +417,31 @@ random_yarrow_flush_reseed(void)
random_yarrow_reseed(); random_yarrow_reseed();
} }
static int
yarrow_modevent(module_t mod, int type, void *unused)
{
switch (type) {
case MOD_LOAD:
random_adaptor_register("yarrow", &random_yarrow);
/*
* For statically built kernels that contain both device
* random and options PADLOCK_RNG/RDRAND_RNG/etc..,
* this event handler will do nothing, since the random
* driver-specific handlers are loaded after these HW
* consumers, and hence hasn't yet registered for this event.
*
* In case where both the random driver and RNG's are built
* as seperate modules, random.ko is loaded prior to *_rng.ko's
* (by dependency). This event handler is there to delay
* creation of /dev/{u,}random and attachment of this *_rng.ko.
*/
EVENTHANDLER_INVOKE(random_adaptor_attach, &random_yarrow);
return (0);
}
return (EINVAL);
}
RANDOM_ADAPTOR_MODULE(yarrow, yarrow_modevent, 1);

View File

@ -72,10 +72,10 @@ void random_process_event(struct harvest *event);
void random_yarrow_reseed(void); void random_yarrow_reseed(void);
void random_yarrow_unblock(void); void random_yarrow_unblock(void);
void random_yarrow_init_alg(struct sysctl_ctx_list *, struct sysctl_oid *); void random_yarrow_init_alg(struct sysctl_ctx_list *);
void random_yarrow_deinit_alg(void); void random_yarrow_deinit_alg(void);
extern struct random_systat random_yarrow; extern struct random_adaptor random_yarrow;
extern struct mtx random_reseed_mtx; extern struct mtx random_reseed_mtx;
/* If this was c++, this would be a template */ /* If this was c++, this would be a template */

View File

@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
#include <crypto/sha2/sha2.h> #include <crypto/sha2/sha2.h>
#include <dev/random/hash.h> #include <dev/random/hash.h>
#include <dev/random/random_adaptors.h>
#include <dev/random/randomdev_soft.h> #include <dev/random/randomdev_soft.h>
#include <dev/random/yarrow.h> #include <dev/random/yarrow.h>
@ -101,7 +102,7 @@ random_process_event(struct harvest *event)
} }
void void
random_yarrow_init_alg(struct sysctl_ctx_list *clist, struct sysctl_oid *in_o) random_yarrow_init_alg(struct sysctl_ctx_list *clist)
{ {
int i; int i;
struct sysctl_oid *random_yarrow_o; struct sysctl_oid *random_yarrow_o;
@ -110,7 +111,7 @@ random_yarrow_init_alg(struct sysctl_ctx_list *clist, struct sysctl_oid *in_o)
* have a very good clue about what they do! * have a very good clue about what they do!
*/ */
random_yarrow_o = SYSCTL_ADD_NODE(clist, random_yarrow_o = SYSCTL_ADD_NODE(clist,
SYSCTL_CHILDREN(in_o), SYSCTL_STATIC_CHILDREN(_kern_random),
OID_AUTO, "yarrow", CTLFLAG_RW, 0, OID_AUTO, "yarrow", CTLFLAG_RW, 0,
"Yarrow Parameters"); "Yarrow Parameters");

View File

@ -1092,6 +1092,13 @@ line programs.
kern.quantum kern.quantum
---
kern.random.adaptors
str
Displays registered PRNG adaptors.
This is a read-only variable.
--- ---
kern.random.sys.burst kern.random.sys.burst