From owner-svn-src-projects@FreeBSD.ORG Sun Nov 10 16:33:17 2013 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id A2B8EB77; Sun, 10 Nov 2013 16:33:17 +0000 (UTC) (envelope-from markm@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 8CF4723A1; Sun, 10 Nov 2013 16:33:17 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rAAGXHaJ045025; Sun, 10 Nov 2013 16:33:17 GMT (envelope-from markm@svn.freebsd.org) Received: (from markm@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rAAGXFKp045009; Sun, 10 Nov 2013 16:33:15 GMT (envelope-from markm@svn.freebsd.org) Message-Id: <201311101633.rAAGXFKp045009@svn.freebsd.org> From: Mark Murray Date: Sun, 10 Nov 2013 16:33:15 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r257918 - in projects/random_number_generator/sys: conf dev/random modules modules/padlock_rng modules/random modules/rdrand_rng sys X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 10 Nov 2013 16:33:17 -0000 Author: markm Date: Sun Nov 10 16:33:14 2013 New Revision: 257918 URL: http://svnweb.freebsd.org/changeset/base/257918 Log: This counts as a pretty heavy code review, much overdue. * Simplify the code where possible; remove unneeded variables, excess macro wrapping and useless code. Tidy comments etc. * Combine common code into files; the harvest.c file was particularly confusing. * The dummy fallback is an inherent part of the device; don't pretend it is a separate module. * Attempt to make the modularisation complete. This is unfinished, in that unloading random.ko may cause panics. * Reduce excess header inclusion where this was found. * Don't unconditionally (re)seed the Yarrow device on boot; there is adequate entropy for it to start by itself with default settings. This was nasty; I managews to get an auto-seed in an unsafe state by fiddling. This is too bad of a foot-shooter to mess with. I'm now much happier with this from a security perspective. Added: projects/random_number_generator/sys/modules/padlock_rng/ projects/random_number_generator/sys/modules/padlock_rng/Makefile (contents, props changed) projects/random_number_generator/sys/modules/rdrand_rng/ projects/random_number_generator/sys/modules/rdrand_rng/Makefile (contents, props changed) Deleted: projects/random_number_generator/sys/dev/random/harvest.c Modified: projects/random_number_generator/sys/conf/files projects/random_number_generator/sys/dev/random/dummy_rng.c projects/random_number_generator/sys/dev/random/hash.c projects/random_number_generator/sys/dev/random/hash.h projects/random_number_generator/sys/dev/random/ivy.c projects/random_number_generator/sys/dev/random/live_entropy_sources.c projects/random_number_generator/sys/dev/random/live_entropy_sources.h projects/random_number_generator/sys/dev/random/nehemiah.c projects/random_number_generator/sys/dev/random/random_adaptors.c projects/random_number_generator/sys/dev/random/random_adaptors.h projects/random_number_generator/sys/dev/random/random_harvestq.c projects/random_number_generator/sys/dev/random/random_harvestq.h projects/random_number_generator/sys/dev/random/randomdev.c projects/random_number_generator/sys/dev/random/randomdev.h projects/random_number_generator/sys/dev/random/randomdev_soft.c projects/random_number_generator/sys/dev/random/randomdev_soft.h projects/random_number_generator/sys/dev/random/rwfile.c projects/random_number_generator/sys/dev/random/rwfile.h projects/random_number_generator/sys/dev/random/yarrow.c projects/random_number_generator/sys/dev/random/yarrow.h projects/random_number_generator/sys/modules/Makefile projects/random_number_generator/sys/modules/random/Makefile projects/random_number_generator/sys/sys/random.h Modified: projects/random_number_generator/sys/conf/files ============================================================================== --- projects/random_number_generator/sys/conf/files Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/conf/files Sun Nov 10 16:33:14 2013 (r257918) @@ -2040,12 +2040,11 @@ rt2860.fw optional rt2860fw | ralfw \ compile-with "${NORMAL_FW}" \ no-obj no-implicit-rule \ clean "rt2860.fw" -dev/random/harvest.c standard -dev/random/dummy_rng.c standard +dev/random/randomdev.c standard dev/random/random_adaptors.c standard +dev/random/dummy_rng.c standard dev/random/live_entropy_sources.c optional random dev/random/random_harvestq.c optional random -dev/random/randomdev.c optional random dev/random/randomdev_soft.c optional random dev/random/yarrow.c optional random dev/random/hash.c optional random Modified: projects/random_number_generator/sys/dev/random/dummy_rng.c ============================================================================== --- projects/random_number_generator/sys/dev/random/dummy_rng.c Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/dummy_rng.c Sun Nov 10 16:33:14 2013 (r257918) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2013 Arthur Mesh + * Copyright (c) 2013 Mark R V Murray * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,15 +31,16 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include -#include +#include #include #include #include #include -#include #include +#include static struct mtx dummy_random_mtx; @@ -94,7 +96,7 @@ dummy_random_deinit(void) } struct random_adaptor dummy_random = { - .ident = "Dummy entropy device that always blocks", + .ident = "Dummy entropy device", .init = dummy_random_init, .deinit = dummy_random_deinit, .block = dummy_random_block, @@ -104,21 +106,3 @@ struct random_adaptor dummy_random = { .seeded = 0, /* This device can never be seeded */ .priority = 1, /* Bottom priority, so goes to last position */ }; - -static int -dummy_random_modevent(module_t mod __unused, int type, void *unused __unused) -{ - - switch (type) { - case MOD_LOAD: - random_adaptor_register("dummy", &dummy_random); - EVENTHANDLER_INVOKE(random_adaptor_attach, - &dummy_random); - - return (0); - } - - return (EINVAL); -} - -RANDOM_ADAPTOR_MODULE(dummy, dummy_random_modevent, 1); Modified: projects/random_number_generator/sys/dev/random/hash.c ============================================================================== --- projects/random_number_generator/sys/dev/random/hash.c Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/hash.c Sun Nov 10 16:33:14 2013 (r257918) @@ -75,7 +75,7 @@ randomdev_encrypt_init(struct randomdev_ * a multiple of BLOCKSIZE. */ void -randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, unsigned length) +randomdev_encrypt(struct randomdev_key *context, void *d_in, void *d_out, u_int length) { rijndael_blockEncrypt(&context->cipher, &context->key, d_in, length*8, d_out); } Modified: projects/random_number_generator/sys/dev/random/hash.h ============================================================================== --- projects/random_number_generator/sys/dev/random/hash.h Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/hash.h Sun Nov 10 16:33:14 2013 (r257918) @@ -45,6 +45,6 @@ void randomdev_hash_init(struct randomde void randomdev_hash_iterate(struct randomdev_hash *, void *, size_t); void randomdev_hash_finish(struct randomdev_hash *, void *); void randomdev_encrypt_init(struct randomdev_key *, void *); -void randomdev_encrypt(struct randomdev_key *context, void *, void *, unsigned); +void randomdev_encrypt(struct randomdev_key *context, void *, void *, u_int); #endif Modified: projects/random_number_generator/sys/dev/random/ivy.c ============================================================================== --- projects/random_number_generator/sys/dev/random/ivy.c Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/ivy.c Sun Nov 10 16:33:14 2013 (r257918) @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -55,7 +56,7 @@ __FBSDID("$FreeBSD$"); static int random_ivy_read(void *, int); -static struct random_hardware_source random_ivy = { +static struct live_entropy_source random_ivy = { .ident = "Hardware, Intel IvyBridge+ RNG", .source = RANDOM_PURE_RDRAND, .read = random_ivy_read @@ -130,4 +131,6 @@ rdrand_modevent(module_t mod, int type, return (error); } -LIVE_ENTROPY_SRC_MODULE(random_rdrand, rdrand_modevent, 1); +DEV_MODULE(rdrand, rdrand_modevent, NULL); +MODULE_VERSION(rdrand, 1); +MODULE_DEPEND(rdrand, randomdev, 1, 1, 1); Modified: projects/random_number_generator/sys/dev/random/live_entropy_sources.c ============================================================================== --- projects/random_number_generator/sys/dev/random/live_entropy_sources.c Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/live_entropy_sources.c Sun Nov 10 16:33:14 2013 (r257918) @@ -58,7 +58,7 @@ static struct les_head sources = LIST_HE static struct sx les_lock; /* need a sleepable lock */ void -live_entropy_source_register(struct random_hardware_source *rsource) +live_entropy_source_register(struct live_entropy_source *rsource) { struct live_entropy_sources *les; @@ -73,7 +73,7 @@ live_entropy_source_register(struct rand } void -live_entropy_source_deregister(struct random_hardware_source *rsource) +live_entropy_source_deregister(struct live_entropy_source *rsource) { struct live_entropy_sources *les = NULL; @@ -93,43 +93,23 @@ live_entropy_source_deregister(struct ra static int live_entropy_source_handler(SYSCTL_HANDLER_ARGS) { + /* XXX: FIX!! Fixed array size */ + char buf[128]; struct live_entropy_sources *les; - int error, count; - - count = error = 0; + int count; sx_slock(&les_lock); - if (LIST_EMPTY(&sources)) - error = SYSCTL_OUT(req, "", 0); - else { - LIST_FOREACH(les, &sources, entries) { - - error = SYSCTL_OUT(req, ",", count++ ? 1 : 0); - if (error) - break; - - error = SYSCTL_OUT(req, les->rsource->ident, strlen(les->rsource->ident)); - if (error) - break; - } + buf[0] = '\0'; + count = 0; + LIST_FOREACH(les, &sources, entries) { + strcat(buf, (count++ ? "," : "")); + strcat(buf, les->rsource->ident); } sx_sunlock(&les_lock); - return (error); -} - -static void -live_entropy_sources_init(void *unused) -{ - - SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources, - CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, - NULL, 0, live_entropy_source_handler, "", - "List of Active Live Entropy Sources"); - - sx_init(&les_lock, "live_entropy_sources"); + return (SYSCTL_OUT(req, buf, strlen(buf))); } /* @@ -142,11 +122,15 @@ live_entropy_sources_init(void *unused) * This function runs inside the RNG thread! Don't do anything silly! * Remember that we are NOT holding harvest_mtx on entry! */ +/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle + * counters are built in, but on older hardware it will do a real time clock + * read which can be quite expensive. + */ void -live_entropy_sources_feed(int rounds, event_proc_f entropy_processor) +live_entropy_sources_feed(void) { static struct harvest event; - static uint8_t buf[HARVESTSIZE]; + static u_int dest = 0; struct live_entropy_sources *les; int i, n; @@ -158,23 +142,22 @@ live_entropy_sources_feed(int rounds, ev */ LIST_FOREACH(les, &sources, entries) { - for (i = 0; i < rounds; i++) { + /* XXX: FIX!! "2" is the number of pools in Yarrow */ + for (i = 0; i < 2; i++) { /* * This should be quick, since it's a live entropy * source. */ - /* FIXME: Whine loudly if this didn't work. */ - n = les->rsource->read(buf, sizeof(buf)); - n = MIN(n, HARVESTSIZE); - + /* XXX: FIX!! Whine loudly if this didn't work. */ + n = les->rsource->read(event.entropy, HARVESTSIZE); event.somecounter = get_cyclecount(); event.size = n; event.bits = (n*8)/2; event.source = les->rsource->source; - memcpy(event.entropy, buf, n); + event.destination = dest++; /* Do the actual entropy insertion */ - entropy_processor(&event); + harvest_process_event(&event); } } @@ -183,6 +166,18 @@ live_entropy_sources_feed(int rounds, ev } static void +live_entropy_sources_init(void *unused) +{ + + SYSCTL_PROC(_kern_random, OID_AUTO, live_entropy_sources, + CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, + NULL, 0, live_entropy_source_handler, "", + "List of Active Live Entropy Sources"); + + sx_init(&les_lock, "live_entropy_sources"); +} + +static void live_entropy_sources_deinit(void *unused) { Modified: projects/random_number_generator/sys/dev/random/live_entropy_sources.h ============================================================================== --- projects/random_number_generator/sys/dev/random/live_entropy_sources.h Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/live_entropy_sources.h Sun Nov 10 16:33:14 2013 (r257918) @@ -35,26 +35,21 @@ * specified or approximate amount of entropy immediately upon request or within * an acceptable amount of time. */ +struct live_entropy_source { + const char *ident; + enum esource source; + random_read_func_t *read; +}; + struct live_entropy_sources { LIST_ENTRY(live_entropy_sources) entries; /* list of providers */ - struct random_hardware_source *rsource; /* associated random adaptor */ + struct live_entropy_source *rsource; /* associated random adaptor */ }; extern struct mtx live_mtx; -void live_entropy_source_register(struct random_hardware_source *); -void live_entropy_source_deregister(struct random_hardware_source *); -void live_entropy_sources_feed(int, event_proc_f); - -#define LIVE_ENTROPY_SRC_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); +void live_entropy_source_register(struct live_entropy_source *); +void live_entropy_source_deregister(struct live_entropy_source *); +void live_entropy_sources_feed(void); #endif /* SYS_DEV_RANDOM_LIVE_ENTROPY_SOURCES_H_INCLUDED */ Modified: projects/random_number_generator/sys/dev/random/nehemiah.c ============================================================================== --- projects/random_number_generator/sys/dev/random/nehemiah.c Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/nehemiah.c Sun Nov 10 16:33:14 2013 (r257918) @@ -1,5 +1,6 @@ /*- * Copyright (c) 2013 Mark R V Murray + * Copyright (c) 2013 David E. O'Brien * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,6 +31,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -52,13 +54,13 @@ static void random_nehemiah_init(void); static void random_nehemiah_deinit(void); static int random_nehemiah_read(void *, int); -static struct random_hardware_source random_nehemiah = { +static struct live_entropy_source random_nehemiah = { .ident = "Hardware, VIA Nehemiah Padlock RNG", .source = RANDOM_PURE_NEHEMIAH, .read = random_nehemiah_read }; -/* TODO: now that the Davies-Meyer hash is gone and we only use +/* XXX: FIX? TODO? now that the Davies-Meyer hash is gone and we only use * the 'xstore' instruction, do we still need to preserve the * FPU state with fpu_kern_(enter|leave)() ? */ @@ -75,7 +77,7 @@ VIA_RNG_store(void *buf) #ifdef __GNUCLIKE_ASM __asm __volatile( "movl $0,%%edx\n\t" - ".byte 0x0f, 0xa7, 0xc0" /* xstore */ + "xstore" : "=a" (retval), "+d" (rate), "+D" (buf) : : "memory" @@ -154,4 +156,6 @@ nehemiah_modevent(module_t mod, int type return (error); } -LIVE_ENTROPY_SRC_MODULE(nehemiah, nehemiah_modevent, 1); +DEV_MODULE(nehemiah, nehemiah_modevent, NULL); +MODULE_VERSION(nehemiah, 1); +MODULE_DEPEND(nehemiah, randomdev, 1, 1, 1); Modified: projects/random_number_generator/sys/dev/random/random_adaptors.c ============================================================================== --- projects/random_number_generator/sys/dev/random/random_adaptors.c Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/random_adaptors.c Sun Nov 10 16:33:14 2013 (r257918) @@ -43,7 +43,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include LIST_HEAD(adaptors_head, random_adaptors); @@ -53,11 +52,11 @@ static struct sx adaptors_lock; /* need /* List for the dynamic sysctls */ static struct sysctl_ctx_list random_clist; -struct random_adaptor *random_adaptor; +struct random_adaptor *random_adaptor = NULL; MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); -int +void random_adaptor_register(const char *name, struct random_adaptor *rsp) { struct random_adaptors *rpp; @@ -72,10 +71,30 @@ random_adaptor_register(const char *name LIST_INSERT_HEAD(&adaptors, rpp, entries); sx_xunlock(&adaptors_lock); - return (0); + random_adaptor_choose(); +} + +void +random_adaptor_deregister(const char *name) +{ + struct random_adaptors *rpp; + + KASSERT(name != NULL, ("invalid input to %s", __func__)); + + sx_xlock(&adaptors_lock); + LIST_FOREACH(rpp, &adaptors, entries) + if (strcmp(rpp->name, name) == 0) { + LIST_REMOVE(rpp, entries); + break; + } + sx_xunlock(&adaptors_lock); + if (rpp != NULL) + free(rpp, M_ENTROPY); + + random_adaptor_choose(); } -struct random_adaptor * +static struct random_adaptor * random_adaptor_get(const char *name) { struct random_adaptors *rpp; @@ -95,91 +114,90 @@ random_adaptor_get(const char *name) } /* - * Walk a list of registered random(4) adaptors and pick the last non-selected - * one. - * - * If none are selected, use yarrow if available. + * Walk a list of registered random(4) adaptors and pick either a requested + * one or the highest priority one, whichever comes first. Panic on failure + * as the fallback must be the "dummy" adaptor. */ void -random_adaptor_choose(struct random_adaptor **adaptor) +random_adaptor_choose(void) { char rngs[128], *token, *cp; struct random_adaptors *rppi; - unsigned primax; + struct random_adaptor *random_adaptor_previous; + u_int primax; - KASSERT(adaptor != NULL, ("pre-conditions failed")); + random_adaptor_previous = random_adaptor; - *adaptor = NULL; + random_adaptor = NULL; if (TUNABLE_STR_FETCH("kern.random.active_adaptor", rngs, sizeof(rngs))) { cp = rngs; while ((token = strsep(&cp, ",")) != NULL) - if ((*adaptor = random_adaptor_get(token)) != NULL) + if ((random_adaptor = random_adaptor_get(token)) != NULL) { + printf("random: selecting requested adaptor <%s>\n", + random_adaptor->ident); break; - else if (bootverbose) - printf("%s random adaptor is not available," - " skipping\n", token); + } + else + printf("random: requested adaptor <%s> not available\n", + token); } - if (*adaptor == NULL) { + primax = 0U; + if (random_adaptor == NULL) { /* * Fall back to the highest priority item on the available * RNG list. */ sx_slock(&adaptors_lock); - - primax = 0U; LIST_FOREACH(rppi, &adaptors, entries) { if (rppi->rsp->priority >= primax) { + random_adaptor = rppi->rsp; primax = rppi->rsp->priority; - *adaptor = rppi->rsp; } } - sx_sunlock(&adaptors_lock); - - if (bootverbose && *adaptor) - printf("Falling back to <%s> random adaptor\n", - (*adaptor)->ident); + if (random_adaptor != NULL) + printf("random: selecting highest priority adaptor <%s>\n", + random_adaptor->ident); } -} -static void -random_adaptors_deinit(void *unused) -{ + KASSERT(random_adaptor != NULL, ("adaptor not found")); - sx_destroy(&adaptors_lock); - sysctl_ctx_free(&random_clist); + /* If we are changing adaptors, deinit the old and init the new. */ + if (random_adaptor != random_adaptor_previous) { + if (random_adaptor_previous != NULL) + (random_adaptor_previous->deinit)(); + (random_adaptor->init)(); + } } static int random_sysctl_adaptors_handler(SYSCTL_HANDLER_ARGS) { - struct random_adaptors *rpp; - int error, count; - - count = error = 0; + /* XXX: FIX!! Fixed array size, but see below, this may be OK */ + char buf[128], *pbuf; + struct random_adaptors *rpp; + int count, snp; + size_t lbuf; sx_slock(&adaptors_lock); - if (LIST_EMPTY(&adaptors)) - error = SYSCTL_OUT(req, "", 0); - else { - 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; - } + buf[0] = '\0'; + pbuf = buf; + lbuf = 256; + count = 0; + LIST_FOREACH(rpp, &adaptors, entries) { + snp = snprintf(pbuf, lbuf, "%s%s(%d)", + (count++ ? "," : ""), rpp->name, rpp->rsp->priority); + KASSERT(snp > 0, ("buffer overflow")); + lbuf -= (size_t)snp; + pbuf += snp; } sx_sunlock(&adaptors_lock); - return (error); + return (SYSCTL_OUT(req, buf, strlen(buf))); } static int @@ -211,8 +229,9 @@ random_sysctl_active_adaptor_handler(SYS return (error); } +/* ARGSUSED */ static void -random_adaptors_init(void *unused) +random_adaptors_init(void *unused __unused) { SYSCTL_PROC(_kern_random, OID_AUTO, adaptors, @@ -226,23 +245,59 @@ random_adaptors_init(void *unused) "Active Random Number Generator Adaptor"); sx_init(&adaptors_lock, "random_adaptors"); + + /* This dummy "thing" is not a module by itself, but part of the + * randomdev module. + */ + random_adaptor_register("dummy", &dummy_random); } -SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator"); +/* ARGSUSED */ +static void +random_adaptors_deinit(void *unused __unused) +{ + /* Don't do this! Panic will follow. */ + /* random_adaptor_deregister("dummy"); */ -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); + sx_destroy(&adaptors_lock); + sysctl_ctx_free(&random_clist); +} +/* XXX: FIX!! Move this to where its not so well hidden, like randomdev[_soft].c, maybe. */ +/* + * First seed. + * + * It turns out this is bloody dangerous. I was fiddling with code elsewhere + * and managed to get conditions where a safe (i.e. seeded) entropy device should + * not have been possible. This managed to hide that by seeding the device anyway. + * As crap randomness is not directly distinguishable from good randomness, this + * could have gone unnoticed for quite a while. + * + * Very luckily, the probe-time entropy is very nearly good enough to cause a + * first seed all of the time, and the default settings for interrupt- and SWI + * entropy harvesting causes a proper, safe, first (re)seed in short order + * after that. + * + * That said, the below would be useful where folks are more concerned with + * a quick start than with extra paranoia. + * + * markm - October 2013. + */ +#ifdef RANDOM_AUTOSEED +/* ARGSUSED */ static void -random_adaptors_reseed(void *unused) +random_adaptors_seed(void *unused __unused) { - - (void)unused; + if (random_adaptor != NULL) (*random_adaptor->reseed)(); arc4rand(NULL, 0, 1); } -SYSINIT(random_reseed, SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST, +SYSINIT(random_seed, SI_SUB_INTRINSIC_POST, SI_ORDER_LAST, random_adaptors_reseed, NULL); +#endif /* RANDOM_AUTOSEED */ + +SYSINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_SECOND, + random_adaptors_init, NULL); +SYSUNINIT(random_adaptors, SI_SUB_DRIVERS, SI_ORDER_SECOND, + random_adaptors_deinit, NULL); Modified: projects/random_number_generator/sys/dev/random/random_adaptors.h ============================================================================== --- projects/random_number_generator/sys/dev/random/random_adaptors.h Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/random_adaptors.h Sun Nov 10 16:33:14 2013 (r257918) @@ -29,43 +29,31 @@ #ifndef SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED #define SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED -#include - MALLOC_DECLARE(M_ENTROPY); +struct random_adaptor { + struct selinfo rsel; + const char *ident; + int seeded; + u_int priority; + random_init_func_t *init; + random_deinit_func_t *deinit; + random_block_func_t *block; + random_read_func_t *read; + random_poll_func_t *poll; + random_reseed_func_t *reseed; +}; + 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 *); -void random_adaptor_choose(struct random_adaptor **); +void random_adaptor_register(const char *, struct random_adaptor *); +void random_adaptor_deregister(const char *); +void random_adaptor_choose(void); extern struct random_adaptor *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 /* SYS_DEV_RANDOM_RANDOM_ADAPTORS_H_INCLUDED */ Modified: projects/random_number_generator/sys/dev/random/random_harvestq.c ============================================================================== --- projects/random_number_generator/sys/dev/random/random_harvestq.c Sun Nov 10 14:18:05 2013 (r257917) +++ projects/random_number_generator/sys/dev/random/random_harvestq.c Sun Nov 10 16:33:14 2013 (r257918) @@ -47,16 +47,20 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include -#include #include #include #include #include -#define RANDOM_FIFO_MAX 1024 /* How many events to queue up */ +/* + * How many events to queue up. We create this many items in + * an 'empty' queue, then transfer them to the 'harvest' queue with + * supplied junk. When used, they are transferred back to the + * 'empty' queue. + */ +#define RANDOM_FIFO_MAX 1024 /* * The harvest mutex protects the consistency of the entropy fifos and @@ -66,7 +70,6 @@ struct mtx harvest_mtx; /* Lockable FIFO queue holding entropy buffers */ struct entropyfifo { - int count; STAILQ_HEAD(harvestlist, harvest) head; }; @@ -76,6 +79,9 @@ static struct entropyfifo emptyfifo; /* Harvested entropy */ static struct entropyfifo harvestfifo; +/* Function called to process one harvested stochastic event */ +void (*harvest_process_event)(struct harvest *); + /* <0 to end the kthread, 0 to let it run, 1 to flush the harvest queues */ int random_kthread_control = 0; @@ -87,6 +93,7 @@ static struct entropy_cache { int already_read; } entropy_files[] = { { "/entropy", 0 }, + { "/var/db/entropy-file", 0 }, { "/var/db/entropy/saved-entropy.1", 0 }, { "/var/db/entropy/saved-entropy.2", 0 }, { "/var/db/entropy/saved-entropy.3", 0 }, @@ -97,53 +104,32 @@ static struct entropy_cache { { "/var/db/entropy/saved-entropy.8", 0 }, { NULL, 0 } }; -#endif /* Deal with entropy cached externally if this is present. * Lots of policy may eventually arrive in this function. - * Called after / is mounted. + * Called after any volume is mounted; this way we can keep + * looking for files in (say) /var/db/entropy/... + * + * We keep a cache of files read so we don't keep re-reading them. + * + * Optionally (a compile-time option) overwrite these files. */ static void random_harvestq_cache(void *arg1 __unused, struct mount *arg2 __unused, struct vnode *arg3 __unused, struct thread *arg4 __unused) { - static int boot_cache_read = 0; - uint8_t *keyfile, *data; - size_t size, i; -#ifdef RANDOM_RWFILE static int caches_read = 0; struct entropy_cache *entropy_file; - uint8_t *zbuf; int error; -#endif + size_t i; + uint8_t *data; - /* Get stuff that may have been preloaded by loader(8) */ - if (!boot_cache_read) { - boot_cache_read = 1; - keyfile = preload_search_by_type("/boot/entropy"); - if (keyfile != NULL) { - data = preload_fetch_addr(keyfile); - size = preload_fetch_size(keyfile); - if (data != NULL && size != 0) { - for (i = 0; i < size; i += 16) - random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); - printf("random: read %zu bytes from preloaded cache\n", size); - bzero(data, size); - } - else - if (bootverbose) - printf("random: no preloaded entropy cache\n"); - } - } - -#ifdef RANDOM_RWFILE /* Read and attempt to overwrite the entropy cache files. * If the file exists, can be read and then overwritten, * then use it. Ignore it otherwise, but print out what is * going on. */ data = malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); - zbuf = __DECONST(void *, zero_region); for (entropy_file = entropy_files; entropy_file->filename; entropy_file++) { if (entropy_file->already_read) break; @@ -151,12 +137,12 @@ random_harvestq_cache(void *arg1 __unuse if (error == 0) { printf("random: entropy cache '%s' provides %ld bytes\n", entropy_file->filename, (long)PAGE_SIZE); #ifdef RANDOM_RWFILE_WRITE_OK /* Not defined so writes disabled for now */ - error = randomdev_write_file(entropy_file->filename, zbuf, PAGE_SIZE); + error = randomdev_write_file(entropy_file->filename, zero_region, PAGE_SIZE); if (error == 0) { - printf("random: entropy cache '%s' contents used and successfully overwritten\n", entropy_file->filename); + printf("random: entropy cache '%s' successfully overwritten\n", entropy_file->filename); #endif for (i = 0; i < PAGE_SIZE; i += 16) - random_harvestq_internal(get_cyclecount(), data + i, 16, 16, RANDOM_CACHED); + random_harvestq_internal(data + i, 16, 16, RANDOM_CACHED); entropy_file->already_read = 1; caches_read++; #ifdef RANDOM_RWFILE_WRITE_OK /* Not defined so writes disabled for now */ @@ -173,21 +159,19 @@ random_harvestq_cache(void *arg1 __unuse free(data, M_ENTROPY); if (bootverbose) - printf("random: total entropy cache files read = %d\n", caches_read); -#endif + printf("random: total entropy cache files read so far = %d\n", caches_read); } +/* Invoke the above every time a FS is mounted; this way we can keep going after cached entropy */ EVENTHANDLER_DEFINE(vfs_mounted, random_harvestq_cache, NULL, 0); +#endif /* RANDOM_RWFILE */ static void -random_kthread(void *arg) +random_kthread(void *arg __unused) { STAILQ_HEAD(, harvest) local_queue; struct harvest *event = NULL; - int local_count; - event_proc_f entropy_processor = arg; STAILQ_INIT(&local_queue); - local_count = 0; /* Process until told to stop */ mtx_lock_spin(&harvest_mtx); @@ -199,8 +183,6 @@ random_kthread(void *arg) * queue for processing while not holding the mutex. */ STAILQ_CONCAT(&local_queue, &harvestfifo.head); - local_count += harvestfifo.count; - harvestfifo.count = 0; /* * Deal with events, if any. @@ -209,22 +191,16 @@ random_kthread(void *arg) if (!STAILQ_EMPTY(&local_queue)) { mtx_unlock_spin(&harvest_mtx); STAILQ_FOREACH(event, &local_queue, next) - entropy_processor(event); + harvest_process_event(event); mtx_lock_spin(&harvest_mtx); STAILQ_CONCAT(&emptyfifo.head, &local_queue); - emptyfifo.count += local_count; - local_count = 0; } - KASSERT(local_count == 0, ("random_kthread: local_count %d", - local_count)); - /* - * Do only one round of the hardware sources for now. - * Later we'll need to make it rate-adaptive. + * Give the fast hardware sources a go */ mtx_unlock_spin(&harvest_mtx); - live_entropy_sources_feed(1, entropy_processor); + live_entropy_sources_feed(); mtx_lock_spin(&harvest_mtx); /* @@ -242,14 +218,16 @@ random_kthread(void *arg) } mtx_unlock_spin(&harvest_mtx); - random_set_wakeup_exit(&random_kthread_control); + randomdev_set_wakeup_exit(&random_kthread_control); /* NOTREACHED */ } void -random_harvestq_init(event_proc_f cb) +random_harvestq_init(void (*event_processor)(struct harvest *)) { + uint8_t *keyfile, *data; int error, i; + size_t size, j; struct harvest *np; /* Initialise the harvest fifos */ @@ -260,20 +238,39 @@ random_harvestq_init(event_proc_f cb) np = malloc(sizeof(struct harvest), M_ENTROPY, M_WAITOK); STAILQ_INSERT_TAIL(&emptyfifo.head, np, next); } - emptyfifo.count = RANDOM_FIFO_MAX; /* Will contain the queued-up events. */ STAILQ_INIT(&harvestfifo.head); - harvestfifo.count = 0; + + /* Point to the correct event_processing function */ + harvest_process_event = event_processor; mtx_init(&harvest_mtx, "entropy harvest mutex", NULL, MTX_SPIN); /* Start the hash/reseed thread */ - error = kproc_create(random_kthread, cb, + error = kproc_create(random_kthread, NULL, &random_kthread_proc, RFHIGHPID, 0, "rand_harvestq"); /* RANDOM_CSPRNG_NAME */ if (error != 0) panic("Cannot create entropy maintenance thread."); + + /* Get entropy that may have been preloaded by loader(8) + * and use it to pre-charge the entropy harvest queue. + */ + keyfile = preload_search_by_type("/boot/entropy"); + if (keyfile != NULL) { + data = preload_fetch_addr(keyfile); + size = preload_fetch_size(keyfile); + if (data != NULL && size != 0) { + for (j = 0; j < size; j += 16) + random_harvestq_internal(data + j, 16, 16, RANDOM_CACHED); + printf("random: read %zu bytes from preloaded cache\n", size); + bzero(data, size); + } + else + printf("random: no preloaded entropy cache\n"); + } + } void @@ -287,13 +284,11 @@ random_harvestq_deinit(void) STAILQ_REMOVE_HEAD(&emptyfifo.head, next); free(np, M_ENTROPY); } - emptyfifo.count = 0; while (!STAILQ_EMPTY(&harvestfifo.head)) { np = STAILQ_FIRST(&harvestfifo.head); STAILQ_REMOVE_HEAD(&harvestfifo.head, next); free(np, M_ENTROPY); } - harvestfifo.count = 0; mtx_destroy(&harvest_mtx); } @@ -308,44 +303,40 @@ random_harvestq_deinit(void) * check a few lines below. This includes the "always-on" sources * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. */ +/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle + * counters are built in, but on older hardware it will do a real time clock + * read which can be quite expensive. + */ void -random_harvestq_internal(u_int64_t somecounter, const void *entropy, - u_int count, u_int bits, enum esource origin) +random_harvestq_internal(const void *entropy, u_int count, u_int bits, + enum esource origin) { + static u_int destination[ENTROPYSOURCE]; struct harvest *event; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("random_harvest_internal: origin %d invalid\n", origin)); - /* Lockless read to avoid lock operations if fifo is full. */ - if (harvestfifo.count >= RANDOM_FIFO_MAX) + /* Lockless check to avoid lock operations if queue is empty. */ + if (STAILQ_EMPTY(&emptyfifo.head)) return; mtx_lock_spin(&harvest_mtx); - /* - * On't overfill the harvest queue; this could steal all - * our memory. - */ - if (harvestfifo.count < RANDOM_FIFO_MAX) { - event = STAILQ_FIRST(&emptyfifo.head); - if (event != NULL) { - /* Add the harvested data to the fifo */ - STAILQ_REMOVE_HEAD(&emptyfifo.head, next); - emptyfifo.count--; - event->somecounter = somecounter; - event->size = count; - event->bits = bits; - event->source = origin; - - /* XXXX Come back and make this dynamic! */ - count = MIN(count, HARVESTSIZE); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***