diff options
| author | Mark Murray <markm@FreeBSD.org> | 2014-10-30 21:21:53 +0000 |
|---|---|---|
| committer | Mark Murray <markm@FreeBSD.org> | 2014-10-30 21:21:53 +0000 |
| commit | 10cb24248a6f13974e11c255c8014cfefe6420a7 (patch) | |
| tree | d5dfa61a018a7d209b25f173c6ee76709037035a /sys/dev/random/randomdev.c | |
| parent | 39d22d86ab05fb09689a9882909dfd35ab546ade (diff) | |
Notes
Diffstat (limited to 'sys/dev/random/randomdev.c')
| -rw-r--r-- | sys/dev/random/randomdev.c | 271 |
1 files changed, 145 insertions, 126 deletions
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c index b76cb839a02c..bc41d511a8f1 100644 --- a/sys/dev/random/randomdev.c +++ b/sys/dev/random/randomdev.c @@ -26,9 +26,28 @@ * */ +/* + * NOTE NOTE NOTE + * + * This file is compiled into the kernel unconditionally. Any random(4) + * infrastructure that needs to be in the kernel by default goes here! + * + * Except ... + * + * The adaptor code all goes into random_adaptor.c, which is also compiled + * the kernel by default. The module in that file is initialised before + * this one. + * + * Other modules must be initialised after the above two, and are + * software random processors which plug into random_adaptor.c. + * + */ + #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); +#include "opt_random.h" + #include <sys/param.h> #include <sys/systm.h> #include <sys/bus.h> @@ -38,196 +57,196 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/kthread.h> #include <sys/lock.h> -#include <sys/malloc.h> #include <sys/module.h> -#include <sys/mutex.h> -#include <sys/poll.h> -#include <sys/priv.h> +#include <sys/malloc.h> #include <sys/proc.h> #include <sys/random.h> -#include <sys/selinfo.h> +#include <sys/sysctl.h> +#include <sys/systm.h> #include <sys/uio.h> #include <sys/unistd.h> -#include <machine/bus.h> -#include <machine/cpu.h> - #include <dev/random/randomdev.h> -#include <dev/random/randomdev_soft.h> #include <dev/random/random_adaptors.h> #include <dev/random/random_harvestq.h> -#include <dev/random/live_entropy_sources.h> #define RANDOM_MINOR 0 -static d_read_t random_read; -static d_write_t random_write; -static d_ioctl_t random_ioctl; -static d_poll_t random_poll; +static d_ioctl_t randomdev_ioctl; static struct cdevsw random_cdevsw = { - .d_version = D_VERSION, - .d_read = random_read, - .d_write = random_write, - .d_ioctl = random_ioctl, - .d_poll = random_poll, .d_name = "random", + .d_version = D_VERSION, + .d_read = random_adaptor_read, + .d_write = random_adaptor_write, + .d_poll = random_adaptor_poll, + .d_ioctl = randomdev_ioctl, }; /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *random_dev; +/* Set up the sysctl root node for the entropy device */ +SYSCTL_NODE(_kern, OID_AUTO, random, CTLFLAG_RW, 0, "Random Number Generator"); + +MALLOC_DEFINE(M_ENTROPY, "entropy", "Entropy harvesting buffers and data structures"); + /* ARGSUSED */ static int -random_read(struct cdev *dev __unused, struct uio *uio, int flag) +randomdev_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, + int flags __unused, struct thread *td __unused) { - int c, error = 0; - void *random_buf; - - /* Blocking logic */ - if (!random_adaptor->seeded) - error = (*random_adaptor->block)(flag); - - /* The actual read */ - if (!error) { - - random_buf = (void *)malloc(PAGE_SIZE, M_ENTROPY, M_WAITOK); + int error = 0; - while (uio->uio_resid > 0 && !error) { - c = MIN(uio->uio_resid, PAGE_SIZE); - c = (*random_adaptor->read)(random_buf, c); - error = uiomove(random_buf, c, uio); - } - /* Finished reading; let the source know so it can do some - * optional housekeeping */ - (*random_adaptor->read)(NULL, 0); + switch (cmd) { + /* Really handled in upper layer */ + case FIOASYNC: + case FIONBIO: + break; - free(random_buf, M_ENTROPY); + default: + error = ENOTTY; } return (error); } -/* ARGSUSED */ -static int -random_write(struct cdev *dev __unused, struct uio *uio, int flag __unused) +/* Helper routine to enable kproc_exit() to work while the module is + * being (or has been) unloaded. + * This routine is in this file because it is always linked into the kernel, + * and will thus never be unloaded. This is critical for unloadable modules + * that have threads. + */ +void +randomdev_set_wakeup_exit(void *control) { - /* We used to allow this to insert userland entropy. - * We don't any more because (1) this so-called entropy - * is usually lousy and (b) its vaguely possible to - * mess with entropy harvesting by overdoing a write. - * Now we just ignore input like /dev/null does. - */ - uio->uio_resid = 0; - - return (0); + wakeup(control); + kproc_exit(0); + /* NOTREACHED */ } /* ARGSUSED */ static int -random_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr __unused, - int flags __unused, struct thread *td __unused) +randomdev_modevent(module_t mod __unused, int type, void *data __unused) { int error = 0; - switch (cmd) { - /* Really handled in upper layer */ - case FIOASYNC: - case FIONBIO: + switch (type) { + case MOD_LOAD: + printf("random: entropy device infrastructure driver\n"); + random_dev = make_dev_credf(MAKEDEV_ETERNAL_KLD, &random_cdevsw, + RANDOM_MINOR, NULL, UID_ROOT, GID_WHEEL, 0644, "random"); + make_dev_alias(random_dev, "urandom"); /* compatibility */ + random_adaptors_init(); break; + + case MOD_UNLOAD: + random_adaptors_deinit(); + destroy_dev(random_dev); + break; + + case MOD_SHUTDOWN: + break; + default: - error = ENOTTY; + error = EOPNOTSUPP; + break; + } + return (error); } -/* ARGSUSED */ -static int -random_poll(struct cdev *dev __unused, int events, struct thread *td) -{ - int revents = 0; +#define EARLY_2_DEV_MODULE(name, evh, arg) \ +static moduledata_t name##_mod = { \ + #name, \ + evh, \ + arg \ +}; \ +DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND) - if (events & (POLLIN | POLLRDNORM)) { - if (random_adaptor->seeded) - revents = events & (POLLIN | POLLRDNORM); - else - revents = (*random_adaptor->poll)(events, td); - } - return (revents); -} +EARLY_2_DEV_MODULE(randomdev, randomdev_modevent, NULL); +MODULE_VERSION(randomdev, 1); + +/* ================ + * Harvesting stubs + * ================ + */ +/* Internal stub/fake routine for when no entropy processor is loaded. + * If the entropy device is not loaded, don't act on harvesting calls + * and just return. + */ +/* ARGSUSED */ static void -random_initialize(void *p, struct random_adaptor *s) +random_harvest_phony(const void *entropy __unused, u_int count __unused, + u_int bits __unused, enum random_entropy_source origin __unused) { - static int random_inited = 0; - - if (random_inited) { - printf("random: <%s> already initialized\n", - random_adaptor->ident); - return; - } +} - random_adaptor = s; +/* Hold the address of the routine which is actually called */ +static void (*reap_func)(const void *, u_int, u_int, enum random_entropy_source) = random_harvest_phony; - (s->init)(); +/* Initialise the harvester when/if it is loaded */ +void +randomdev_init_harvester(void (*reaper)(const void *, u_int, u_int, enum random_entropy_source)) +{ - printf("random: <%s> initialized\n", s->ident); + reap_func = reaper; +} - /* Use an appropriately evil mode for those who are concerned - * with daemons */ - 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"); /* compatibility */ +/* Deinitialise the harvester when/if it is unloaded */ +void +randomdev_deinit_harvester(void) +{ - /* mark random(4) as initialized, to avoid being called again */ - random_inited = 1; + reap_func = random_harvest_phony; } -/* ARGSUSED */ -static int -random_modevent(module_t mod __unused, int type, void *data __unused) +/* Entropy harvesting routine. + * Implemented as in indirect call to allow non-inclusion of + * the entropy device. + */ +void +random_harvest(const void *entropy, u_int count, u_int bits, enum random_entropy_source origin) { - static eventhandler_tag attach_tag = NULL; - int error = 0; - - switch (type) { - case MOD_LOAD: - random_adaptor_choose(&random_adaptor); - if (random_adaptor == NULL) { - printf("random: No random adaptor attached, " - "postponing initialization\n"); - attach_tag = EVENTHANDLER_REGISTER(random_adaptor_attach, - random_initialize, NULL, EVENTHANDLER_PRI_ANY); - } else - random_initialize(NULL, random_adaptor); + (*reap_func)(entropy, count, bits, origin); +} - break; +/* ================================ + * Internal reading stubs and fakes + * ================================ + */ - case MOD_UNLOAD: - if (random_adaptor != NULL) { - (*random_adaptor->deinit)(); - destroy_dev(random_dev); - } - /* Unregister the event handler */ - if (attach_tag != NULL) - EVENTHANDLER_DEREGISTER(random_adaptor_attach, - attach_tag); +/* Hold the address of the routine which is actually called */ +static u_int (*read_func)(uint8_t *, u_int) = dummy_random_read_phony; - break; +/* Initialise the reader when/if it is loaded */ +void +randomdev_init_reader(u_int (*reader)(uint8_t *, u_int)) +{ - case MOD_SHUTDOWN: - break; + read_func = reader; +} - default: - error = EOPNOTSUPP; - break; +/* Deinitialise the reader when/if it is unloaded */ +void +randomdev_deinit_reader(void) +{ - } - return (error); + read_func = dummy_random_read_phony; } -DEV_MODULE(random, random_modevent, NULL); -MODULE_VERSION(random, 1); +/* Kernel API version of read_random(). + * Implemented as in indirect call to allow non-inclusion of + * the entropy device. + */ +int +read_random(void *buf, int count) +{ + + return ((int)(*read_func)(buf, (u_int)count)); +} |
