diff --git a/share/examples/kld/Makefile b/share/examples/kld/Makefile index 4e3b641f57c7..5e6fc7459bc5 100644 --- a/share/examples/kld/Makefile +++ b/share/examples/kld/Makefile @@ -67,6 +67,6 @@ # $FreeBSD$ # -SUBDIR= cdev dyn_sysctl firmware khelp syscall +SUBDIR= cdev dyn_sysctl firmware khelp random_adaptor syscall .include diff --git a/share/examples/kld/random_adaptor/Makefile b/share/examples/kld/random_adaptor/Makefile new file mode 100644 index 000000000000..d19b4dc26473 --- /dev/null +++ b/share/examples/kld/random_adaptor/Makefile @@ -0,0 +1,6 @@ +# $FreeBSD$ + +KMOD= random_adaptor_example +SRCS= ${KMOD}.c + +.include diff --git a/share/examples/kld/random_adaptor/random_adaptor_example.c b/share/examples/kld/random_adaptor/random_adaptor_example.c new file mode 100644 index 000000000000..f94a7c20f3a3 --- /dev/null +++ b/share/examples/kld/random_adaptor/random_adaptor_example.c @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 2013 Arthur Mesh + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +static int random_example_entropy_control; + +#define RNG_NAME "example" + +static int random_example_read(void *, int); +static void random_example_init(void); + +struct random_adaptor random_example = { + .ident = "Example RNG", + .init = random_example_init, + .deinit = (random_deinit_func_t *)random_null_func, + .read = random_example_read, + .write = (random_write_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 1, +}; + +static void +random_example_init(void) +{ + + /* + * Init() is called only if this RNG was chosen to plugin in to + * random(4). In which case, we should no longer use this adaptor as + * an entropy source. + */ + random_example_entropy_control = 1; +} + +/* + * Used under the license provided @ http://xkcd.com/221/ + * http://creativecommons.org/licenses/by-nc/2.5/ + */ +static u_char +getRandomNumber(void) +{ + return 4; /* chosen by fair dice roll, guaranteed to be random */ +} + +static int +random_example_read(void *buf, int c) +{ + u_char *b; + int count; + + b = buf; + + for (count = 0; count < c; count++) { + b[count] = getRandomNumber(); + } + + printf("returning %d bytes of pure randomness\n", c); + return (c); +} + +static int +random_example_modevent(module_t mod, int type, void *unused) +{ + + switch (type) { + case MOD_LOAD: + /* start off by using this as an entropy source */ + random_adaptor_use_as_entropy(RNG_NAME, &random_example, + &random_example_entropy_control); + random_adaptor_register(RNG_NAME, &random_example); + EVENTHANDLER_INVOKE(random_adaptor_attach, &random_example); + return (0); + } + + return (EINVAL); +} + +RANDOM_ADAPTOR_MODULE(random_example, random_example_modevent, 1); diff --git a/sys/conf/files b/sys/conf/files index 6b811f3bbbc8..7694329d8d76 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2032,8 +2032,8 @@ rt2860.fw optional rt2860fw | ralfw \ clean "rt2860.fw" dev/random/harvest.c standard dev/random/hash.c optional random -dev/random/probe.c optional random dev/random/random_adaptors.c standard +dev/random/pseudo_rng.c standard dev/random/randomdev.c optional random dev/random/randomdev_soft.c optional random dev/random/yarrow.c optional random diff --git a/sys/dev/random/probe.c b/sys/dev/random/probe.c deleted file mode 100644 index 7039b92606eb..000000000000 --- a/sys/dev/random/probe.c +++ /dev/null @@ -1,62 +0,0 @@ -/*- - * Copyright (c) 2004 Mark R V Murray - * 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 -__FBSDID("$FreeBSD$"); - -#if defined(__amd64__) || defined(__i386__) -#include "opt_cpu.h" -#endif - -#include -#include -#include -#include - -#include -#include - -void -random_ident_hardware(struct random_adaptor **adaptor) -{ - struct random_adaptor *tmp; - int enable; - - /* Set default to software (yarrow) */ - *adaptor = random_adaptor_get("yarrow"); - - /* Then go looking for hardware */ - enable = 1; - TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable); - if (enable && (tmp = random_adaptor_get("nehemiah"))) - *adaptor = tmp; - - enable = 1; - TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable); - if (enable && (tmp = random_adaptor_get("rdrand"))) - *adaptor = tmp; -} diff --git a/sys/dev/random/pseudo_rng.c b/sys/dev/random/pseudo_rng.c new file mode 100644 index 000000000000..13552942f795 --- /dev/null +++ b/sys/dev/random/pseudo_rng.c @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2013 Arthur Mesh + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct mtx pseudo_random_block_mtx; + +static int +pseudo_random_block_read(void *buf __unused, int c __unused) +{ + + mtx_lock(&pseudo_random_block_mtx); + + printf("random(4) device is blocking.\n"); + msleep(pseudo_random_block_read, &pseudo_random_block_mtx, 0, + "block", 0); + + mtx_unlock(&pseudo_random_block_mtx); + + return (0); +} + +static void +pseudo_random_block_init(void) +{ + + mtx_init(&pseudo_random_block_mtx, "sleep mtx for random_block", + NULL, MTX_DEF); +} + +static void +pseudo_random_block_deinit(void) +{ + + mtx_destroy(&pseudo_random_block_mtx); +} + +struct random_adaptor pseudo_random_block = { + .ident = "pseudo-RNG that always blocks", + .init = pseudo_random_block_init, + .deinit = pseudo_random_block_deinit, + .read = pseudo_random_block_read, + .write = (random_write_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 1, +}; + +static int +pseudo_random_panic_read(void *buf, int c) +{ + + panic("Insert a witty panic msg in here."); + + return (0); +} + +struct random_adaptor pseudo_random_panic = { + .ident = "pseudo-RNG that always panics on first read(2)", + .init = (random_init_func_t *)random_null_func, + .deinit = (random_deinit_func_t *)random_null_func, + .read = pseudo_random_panic_read, + .write = (random_write_func_t *)random_null_func, + .reseed = (random_reseed_func_t *)random_null_func, + .seeded = 1, +}; + +static int +pseudo_random_modevent(module_t mod, int type, void *unused) +{ + + switch (type) { + case MOD_LOAD: + random_adaptor_register("block", &pseudo_random_block); + EVENTHANDLER_INVOKE(random_adaptor_attach, + &pseudo_random_block); + + random_adaptor_register("panic", &pseudo_random_panic); + + return (0); + } + + return (EINVAL); +} + +RANDOM_ADAPTOR_MODULE(pseudo, pseudo_random_modevent, 1); diff --git a/sys/dev/random/random_adaptors.c b/sys/dev/random/random_adaptors.c index c187bdb7fcfe..b017993c1ecc 100644 --- a/sys/dev/random/random_adaptors.c +++ b/sys/dev/random/random_adaptors.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2013 Arthur Mesh * Copyright (c) 2013 David E. O'Brien + * Copyright (c) 2004 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,16 +31,20 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include +#include #include #include #include #include #include #include +#include -#include #include +#include +#include LIST_HEAD(adaptors_head, random_adaptors); static struct adaptors_head adaptors = LIST_HEAD_INITIALIZER(adaptors); @@ -50,6 +55,11 @@ static struct sysctl_ctx_list random_clist; MALLOC_DEFINE(M_RANDOM_ADAPTORS, "random_adaptors", "Random adaptors buffers"); +struct entropy_thread_ctx { + struct random_adaptor *adaptor; + int *control; +}; + int random_adaptor_register(const char *name, struct random_adaptor *rsp) { @@ -57,7 +67,8 @@ random_adaptor_register(const char *name, struct random_adaptor *rsp) KASSERT(name != NULL && rsp != NULL, ("invalid input to %s", __func__)); - rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS, M_WAITOK); + rpp = malloc(sizeof(struct random_adaptors), M_RANDOM_ADAPTORS, + M_WAITOK); rpp->name = name; rpp->rsp = rsp; @@ -87,6 +98,159 @@ random_adaptor_get(const char *name) return (rsp); } +/* + * In the past, the logic of the random_adaptor selection was inverted, such + * that hardware RNGs would be chosen unless disabled. This routine is here to + * preserve that functionality to avoid folks losing their hardware RNGs by + * upgrading to newer kernel. + */ +static void +random_adaptor_choose_legacy(struct random_adaptor **adaptor) +{ + struct random_adaptor *tmp; + int enable; + + /* Then go looking for hardware */ + enable = 1; + TUNABLE_INT_FETCH("hw.nehemiah_rng_enable", &enable); + if (enable && (tmp = random_adaptor_get("nehemiah"))) + *adaptor = tmp; + + enable = 1; + TUNABLE_INT_FETCH("hw.ivy_rng_enable", &enable); + if (enable && (tmp = random_adaptor_get("rdrand"))) + *adaptor = tmp; +} + +/* + * Walk a list of registered random(4) adaptors and pick the last non-selected + * one. + * + * If none are selected, use yarrow if available. + */ +void +random_adaptor_choose(struct random_adaptor **adaptor) +{ + char rngs[128], *token, *cp; + struct random_adaptors *rpp; + + KASSERT(adaptor != NULL, ("pre-conditions failed")); + + *adaptor = NULL; + + random_adaptor_choose_legacy(adaptor); + + if (*adaptor != NULL) + return; + + if (TUNABLE_STR_FETCH("rngs_want", rngs, sizeof(rngs))) { + cp = rngs; + + while ((token = strsep(&cp, ",")) != NULL) { + if ((*adaptor = random_adaptor_get(token)) != NULL) + break; + else if (bootverbose) + printf( + "%s random adaptor is not available, skipping\n", + token); + } + } + + if (*adaptor == NULL) { + /* + * Either no RNGs are prefered via rngs_want tunable, or + * no prefered RNGs are registered. + * Fallback to Yarrow. + */ + *adaptor = random_adaptor_get("yarrow"); + + if (*adaptor == NULL) { + /* + * Yarrow doesn't seem to be available. + * Fallback to the first thing that's on the list of + * available RNGs. + */ + sx_slock(&adaptors_lock); + + rpp = LIST_FIRST(&adaptors); + if (rpp != NULL) + *adaptor = rpp->rsp; + + sx_sunlock(&adaptors_lock); + } + + if (bootverbose && *adaptor) + printf("Falling back to <%s> random adaptor", + (*adaptor)->ident); + } +} + +static void +random_proc(void *arg) +{ + struct entropy_thread_ctx *ctx; + u_char randomness[HARVESTSIZE]; + int i; + + ctx = (struct entropy_thread_ctx *)arg; + + /* Sanity check. */ + if (ctx->adaptor == NULL || ctx->adaptor->read == NULL) + return; + + for (; *ctx->control == 0;) { + i = ctx->adaptor->read(randomness, sizeof(randomness)); + + if (i > 0) + /* Be very conservative with entropy estimation here. */ + random_harvest(randomness, i, 0, 0, RANDOM_PURE); + + /* Wake up every 10 secs. */ + tsleep_sbt(ctx->adaptor, PWAIT | PCATCH, "-", SBT_1M / 6, 0, 0); + } + + printf("<%s> entropy source is exiting\n", ctx->adaptor->ident); + free(ctx, M_RANDOM_ADAPTORS); + kproc_exit(0); +} + +/* + * Use RNG's output as an entropy source for another RNG. i.e.: + * +--------+ +--------+ + * | Intel | | Yarrow | + * | RDRAND +--------->| | + * +--------+ +--------+ + * Very useful for seeding software RNGs with output of + * Hardware RNGs like Intel's RdRand and VIA's Padlock. + * + * Returns a handle to the newly created kernel process. + */ +void * +random_adaptor_use_as_entropy(const char *id, struct random_adaptor *adaptor, + int *control) +{ + int error; + struct proc *random_chain_proc; + struct entropy_thread_ctx *ctx; + + KASSERT(adaptor != NULL, ("can't obtain randomness")); + KASSERT(control != NULL, ("can't control entropy process")); + + ctx = malloc(sizeof(struct entropy_thread_ctx), M_RANDOM_ADAPTORS, + M_WAITOK); + + ctx->control = control; + ctx->adaptor = adaptor; + + /* Start the thread */ + error = kproc_create(random_proc, ctx, &random_chain_proc, RFHIGHPID, + 0, "%s_entropy", id); + if (error != 0) + panic("Cannot create rng chaining thread"); + + return random_chain_proc; +} + static void random_adaptors_deinit(void *unused) { @@ -99,18 +263,28 @@ static int random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) { struct random_adaptors *rpp; - int error; + int error, count; - error = 0; + count = error = 0; sx_slock(&adaptors_lock); - if (LIST_EMPTY(&adaptors)) - error = SYSCTL_OUT(req, "", strlen("")); + if (LIST_EMPTY(&adaptors)) { + error = SYSCTL_OUT(req, "", 0); + } else { - LIST_FOREACH(rpp, &adaptors, entries) { - if (0 != SYSCTL_OUT(req, rpp->name, strlen(rpp->name))) - break; + LIST_FOREACH(rpp, &adaptors, entries) { + + error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); + + if (error) + break; + + error = SYSCTL_OUT(req, rpp->name, strlen(rpp->name)); + + if (error) + break; + } } sx_sunlock(&adaptors_lock); @@ -118,6 +292,37 @@ random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) return (error); } +static int +random_sysctl_active_adaptor_handler(SYSCTL_HANDLER_ARGS) +{ + struct random_adaptor *rsp; + struct random_adaptors *rpp; + const char *name; + int error; + + name = NULL; + rsp = random_get_active_adaptor(); + + if (rsp != NULL) { + sx_slock(&adaptors_lock); + + LIST_FOREACH(rpp, &adaptors, entries) { + if (rpp->rsp == rsp) + name = rpp->name; + } + + sx_sunlock(&adaptors_lock); + } + + if (rsp == NULL || name == NULL) { + error = SYSCTL_OUT(req, "", 0); + } else { + error = SYSCTL_OUT(req, name, strlen(name)); + } + + return (error); +} + static void random_adaptors_init(void *unused) { @@ -127,6 +332,11 @@ random_adaptors_init(void *unused) NULL, 0, random_sysctl_adaptors_handler, "", "Random Number Generator adaptors"); + SYSCTL_PROC(_kern_random, OID_AUTO, active_adaptor, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, random_sysctl_active_adaptor_handler, "", + "Active Random Number Generator Adaptor"); + sx_init(&adaptors_lock, "random_adaptors"); } diff --git a/sys/dev/random/random_adaptors.h b/sys/dev/random/random_adaptors.h index 50a7a0fea017..b3038e750620 100644 --- a/sys/dev/random/random_adaptors.h +++ b/sys/dev/random/random_adaptors.h @@ -39,6 +39,9 @@ struct random_adaptors { struct random_adaptor *random_adaptor_get(const char *); int random_adaptor_register(const char *, struct random_adaptor *); +void random_adaptor_choose(struct random_adaptor **); +void *random_adaptor_use_as_entropy(const char *, struct random_adaptor *, + int *); /* * random_adaptor's should be registered prior to diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index d18641fe3098..850948ee9627 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #define RANDOM_MINOR 0 @@ -85,6 +86,13 @@ random_null_func(void) { } +struct random_adaptor * +random_get_active_adaptor(void) +{ + + return (random_adaptor); +} + /* ARGSUSED */ static int random_close(struct cdev *dev __unused, int flags, int fmt __unused, @@ -215,7 +223,7 @@ random_modevent(module_t mod __unused, int type, void *data __unused) switch (type) { case MOD_LOAD: - random_ident_hardware(&random_adaptor); + random_adaptor_choose(&random_adaptor); if (random_adaptor == NULL) { printf( diff --git a/sys/dev/random/randomdev.h b/sys/dev/random/randomdev.h index 75b2c1980901..aeb47531ae72 100644 --- a/sys/dev/random/randomdev.h +++ b/sys/dev/random/randomdev.h @@ -53,3 +53,4 @@ struct random_adaptor { extern void random_ident_hardware(struct random_adaptor **); extern void random_null_func(void); +struct random_adaptor *random_get_active_adaptor(void); diff --git a/sys/modules/random/Makefile b/sys/modules/random/Makefile index ad14899e7efc..60b62afde1d9 100644 --- a/sys/modules/random/Makefile +++ b/sys/modules/random/Makefile @@ -5,7 +5,7 @@ .PATH: ${.CURDIR}/../../crypto/sha2 KMOD= random -SRCS= randomdev.c probe.c +SRCS= randomdev.c .if ${MACHINE} == "amd64" || ${MACHINE} == "i386" SRCS+= nehemiah.c SRCS+= ivy.c