? out ? arch/amd64/conf/RNDVERBOSE ? arch/arm/xscale/.iopaau.c.swp Index: arch/amd64/include/types.h =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/include/types.h,v retrieving revision 1.40 diff -u -p -r1.40 types.h --- arch/amd64/include/types.h 4 Dec 2011 16:24:13 -0000 1.40 +++ arch/amd64/include/types.h 9 Dec 2011 03:59:21 -0000 @@ -95,7 +95,7 @@ typedef volatile unsigned char __cpu_si #define __HAVE_RAS #include "opt_xen.h" -#if defined(__x86_64__) && !defined(XEN) +#if defined(__x86_64__) && !defined(XEN) && defined(notdef) #define __HAVE_DIRECT_MAP 1 #define __HAVE_MM_MD_DIRECT_MAPPED_IO #define __HAVE_MM_MD_DIRECT_MAPPED_PHYS Index: conf/files =================================================================== RCS file: /cvsroot/src/sys/conf/files,v retrieving revision 1.1032 diff -u -p -r1.1032 files --- conf/files 19 Nov 2011 22:51:21 -0000 1.1032 +++ conf/files 9 Dec 2011 03:59:23 -0000 @@ -1439,8 +1439,9 @@ file dev/mm.c file dev/mulaw.c mulaw needs-flag file dev/nullcons_subr.c nullcons needs-flag file dev/radio.c radio needs-flag -file dev/rnd.c rnd needs-flag -file dev/rndpool.c rnd needs-flag +file dev/rnd.c +file dev/rndpool.c +file dev/rndpseudo.c rnd needs-flag file dev/sequencer.c sequencer needs-flag file dev/video.c video needs-flag file dev/vnd.c vnd needs-flag Index: crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h =================================================================== RCS file: /cvsroot/src/sys/crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h,v retrieving revision 1.1 diff -u -p -r1.1 nist_ctr_drbg_aes128.h --- crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h 19 Nov 2011 22:51:22 -0000 1.1 +++ crypto/nist_ctr_drbg/nist_ctr_drbg_aes128.h 9 Dec 2011 03:59:23 -0000 @@ -73,8 +73,8 @@ typedef NIST_AES_ENCRYPT_CTX NIST_Key; * 10.2 DRBG Mechanism Based on Block Ciphers * * Table 3 specifies the reseed interval as - * <= 2^48. We use 2^32 so we can always be sure it'll fit in an int. + * <= 2^48. We use 2^31 so we can always be sure it'll fit in an int. */ -#define NIST_CTR_DRBG_RESEED_INTERVAL (0xffffffffU) +#define NIST_CTR_DRBG_RESEED_INTERVAL (0x7fffffffU) #endif /* NIST_CTR_DRBG_AES128_H */ Index: dev/rnd.c =================================================================== RCS file: /cvsroot/src/sys/dev/rnd.c,v retrieving revision 1.88 diff -u -p -r1.88 rnd.c --- dev/rnd.c 29 Nov 2011 03:50:31 -0000 1.88 +++ dev/rnd.c 9 Dec 2011 03:59:23 -0000 @@ -118,14 +118,9 @@ kmutex_t rnd_mtx; TAILQ_HEAD(, rndsink) rnd_sinks; /* - * our select/poll queue - */ -struct selinfo rnd_selq; - -/* * Memory pool for sample buffers */ -static struct pool rnd_mempool; +static pool_cache_t rnd_mempc; /* * Our random pool. This is defined here rather than using the general @@ -159,34 +154,25 @@ static krndsource_t rnd_source_no_collec struct callout rnd_callout; -void rndattach(int); - -dev_type_open(rndopen); -dev_type_read(rndread); -dev_type_write(rndwrite); -dev_type_ioctl(rndioctl); -dev_type_poll(rndpoll); -dev_type_kqfilter(rndkqfilter); - -const struct cdevsw rnd_cdevsw = { - rndopen, nullclose, rndread, rndwrite, rndioctl, - nostop, notty, rndpoll, nommap, rndkqfilter, D_OTHER|D_MPSAFE, -}; - -static inline void rnd_wakeup_readers(void); +void rnd_wakeup_readers(void); static inline u_int32_t rnd_estimate_entropy(krndsource_t *, u_int32_t); static inline u_int32_t rnd_counter(void); static void rnd_timeout(void *); static void rnd_process_events(void *); -static u_int32_t rnd_extract_data_locked(void *, u_int32_t, u_int32_t); +u_int32_t rnd_extract_data_locked(void *, u_int32_t, u_int32_t); /* XXX */ -static int rnd_ready = 0; +int rnd_ready = 0; static int rnd_have_entropy = 0; + +#ifdef DIAGNOSTIC static int rnd_tested = 0; +static rngtest_t rnd_rt; +static uint8_t rnd_testbits[sizeof(rnd_rt.rt_b)]; +#endif LIST_HEAD(, krndsource) rnd_sources; -static rndsave_t *boot_rsp; +rndsave_t *boot_rsp; /* * Generate a 32-bit counter. This should be more machine dependent, * using cycle counters and the like when possible. @@ -211,7 +197,7 @@ rnd_counter(void) /* * Check to see if there are readers waiting on us. If so, kick them. */ -static inline void +void rnd_wakeup_readers(void) { rndsink_t *sink, *tsink; @@ -252,9 +238,7 @@ rnd_wakeup_readers(void) rndpool_get_entropy_count(&rnd_pool)); #endif rnd_have_entropy = 1; - cv_broadcast(&rndpool_cv); mutex_spin_exit(&rndpool_mtx); - selnotify(&rnd_selq, 0, 0); } else { mutex_spin_exit(&rndpool_mtx); } @@ -324,39 +308,6 @@ rnd_estimate_entropy(krndsource_t *rs, u return (1); } -static int -rnd_mempool_init(void) -{ - - pool_init(&rnd_mempool, sizeof(rnd_sample_t), 0, 0, 0, "rndsample", - NULL, IPL_VM); - return 0; -} -static ONCE_DECL(rnd_mempoolinit_ctrl); - -/* - * "Attach" the random device. This is an (almost) empty stub, since - * pseudo-devices don't get attached until after config, after the - * entropy sources will attach. We just use the timing of this event - * as another potential source of initial entropy. - */ -void -rndattach(int num) -{ - u_int32_t c; - - RUN_ONCE(&rnd_mempoolinit_ctrl, rnd_mempool_init); - - /* Trap unwary players who don't call rnd_init() early */ - KASSERT(rnd_ready); - - /* mix in another counter */ - c = rnd_counter(); - mutex_spin_enter(&rndpool_mtx); - rndpool_add_data(&rnd_pool, &c, sizeof(u_int32_t), 1); - mutex_spin_exit(&rndpool_mtx); -} - /* * initialize the global random pool for our use. * rnd_init() must be called very early on in the boot process, so @@ -384,12 +335,14 @@ rnd_init(void) LIST_INIT(&rnd_sources); SIMPLEQ_INIT(&rnd_samples); TAILQ_INIT(&rnd_sinks); - selinit(&rnd_selq); rndpool_init(&rnd_pool); mutex_init(&rndpool_mtx, MUTEX_DEFAULT, IPL_VM); cv_init(&rndpool_cv, "rndread"); + rnd_mempc = pool_cache_init(sizeof(rnd_sample_t), 0, 0, 0, + "rndsample", NULL, IPL_VM, + NULL, NULL, NULL); /* Mix *something*, *anything* into the pool to help it get started. * However, it's not safe for rnd_counter() to call microtime() yet, * so on some platforms we might just end up with zeros anyway. @@ -428,496 +381,12 @@ rnd_init(void) } } -int -rndopen(dev_t dev, int flags, int ifmt, - struct lwp *l) -{ - - if (rnd_ready == 0) - return (ENXIO); - - if (minor(dev) == RND_DEV_URANDOM || minor(dev) == RND_DEV_RANDOM) - return (0); - - return (ENXIO); -} - -int -rndread(dev_t dev, struct uio *uio, int ioflag) -{ - u_int8_t *bf; - u_int32_t entcnt, mode, n, nread; - int ret; - - DPRINTF(RND_DEBUG_READ, - ("Random: Read of %zu requested, flags 0x%08x\n", - uio->uio_resid, ioflag)); - - if (uio->uio_resid == 0) - return (0); - - switch (minor(dev)) { - case RND_DEV_RANDOM: - mode = RND_EXTRACT_GOOD; - break; - case RND_DEV_URANDOM: - mode = RND_EXTRACT_ANY; - break; - default: - /* Can't happen, but this is cheap */ - return (ENXIO); - } - - ret = 0; - bf = kmem_alloc(RND_TEMP_BUFFER_SIZE, KM_SLEEP); - while (uio->uio_resid > 0) { - n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid); - - /* - * Make certain there is data available. If there - * is, do the I/O even if it is partial. If not, - * sleep unless the user has requested non-blocking - * I/O. - * - * If not requesting strong randomness, we can always read. - */ - mutex_spin_enter(&rndpool_mtx); - if (mode != RND_EXTRACT_ANY) { - for (;;) { - /* - * How much entropy do we have? - * If it is enough for one hash, we can read. - */ - entcnt = rndpool_get_entropy_count(&rnd_pool); - if (entcnt >= RND_ENTROPY_THRESHOLD * 8) - break; - - /* - * Data is not available. - */ - if (ioflag & IO_NDELAY) { - mutex_spin_exit(&rndpool_mtx); - ret = EWOULDBLOCK; - goto out; - } - ret = cv_wait_sig(&rndpool_cv, &rndpool_mtx); - if (ret) { - mutex_spin_exit(&rndpool_mtx); - goto out; - } - } - } - nread = rnd_extract_data_locked(bf, n, mode); - mutex_spin_exit(&rndpool_mtx); - - /* - * Copy (possibly partial) data to the user. - * If an error occurs, or this is a partial - * read, bail out. - */ - ret = uiomove((void *)bf, nread, uio); - if (ret != 0 || nread != n) - goto out; - } - -out: - kmem_free(bf, RND_TEMP_BUFFER_SIZE); - return (ret); -} - -int -rndwrite(dev_t dev, struct uio *uio, int ioflag) -{ - u_int8_t *bf; - int n, ret = 0, estimate_ok = 0, estimate = 0, added = 0; - - ret = kauth_authorize_device(curlwp->l_cred, - KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL); - if (ret) { - return (ret); - } - estimate_ok = !kauth_authorize_device(curlwp->l_cred, - KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL); - - DPRINTF(RND_DEBUG_WRITE, - ("Random: Write of %zu requested\n", uio->uio_resid)); - - if (uio->uio_resid == 0) - return (0); - ret = 0; - bf = kmem_alloc(RND_TEMP_BUFFER_SIZE, KM_SLEEP); - while (uio->uio_resid > 0) { - /* - * Don't flood the pool. - */ - if (added > RND_POOLWORDS * sizeof(int)) { - printf("rnd: added %d already, adding no more.\n", - added); - break; - } - n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid); - - ret = uiomove((void *)bf, n, uio); - if (ret != 0) - break; - - if (estimate_ok) { - /* - * Don't cause samples to be discarded by taking - * the pool's entropy estimate to the max. - */ - if (added > RND_POOLWORDS / 2) - estimate = 0; - else - estimate = n * NBBY / 2; - printf("rnd: adding on write, %d bytes, estimate %d\n", - n, estimate); - } else { - printf("rnd: kauth says no entropy.\n"); - } - - /* - * Mix in the bytes. - */ - mutex_spin_enter(&rndpool_mtx); - rndpool_add_data(&rnd_pool, bf, n, estimate); - mutex_spin_exit(&rndpool_mtx); - - added += n; - DPRINTF(RND_DEBUG_WRITE, ("Random: Copied in %d bytes\n", n)); - } - kmem_free(bf, RND_TEMP_BUFFER_SIZE); - return (ret); -} - -static void -krndsource_to_rndsource(krndsource_t *kr, rndsource_t *r) -{ - memset(r, 0, sizeof(*r)); - strlcpy(r->name, kr->name, sizeof(r->name)); - r->total = kr->total; - r->type = kr->type; - r->flags = kr->flags; -} - -int -rndioctl(dev_t dev, u_long cmd, void *addr, int flag, - struct lwp *l) -{ - krndsource_t *kr; - rndstat_t *rst; - rndstat_name_t *rstnm; - rndctl_t *rctl; - rnddata_t *rnddata; - u_int32_t count, start; - int ret = 0; - int estimate_ok = 0, estimate = 0; - - switch (cmd) { - case FIONBIO: - case FIOASYNC: - case RNDGETENTCNT: - break; - - case RNDGETPOOLSTAT: - case RNDGETSRCNUM: - case RNDGETSRCNAME: - ret = kauth_authorize_device(l->l_cred, - KAUTH_DEVICE_RND_GETPRIV, NULL, NULL, NULL, NULL); - if (ret) - return (ret); - break; - - case RNDCTL: - ret = kauth_authorize_device(l->l_cred, - KAUTH_DEVICE_RND_SETPRIV, NULL, NULL, NULL, NULL); - if (ret) - return (ret); - break; - - case RNDADDDATA: - ret = kauth_authorize_device(l->l_cred, - KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL); - if (ret) - return (ret); - estimate_ok = !kauth_authorize_device(l->l_cred, - KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL); - break; - - default: - return (EINVAL); - } - - switch (cmd) { - - /* - * Handled in upper layer really, but we have to return zero - * for it to be accepted by the upper layer. - */ - case FIONBIO: - case FIOASYNC: - break; - - case RNDGETENTCNT: - mutex_spin_enter(&rndpool_mtx); - *(u_int32_t *)addr = rndpool_get_entropy_count(&rnd_pool); - mutex_spin_exit(&rndpool_mtx); - break; - - case RNDGETPOOLSTAT: - mutex_spin_enter(&rndpool_mtx); - rndpool_get_stats(&rnd_pool, addr, sizeof(rndpoolstat_t)); - mutex_spin_exit(&rndpool_mtx); - break; - - case RNDGETSRCNUM: - rst = (rndstat_t *)addr; - - if (rst->count == 0) - break; - - if (rst->count > RND_MAXSTATCOUNT) - return (EINVAL); - - /* - * Find the starting source by running through the - * list of sources. - */ - kr = rnd_sources.lh_first; - start = rst->start; - while (kr != NULL && start >= 1) { - kr = kr->list.le_next; - start--; - } - - /* - * Return up to as many structures as the user asked - * for. If we run out of sources, a count of zero - * will be returned, without an error. - */ - for (count = 0; count < rst->count && kr != NULL; count++) { - krndsource_to_rndsource(kr, &rst->source[count]); - kr = kr->list.le_next; - } - - rst->count = count; - - break; - - case RNDGETSRCNAME: - /* - * Scan through the list, trying to find the name. - */ - rstnm = (rndstat_name_t *)addr; - kr = rnd_sources.lh_first; - while (kr != NULL) { - if (strncmp(kr->name, rstnm->name, - MIN(sizeof(kr->name), - sizeof(*rstnm))) == 0) { - krndsource_to_rndsource(kr, &rstnm->source); - return (0); - } - kr = kr->list.le_next; - } - - ret = ENOENT; /* name not found */ - - break; - - case RNDCTL: - /* - * Set flags to enable/disable entropy counting and/or - * collection. - */ - rctl = (rndctl_t *)addr; - kr = rnd_sources.lh_first; - - /* - * Flags set apply to all sources of this type. - */ - if (rctl->type != 0xff) { - while (kr != NULL) { - if (kr->type == rctl->type) { - kr->flags &= ~rctl->mask; - kr->flags |= - (rctl->flags & rctl->mask); - } - kr = kr->list.le_next; - } - - return (0); - } - - /* - * scan through the list, trying to find the name - */ - while (kr != NULL) { - if (strncmp(kr->name, rctl->name, - MIN(sizeof(kr->name), - sizeof(rctl->name))) == 0) { - kr->flags &= ~rctl->mask; - kr->flags |= (rctl->flags & rctl->mask); - - return (0); - } - kr = kr->list.le_next; - } - - ret = ENOENT; /* name not found */ - - break; - - case RNDADDDATA: - /* - * Don't seed twice if our bootloader has - * seed loading support. - */ - if (!boot_rsp) { - rnddata = (rnddata_t *)addr; - - if (rnddata->len > sizeof(rnddata->data)) - return EINVAL; - - if (estimate_ok) { - /* - * Do not accept absurd entropy estimates, and - * do not flood the pool with entropy such that - * new samples are discarded henceforth. - */ - estimate = MIN((rnddata->len * NBBY) / 2, - MIN(rnddata->entropy, - RND_POOLBITS / 2)); - } else { - estimate = 0; - } - - mutex_spin_enter(&rndpool_mtx); - rndpool_add_data(&rnd_pool, rnddata->data, - rnddata->len, estimate); - mutex_spin_exit(&rndpool_mtx); - - rnd_wakeup_readers(); - } -#ifdef RND_VERBOSE - else { - printf("rnd: already seeded by boot loader\n"); - } -#endif - break; - - default: - return (EINVAL); - } - - return (ret); -} - -int -rndpoll(dev_t dev, int events, struct lwp *l) -{ - u_int32_t entcnt; - int revents; - - /* - * We are always writable. - */ - revents = events & (POLLOUT | POLLWRNORM); - - /* - * Save some work if not checking for reads. - */ - if ((events & (POLLIN | POLLRDNORM)) == 0) - return (revents); - - /* - * If the minor device is not /dev/random, we are always readable. - */ - if (minor(dev) != RND_DEV_RANDOM) { - revents |= events & (POLLIN | POLLRDNORM); - return (revents); - } - - /* - * Make certain we have enough entropy to be readable. - */ - mutex_spin_enter(&rndpool_mtx); - entcnt = rndpool_get_entropy_count(&rnd_pool); - mutex_spin_exit(&rndpool_mtx); - if (entcnt >= RND_ENTROPY_THRESHOLD * 8) - revents |= events & (POLLIN | POLLRDNORM); - else - selrecord(l, &rnd_selq); - - return (revents); -} - -static void -filt_rnddetach(struct knote *kn) -{ - mutex_spin_enter(&rndpool_mtx); - SLIST_REMOVE(&rnd_selq.sel_klist, kn, knote, kn_selnext); - mutex_spin_exit(&rndpool_mtx); -} - -static int -filt_rndread(struct knote *kn, long hint) -{ - uint32_t entcnt; - - mutex_spin_enter(&rndpool_mtx); - entcnt = rndpool_get_entropy_count(&rnd_pool); - mutex_spin_exit(&rndpool_mtx); - if (entcnt >= RND_ENTROPY_THRESHOLD * 8) { - kn->kn_data = RND_TEMP_BUFFER_SIZE; - return (1); - } - return (0); -} - -static const struct filterops rnd_seltrue_filtops = - { 1, NULL, filt_rnddetach, filt_seltrue }; - -static const struct filterops rndread_filtops = - { 1, NULL, filt_rnddetach, filt_rndread }; - -int -rndkqfilter(dev_t dev, struct knote *kn) -{ - struct klist *klist; - - switch (kn->kn_filter) { - case EVFILT_READ: - klist = &rnd_selq.sel_klist; - if (minor(dev) == RND_DEV_URANDOM) - kn->kn_fop = &rnd_seltrue_filtops; - else - kn->kn_fop = &rndread_filtops; - break; - - case EVFILT_WRITE: - klist = &rnd_selq.sel_klist; - kn->kn_fop = &rnd_seltrue_filtops; - break; - - default: - return (EINVAL); - } - - kn->kn_hook = NULL; - - mutex_spin_enter(&rndpool_mtx); - SLIST_INSERT_HEAD(klist, kn, kn_selnext); - mutex_spin_exit(&rndpool_mtx); - - return (0); -} - static rnd_sample_t * rnd_sample_allocate(krndsource_t *source) { rnd_sample_t *c; - c = pool_get(&rnd_mempool, PR_WAITOK); + c = pool_cache_get(rnd_mempc, PR_WAITOK); if (c == NULL) return (NULL); @@ -936,7 +405,7 @@ rnd_sample_allocate_isr(krndsource_t *so { rnd_sample_t *c; - c = pool_get(&rnd_mempool, PR_NOWAIT); + c = pool_cache_get(rnd_mempc, PR_NOWAIT); if (c == NULL) return (NULL); @@ -951,7 +420,7 @@ static void rnd_sample_free(rnd_sample_t *c) { memset(c, 0, sizeof(*c)); - pool_put(&rnd_mempool, c); + pool_cache_put(rnd_mempc, c); } /* @@ -963,8 +432,6 @@ rnd_attach_source(krndsource_t *rs, cons { u_int32_t ts; - RUN_ONCE(&rnd_mempoolinit_ctrl, rnd_mempool_init); - ts = rnd_counter(); strlcpy(rs->name, name, sizeof(rs->name)); @@ -1365,7 +832,7 @@ rnd_timeout(void *arg) rnd_process_events(arg); } -static u_int32_t +u_int32_t rnd_extract_data_locked(void *p, u_int32_t len, u_int32_t flags) { @@ -1381,9 +848,9 @@ rnd_extract_data_locked(void *p, u_int32 c = rnd_counter(); rndpool_add_data(&rnd_pool, &c, sizeof(u_int32_t), 1); } - if (!rnd_tested) { - rngtest_t rt; - uint8_t testbits[sizeof(rt.rt_b)]; + +#ifdef DIAGNOSTIC + while (!rnd_tested) { int entropy_count; entropy_count = rndpool_get_entropy_count(&rnd_pool); @@ -1391,8 +858,9 @@ rnd_extract_data_locked(void *p, u_int32 printf("rnd: starting statistical RNG test, entropy = %d.\n", entropy_count); #endif - if (rndpool_extract_data(&rnd_pool, rt.rt_b, - sizeof(rt.rt_b), RND_EXTRACT_ANY) != sizeof(rt.rt_b)) { + if (rndpool_extract_data(&rnd_pool, rnd_rt.rt_b, + sizeof(rnd_rt.rt_b), RND_EXTRACT_ANY) + != sizeof(rnd_rt.rt_b)) { panic("rnd: could not get bits for statistical test"); } /* @@ -1402,27 +870,30 @@ rnd_extract_data_locked(void *p, u_int32 * up adding back non-random data claiming it were pure * entropy. */ - memcpy(testbits, rt.rt_b, sizeof(rt.rt_b)); - strlcpy(rt.rt_name, "entropy pool", sizeof(rt.rt_name)); - if (rngtest(&rt)) { + memcpy(rnd_testbits, rnd_rt.rt_b, sizeof(rnd_rt.rt_b)); + strlcpy(rnd_rt.rt_name, "entropy pool", sizeof(rnd_rt.rt_name)); + if (rngtest(&rnd_rt)) { /* * The probabiliity of a Type I error is 3/10000, * but note this can only happen at boot time. * The relevant standard says to reset the module, - * so that's what we do. + * but developers objected... */ - panic("rnd: entropy pool failed statistical test"); + printf("rnd: WARNING, ENTROPY POOL FAILED " + "statistical test!\n"); + continue; } - memset(&rt, 0, sizeof(rt)); - rndpool_add_data(&rnd_pool, testbits, sizeof(testbits), + memset(&rnd_rt, 0, sizeof(rnd_rt)); + rndpool_add_data(&rnd_pool, rnd_testbits, sizeof(rnd_testbits), entropy_count); - memset(testbits, 0, sizeof(testbits)); + memset(rnd_testbits, 0, sizeof(rnd_testbits)); #ifdef RND_VERBOSE printf("rnd: statistical RNG test done, entropy = %d.\n", rndpool_get_entropy_count(&rnd_pool)); #endif rnd_tested++; } +#endif return rndpool_extract_data(&rnd_pool, p, len, flags); } Index: dev/rndpseudo.c =================================================================== RCS file: dev/rndpseudo.c diff -N dev/rndpseudo.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ dev/rndpseudo.c 9 Dec 2011 03:59:23 -0000 @@ -0,0 +1,715 @@ +/* $NetBSD: rndpseudo.c,v 1.87 2011/11/28 07:56:54 tls Exp $ */ + +/*- + * Copyright (c) 1997-2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Michael Graff and Thor Lancelot Simon. + * This code uses ideas and algorithms from the Linux driver written by + * Ted Ts'o. + * + * 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. + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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 +__KERNEL_RCSID(0, "$NetBSD: rnd.c,v 1.87 2011/11/28 07:56:54 tls Exp $"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if defined(__HAVE_CPU_COUNTER) && !defined(_RUMPKERNEL) /* XXX: bad pooka */ +#include +#endif + +#ifdef RND_DEBUG +#define DPRINTF(l,x) if (rnd_debug & (l)) printf x +int rnd_debug = 0; +#else +#define DPRINTF(l,x) +#endif + +#define RND_DEBUG_WRITE 0x0001 +#define RND_DEBUG_READ 0x0002 +#define RND_DEBUG_IOCTL 0x0004 +#define RND_DEBUG_SNOOZE 0x0008 + +/* + * list devices attached + */ +#if 0 +#define RND_VERBOSE +#endif + +/* + * The size of a temporary buffer, kmem_alloc()ed when needed, and used for + * reading and writing data. + */ +#define RND_TEMP_BUFFER_SIZE 512 + +static pool_cache_t rp_pc; +static pool_cache_t rp_cpc; + +/* + * A context. cprng plus a smidge. + */ +typedef struct { + cprng_strong_t *cprng; + int hard; +} rp_ctx_t; + +/* + * Our random pool. This is defined here rather than using the general + * purpose one defined in rndpool.c. + * + * Samples are collected and queued into a separate mutex-protected queue + * (rnd_samples, see above), and processed in a timeout routine; therefore, + * the mutex protecting the random pool is at IPL_SOFTCLOCK() as well. + */ +extern rndpool_t rnd_pool; +extern kmutex_t rndpool_mtx; + +void rndattach(int); + +dev_type_open(rndopen); + +const struct cdevsw rnd_cdevsw = { + rndopen, noclose, noread, nowrite, noioctl, nostop, + notty, nopoll, nommap, nokqfilter, D_OTHER|D_MPSAFE +}; + +static int rnd_read(struct file *, off_t *, struct uio *, kauth_cred_t, int); +static int rnd_write(struct file *, off_t *, struct uio *, kauth_cred_t, int); +static int rnd_ioctl(struct file *, u_long, void *); +static int rnd_poll(struct file *, int); +static int rnd_stat(struct file *, struct stat *); +static int rnd_close(struct file *); +static int rnd_kqfilter(struct file *, struct knote *); + +const struct fileops rnd_fileops = { + .fo_read = rnd_read, + .fo_write = rnd_write, + .fo_ioctl = rnd_ioctl, + .fo_fcntl = fnullop_fcntl, + .fo_poll = rnd_poll, + .fo_stat = rnd_stat, + .fo_close = rnd_close, + .fo_kqfilter = rnd_kqfilter, + .fo_restart = fnullop_restart +}; + +void rnd_wakeup_readers(void); /* XXX */ +extern int rnd_ready; /* XXX */ +extern rndsave_t *boot_rsp; /* XXX */ +extern LIST_HEAD(, krndsource) rnd_sources; /* XXX */ + +/* + * Generate a 32-bit counter. This should be more machine dependent, + * using cycle counters and the like when possible. + */ +static inline u_int32_t +rndpseudo_counter(void) +{ + struct timeval tv; + +#if defined(__HAVE_CPU_COUNTER) && !defined(_RUMPKERNEL) /* XXX: bad pooka */ + if (cpu_hascounter()) + return (cpu_counter32()); +#endif + microtime(&tv); + return (tv.tv_sec * 1000000 + tv.tv_usec); +} + +/* + * "Attach" the random device. This is an (almost) empty stub, since + * pseudo-devices don't get attached until after config, after the + * entropy sources will attach. We just use the timing of this event + * as another potential source of initial entropy. + */ +void +rndattach(int num) +{ + u_int32_t c; + + /* Trap unwary players who don't call rnd_init() early */ + KASSERT(rnd_ready); + + rp_pc = pool_cache_init(RND_TEMP_BUFFER_SIZE, 0, 0, 0, + "rndtemp", NULL, IPL_NONE, + NULL, NULL, NULL); + rp_cpc = pool_cache_init(sizeof(rp_ctx_t), 0, 0, 0, + "rndctx", NULL, IPL_NONE, + NULL, NULL, NULL); + + /* mix in another counter */ + c = rndpseudo_counter(); + mutex_spin_enter(&rndpool_mtx); + rndpool_add_data(&rnd_pool, &c, sizeof(u_int32_t), 1); + mutex_spin_exit(&rndpool_mtx); +} + +int +rndopen(dev_t dev, int flag, int ifmt, + struct lwp *l) +{ + rp_ctx_t *ctx; + file_t *fp; + int fd, hard, error = 0; + + switch (minor(dev)) { + case RND_DEV_URANDOM: + hard = 0; + break; + case RND_DEV_RANDOM: + hard = 1; + break; + default: + return ENXIO; + } + ctx = pool_cache_get(rp_cpc, PR_WAITOK); + ctx->cprng = NULL; + ctx->hard = hard; + + if ((error = fd_allocfile(&fp, &fd)) != 0) { + pool_cache_put(rp_cpc, ctx); + return error; + } + + return fd_clone(fp, fd, flag, &rnd_fileops, ctx); +} + +static cprng_strong_t * +rnd_alloc_cprng(rp_ctx_t *ctx) +{ + char personalization_buf[64]; + struct lwp *l = curlwp; + int cflags = ctx->hard ? CPRNG_USE_CV : + CPRNG_INIT_ANY|CPRNG_REKEY_ANY; + + snprintf(personalization_buf, sizeof(personalization_buf), + "%d%llud%p%p%d", l->l_proc->p_pid, + (unsigned long long int)l->l_ncsw, l, l->l_proc, + l->l_cpticks); + + return cprng_strong_create(personalization_buf, IPL_NONE, cflags); +} + +static int +rnd_read(struct file * fp, off_t *offp, struct uio *uio, + kauth_cred_t cred, int flags) +{ + rp_ctx_t *ctx = fp->f_data; + u_int8_t *bf; + u_int32_t n, nread; + int ret; + + DPRINTF(RND_DEBUG_READ, + ("Random: Read of %zu requested, flags 0x%08x\n", + uio->uio_resid, ioflag)); + + if (uio->uio_resid == 0) + return (0); + + if (ctx->cprng == NULL) { + ctx->cprng = rnd_alloc_cprng(ctx); + if (ctx->cprng == NULL) { + return EIO; + } + } + + ret = 0; + bf = pool_cache_get(rp_pc, PR_WAITOK); + while (uio->uio_resid > 0) { + n = MIN(RND_TEMP_BUFFER_SIZE, uio->uio_resid); + + nread = cprng_strong(ctx->cprng, bf, n, + (fp->f_flag & FNONBLOCK) ? FNONBLOCK : 0); + if (nread != n) { + if (fp->f_flag & FNONBLOCK) { + ret = EWOULDBLOCK; + } else { + ret = EINTR; + } + goto out; + } + ret = uiomove((void *)bf, nread, uio); + if (ret != 0) + goto out; + } + +out: + pool_cache_put(rp_pc, bf); + return (ret); +} + +static int +rnd_write(struct file *fp, off_t *offp, struct uio *uio, + kauth_cred_t cred, int flags) +{ + u_int8_t *bf; + int n, ret = 0, estimate_ok = 0, estimate = 0, added = 0; + + ret = kauth_authorize_device(cred, + KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL); + if (ret) { + return (ret); + } + estimate_ok = !kauth_authorize_device(cred, + KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL); + + DPRINTF(RND_DEBUG_WRITE, + ("Random: Write of %zu requested\n", uio->uio_resid)); + + if (uio->uio_resid == 0) + return (0); + ret = 0; + bf = pool_cache_get(rp_pc, PR_WAITOK); + while (uio->uio_resid > 0) { + /* + * Don't flood the pool. + */ + if (added > RND_POOLWORDS * sizeof(int)) { +#ifdef RND_VERBOSE + printf("rnd: added %d already, adding no more.\n", + added); +#endif + break; + } + n = min(RND_TEMP_BUFFER_SIZE, uio->uio_resid); + + ret = uiomove((void *)bf, n, uio); + if (ret != 0) + break; + + if (estimate_ok) { + /* + * Don't cause samples to be discarded by taking + * the pool's entropy estimate to the max. + */ + if (added > RND_POOLWORDS / 2) + estimate = 0; + else + estimate = n * NBBY / 2; +#ifdef RND_VERBOSE + printf("rnd: adding on write, %d bytes, estimate %d\n", + n, estimate); +#endif + } else { +#ifdef RND_VERBOSE + printf("rnd: kauth says no entropy.\n"); +#endif + } + + /* + * Mix in the bytes. + */ + mutex_spin_enter(&rndpool_mtx); + rndpool_add_data(&rnd_pool, bf, n, estimate); + mutex_spin_exit(&rndpool_mtx); + + added += n; + DPRINTF(RND_DEBUG_WRITE, ("Random: Copied in %d bytes\n", n)); + } + pool_cache_put(rp_pc, bf); + return (ret); +} + +static void +krndsource_to_rndsource(krndsource_t *kr, rndsource_t *r) +{ + memset(r, 0, sizeof(*r)); + strlcpy(r->name, kr->name, sizeof(r->name)); + r->total = kr->total; + r->type = kr->type; + r->flags = kr->flags; +} + +int +rnd_ioctl(struct file *fp, u_long cmd, void *addr) +{ + krndsource_t *kr; + rndstat_t *rst; + rndstat_name_t *rstnm; + rndctl_t *rctl; + rnddata_t *rnddata; + u_int32_t count, start; + int ret = 0; + int estimate_ok = 0, estimate = 0; + + switch (cmd) { + case FIONBIO: + case FIOASYNC: + case RNDGETENTCNT: + break; + + case RNDGETPOOLSTAT: + case RNDGETSRCNUM: + case RNDGETSRCNAME: + ret = kauth_authorize_device(curlwp->l_cred, + KAUTH_DEVICE_RND_GETPRIV, NULL, NULL, NULL, NULL); + if (ret) + return (ret); + break; + + case RNDCTL: + ret = kauth_authorize_device(curlwp->l_cred, + KAUTH_DEVICE_RND_SETPRIV, NULL, NULL, NULL, NULL); + if (ret) + return (ret); + break; + + case RNDADDDATA: + ret = kauth_authorize_device(curlwp->l_cred, + KAUTH_DEVICE_RND_ADDDATA, NULL, NULL, NULL, NULL); + if (ret) + return (ret); + estimate_ok = !kauth_authorize_device(curlwp->l_cred, + KAUTH_DEVICE_RND_ADDDATA_ESTIMATE, NULL, NULL, NULL, NULL); + break; + + default: + return (EINVAL); + } + + switch (cmd) { + + /* + * Handled in upper layer really, but we have to return zero + * for it to be accepted by the upper layer. + */ + case FIONBIO: + case FIOASYNC: + break; + + case RNDGETENTCNT: + mutex_spin_enter(&rndpool_mtx); + *(u_int32_t *)addr = rndpool_get_entropy_count(&rnd_pool); + mutex_spin_exit(&rndpool_mtx); + break; + + case RNDGETPOOLSTAT: + mutex_spin_enter(&rndpool_mtx); + rndpool_get_stats(&rnd_pool, addr, sizeof(rndpoolstat_t)); + mutex_spin_exit(&rndpool_mtx); + break; + + case RNDGETSRCNUM: + rst = (rndstat_t *)addr; + + if (rst->count == 0) + break; + + if (rst->count > RND_MAXSTATCOUNT) + return (EINVAL); + + mutex_spin_enter(&rndpool_mtx); + /* + * Find the starting source by running through the + * list of sources. + */ + kr = rnd_sources.lh_first; + start = rst->start; + while (kr != NULL && start >= 1) { + kr = kr->list.le_next; + start--; + } + + /* + * Return up to as many structures as the user asked + * for. If we run out of sources, a count of zero + * will be returned, without an error. + */ + for (count = 0; count < rst->count && kr != NULL; count++) { + krndsource_to_rndsource(kr, &rst->source[count]); + kr = kr->list.le_next; + } + + rst->count = count; + + mutex_spin_exit(&rndpool_mtx); + break; + + case RNDGETSRCNAME: + /* + * Scan through the list, trying to find the name. + */ + mutex_spin_enter(&rndpool_mtx); + rstnm = (rndstat_name_t *)addr; + kr = rnd_sources.lh_first; + while (kr != NULL) { + if (strncmp(kr->name, rstnm->name, + MIN(sizeof(kr->name), + sizeof(*rstnm))) == 0) { + krndsource_to_rndsource(kr, &rstnm->source); + mutex_spin_exit(&rndpool_mtx); + return (0); + } + kr = kr->list.le_next; + } + mutex_spin_exit(&rndpool_mtx); + + ret = ENOENT; /* name not found */ + + break; + + case RNDCTL: + /* + * Set flags to enable/disable entropy counting and/or + * collection. + */ + mutex_spin_enter(&rndpool_mtx); + rctl = (rndctl_t *)addr; + kr = rnd_sources.lh_first; + + /* + * Flags set apply to all sources of this type. + */ + if (rctl->type != 0xff) { + while (kr != NULL) { + if (kr->type == rctl->type) { + kr->flags &= ~rctl->mask; + kr->flags |= + (rctl->flags & rctl->mask); + } + kr = kr->list.le_next; + } + mutex_spin_exit(&rndpool_mtx); + return (0); + } + + /* + * scan through the list, trying to find the name + */ + while (kr != NULL) { + if (strncmp(kr->name, rctl->name, + MIN(sizeof(kr->name), + sizeof(rctl->name))) == 0) { + kr->flags &= ~rctl->mask; + kr->flags |= (rctl->flags & rctl->mask); + + mutex_spin_exit(&rndpool_mtx); + return (0); + } + kr = kr->list.le_next; + } + + mutex_spin_exit(&rndpool_mtx); + ret = ENOENT; /* name not found */ + + break; + + case RNDADDDATA: + /* + * Don't seed twice if our bootloader has + * seed loading support. + */ + if (!boot_rsp) { + rnddata = (rnddata_t *)addr; + + if (rnddata->len > sizeof(rnddata->data)) + return EINVAL; + + if (estimate_ok) { + /* + * Do not accept absurd entropy estimates, and + * do not flood the pool with entropy such that + * new samples are discarded henceforth. + */ + estimate = MIN((rnddata->len * NBBY) / 2, + MIN(rnddata->entropy, + RND_POOLBITS / 2)); + } else { + estimate = 0; + } + + mutex_spin_enter(&rndpool_mtx); + rndpool_add_data(&rnd_pool, rnddata->data, + rnddata->len, estimate); + mutex_spin_exit(&rndpool_mtx); + + rnd_wakeup_readers(); + } +#ifdef RND_VERBOSE + else { + printf("rnd: already seeded by boot loader\n"); + } +#endif + break; + + default: + return (EINVAL); + } + + return (ret); +} + +static int +rnd_poll(struct file *fp, int events) +{ + int revents; + rp_ctx_t *ctx = fp->f_data; + + /* + * We are always writable. + */ + revents = events & (POLLOUT | POLLWRNORM); + + /* + * Save some work if not checking for reads. + */ + if ((events & (POLLIN | POLLRDNORM)) == 0) + return (revents); + + if (ctx->cprng == NULL) { + ctx->cprng = rnd_alloc_cprng(ctx); + if (ctx->cprng == NULL) { + return EIO; + } + } + + if (cprng_strong_ready(ctx->cprng)) { + revents |= events & (POLLIN | POLLRDNORM); + } else { + mutex_enter(&ctx->cprng->mtx); + selrecord(curlwp, &ctx->cprng->selq); + mutex_exit(&ctx->cprng->mtx); + } + + return (revents); +} + +static int +rnd_stat(struct file *fp, struct stat *st) +{ + rp_ctx_t *ctx = fp->f_data; + + /* XXX lock, if cprng allocated? why? */ + memset(st, 0, sizeof(*st)); + st->st_dev = makedev(cdevsw_lookup_major(&rnd_cdevsw), + ctx->hard ? RND_DEV_RANDOM : + RND_DEV_URANDOM); + /* XXX leave atimespect, mtimespec, ctimespec = 0? */ + + st->st_uid = kauth_cred_geteuid(fp->f_cred); + st->st_gid = kauth_cred_getegid(fp->f_cred); + st->st_mode = S_IFCHR; + return 0; +} + +static int +rnd_close(struct file *fp) +{ + rp_ctx_t *ctx = fp->f_data; + + if (ctx->cprng) { + cprng_strong_destroy(ctx->cprng); + } + fp->f_data = NULL; + pool_cache_put(rp_cpc, ctx); + + return 0; +} + +static void +filt_rnddetach(struct knote *kn) +{ + cprng_strong_t *c = kn->kn_hook; + + mutex_enter(&c->mtx); + SLIST_REMOVE(&c->selq.sel_klist, kn, knote, kn_selnext); + mutex_exit(&c->mtx); +} + +static int +filt_rndread(struct knote *kn, long hint) +{ + cprng_strong_t *c = kn->kn_hook; + + if (cprng_strong_ready(c)) { + kn->kn_data = RND_TEMP_BUFFER_SIZE; + return 1; + } + return 0; +} + +static const struct filterops rnd_seltrue_filtops = + { 1, NULL, filt_rnddetach, filt_seltrue }; + +static const struct filterops rndread_filtops = + { 1, NULL, filt_rnddetach, filt_rndread }; + +static int +rnd_kqfilter(struct file *fp, struct knote *kn) +{ + rp_ctx_t *ctx = fp->f_data; + struct klist *klist; + + if (ctx->cprng == NULL) { + ctx->cprng = rnd_alloc_cprng(ctx); + if (ctx->cprng == NULL) { + return EIO; + } + } + + mutex_enter(&ctx->cprng->mtx); + switch (kn->kn_filter) { + case EVFILT_READ: + klist = &ctx->cprng->selq.sel_klist; + kn->kn_fop = &rndread_filtops; + break; + + case EVFILT_WRITE: + klist = &ctx->cprng->selq.sel_klist; + kn->kn_fop = &rnd_seltrue_filtops; + break; + + default: + mutex_exit(&ctx->cprng->mtx); + return EINVAL; + } + + kn->kn_hook = ctx->cprng; + + SLIST_INSERT_HEAD(klist, kn, kn_selnext); + + mutex_exit(&ctx->cprng->mtx); + return (0); +} Index: dev/iscsi/iscsi_text.c =================================================================== RCS file: /cvsroot/src/sys/dev/iscsi/iscsi_text.c,v retrieving revision 1.2 diff -u -p -r1.2 iscsi_text.c --- dev/iscsi/iscsi_text.c 29 Nov 2011 03:50:31 -0000 1.2 +++ dev/iscsi/iscsi_text.c 9 Dec 2011 03:59:23 -0000 @@ -1459,7 +1459,7 @@ assemble_security_parameters(connection_ cprng_strong(kern_cprng, &state->temp_buf[CHAP_MD5_SIZE], - CHAP_CHALLENGE_LEN + 1); + CHAP_CHALLENGE_LEN + 1, 0); set_key_n(state, K_Auth_CHAP_Identifier, state->temp_buf[CHAP_MD5_SIZE]); cpar = set_key_s(state, K_Auth_CHAP_Challenge, Index: dist/pf/netinet/tcp_rndiss.c =================================================================== RCS file: /cvsroot/src/sys/dist/pf/netinet/tcp_rndiss.c,v retrieving revision 1.3 diff -u -p -r1.3 tcp_rndiss.c --- dist/pf/netinet/tcp_rndiss.c 19 Nov 2011 22:51:24 -0000 1.3 +++ dist/pf/netinet/tcp_rndiss.c 9 Dec 2011 03:59:23 -0000 @@ -104,7 +104,7 @@ tcp_rndiss_encrypt(u_int16_t val) void tcp_rndiss_init(void) { - cprng_strong(kern_cprng, tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox)); + cprng_strong(kern_cprng, tcp_rndiss_sbox, sizeof(tcp_rndiss_sbox), 0); tcp_rndiss_reseed = time_second + TCP_RNDISS_OUT; tcp_rndiss_msb = tcp_rndiss_msb == 0x8000 ? 0 : 0x8000; Index: kern/init_sysctl.c =================================================================== RCS file: /cvsroot/src/sys/kern/init_sysctl.c,v retrieving revision 1.185 diff -u -p -r1.185 init_sysctl.c --- kern/init_sysctl.c 20 Nov 2011 01:09:14 -0000 1.185 +++ kern/init_sysctl.c 9 Dec 2011 03:59:24 -0000 @@ -1396,7 +1396,7 @@ sysctl_kern_urnd(SYSCTLFN_ARGS) { int v, rv; - rv = cprng_strong(sysctl_prng, &v, sizeof(v)); + rv = cprng_strong(sysctl_prng, &v, sizeof(v), 0); if (rv == sizeof(v)) { struct sysctlnode node = *rnode; node.sysctl_data = &v; Index: kern/subr_cprng.c =================================================================== RCS file: /cvsroot/src/sys/kern/subr_cprng.c,v retrieving revision 1.4 diff -u -p -r1.4 subr_cprng.c --- kern/subr_cprng.c 29 Nov 2011 21:48:22 -0000 1.4 +++ kern/subr_cprng.c 9 Dec 2011 03:59:24 -0000 @@ -72,6 +72,17 @@ cprng_counter(void) } static void +cprng_strong_sched_reseed(cprng_strong_t *const c) +{ + KASSERT(mutex_owned(&c->mtx)); + if (!(c->reseed_pending)) { + c->reseed_pending = 1; + c->reseed.len = NIST_BLOCK_KEYLEN_BYTES; + rndsink_attach(&c->reseed); + } +} + +static void cprng_strong_reseed(void *const arg) { cprng_strong_t *c = arg; @@ -91,6 +102,7 @@ cprng_strong_reseed(void *const arg) if (c->flags & CPRNG_USE_CV) { cv_broadcast(&c->cv); } + selnotify(&c->selq, 0, 0); mutex_exit(&c->mtx); } @@ -99,7 +111,7 @@ cprng_strong_create(const char *const na { cprng_strong_t *c; uint8_t key[NIST_BLOCK_KEYLEN_BYTES]; - int r, getmore = 0; + int r, getmore = 0, hard = 0; uint32_t cc; c = kmem_alloc(sizeof(*c), KM_NOSLEEP); @@ -119,6 +131,8 @@ cprng_strong_create(const char *const na cv_init(&c->cv, name); } + selinit(&c->selq); + r = rnd_extract_data(key, sizeof(key), RND_EXTRACT_GOOD); if (r != sizeof(key)) { if (c->flags & CPRNG_INIT_ANY) { @@ -127,7 +141,7 @@ cprng_strong_create(const char *const na rnd_extract_data(key + r, sizeof(key - r), RND_EXTRACT_ANY); } else { - return NULL; + hard++; } getmore++; } @@ -138,46 +152,30 @@ cprng_strong_create(const char *const na } if (getmore) { - int wr = 0; - - /* Ask for more. */ - c->reseed_pending = 1; - c->reseed.len = sizeof(key); - rndsink_attach(&c->reseed); - if (c->flags & CPRNG_USE_CV) { - mutex_enter(&c->mtx); - do { - wr = cv_wait_sig(&c->cv, &c->mtx); - if (__predict_true(wr == 0)) { - break; - } - if (wr == ERESTART) { - continue; - } else { - cv_destroy(&c->cv); - mutex_exit(&c->mtx); - mutex_destroy(&c->mtx); - kmem_free(c, sizeof(c)); - return NULL; - } - } while (1); - mutex_exit(&c->mtx); + /* Cause readers to wait for rekeying. */ + if (hard) { + c->drbg.reseed_counter = + NIST_CTR_DRBG_RESEED_INTERVAL + 1; + } else { + c->drbg.reseed_counter = + (NIST_CTR_DRBG_RESEED_INTERVAL / 2) + 1; } } return c; } size_t -cprng_strong(cprng_strong_t *const c, void *const p, size_t len) +cprng_strong(cprng_strong_t *const c, void *const p, size_t len, int flags) { uint32_t cc = cprng_counter(); - +#ifdef DEBUG + int testfail = 0; +#endif if (len > CPRNG_MAX_LEN) { /* XXX should we loop? */ len = CPRNG_MAX_LEN; /* let the caller loop if desired */ } - mutex_enter(&c->mtx); -again: + if (nist_ctr_drbg_generate(&c->drbg, p, len, &cc, sizeof(cc))) { /* A generator failure really means we hit the hard limit. */ if (c->flags & CPRNG_REKEY_ANY) { @@ -192,16 +190,15 @@ again: panic("cprng %s: nist_ctr_drbg_reseed " "failed.", c->name); } - if (c->flags & CPRNG_USE_CV) { - cv_broadcast(&c->cv); /* XXX unnecessary? */ - } } else { - if (c->flags & CPRNG_USE_CV) { + if (!(flags & FNONBLOCK) && + (c->flags & CPRNG_USE_CV)) { int wr; + cprng_strong_sched_reseed(c); do { - wr = cv_wait_sig(&c->cv, &c->mtx); - if (wr == EINTR) { + wr = cv_wait_sig(&c->cv, &c->mtx); + if (wr == ERESTART) { mutex_exit(&c->mtx); return 0; } @@ -209,49 +206,46 @@ again: len, &cc, sizeof(cc))); } else { - mutex_exit(&c->mtx); - return 0; + len = 0; } } } -#ifdef DIAGNOSTIC +#ifdef DEBUG /* * If the generator has just been keyed, perform * the statistical RNG test. */ if (__predict_false(c->drbg.reseed_counter == 1)) { - rngtest_t rt; + rngtest_t *rt = kmem_alloc(sizeof(*rt), KM_NOSLEEP); + + if (rt) { - strncpy(rt.rt_name, c->name, sizeof(rt.rt_name)); + strncpy(rt->rt_name, c->name, sizeof(rt->rt_name)); - if (nist_ctr_drbg_generate(&c->drbg, rt.rt_b, - sizeof(rt.rt_b), NULL, 0)) { - panic("cprng %s: nist_ctr_drbg_generate failed!", - c->name); + if (nist_ctr_drbg_generate(&c->drbg, rt->rt_b, + sizeof(rt->rt_b), NULL, 0)) { + panic("cprng %s: nist_ctr_drbg_generate " + "failed!", c->name); - } - if (rngtest(&rt)) { - printf("cprng %s: failed statistical RNG test.\n", - c->name); - c->drbg.reseed_counter = - NIST_CTR_DRBG_RESEED_INTERVAL + 1; - } + } + testfail = rngtest(rt); - memset(&rt, 0, sizeof(rt)); + if (testfail) { + printf("cprng %s: failed statistical RNG " + "test.\n", c->name); + c->drbg.reseed_counter = + NIST_CTR_DRBG_RESEED_INTERVAL + 1; + len = 0; + } + memset(rt, 0, sizeof(*rt)); + kmem_free(rt, sizeof(*rt)); + } } #endif if (__predict_false(c->drbg.reseed_counter > (NIST_CTR_DRBG_RESEED_INTERVAL / 2))) { - if (!(c->reseed_pending)) { - c->reseed_pending = 1; - c->reseed.len = NIST_BLOCK_KEYLEN_BYTES; - rndsink_attach(&c->reseed); - } - if (__predict_false(c->drbg.reseed_counter > - NIST_CTR_DRBG_RESEED_INTERVAL)) { - goto again; /* statistical test failure */ - } + cprng_strong_sched_reseed(c); } mutex_exit(&c->mtx); @@ -266,6 +260,7 @@ cprng_strong_destroy(cprng_strong_t *c) KASSERT(!cv_has_waiters(&c->cv)); cv_destroy(&c->cv); } + seldestroy(&c->selq); mutex_destroy(&c->mtx); if (c->reseed_pending) { @@ -302,6 +297,7 @@ cprng_strong_setflags(cprng_strong_t *co if (c->flags & CPRNG_USE_CV) { cv_broadcast(&c->cv); } + selnotify(&c->selq, 0, 0); } } c->flags = flags; Index: net/if_spppsubr.c =================================================================== RCS file: /cvsroot/src/sys/net/if_spppsubr.c,v retrieving revision 1.124 diff -u -p -r1.124 if_spppsubr.c --- net/if_spppsubr.c 19 Nov 2011 22:51:25 -0000 1.124 +++ net/if_spppsubr.c 9 Dec 2011 03:59:24 -0000 @@ -4298,7 +4298,7 @@ sppp_chap_scr(struct sppp *sp) /* Compute random challenge. */ ch = (uint32_t *)sp->myauth.challenge; - cprng_strong(kern_cprng, ch, clen); + cprng_strong(kern_cprng, ch, clen, 0); sp->confid[IDX_CHAP] = ++sp->pp_seq[IDX_CHAP]; Index: netinet/tcp_subr.c =================================================================== RCS file: /cvsroot/src/sys/netinet/tcp_subr.c,v retrieving revision 1.243 diff -u -p -r1.243 tcp_subr.c --- netinet/tcp_subr.c 19 Nov 2011 22:51:26 -0000 1.243 +++ netinet/tcp_subr.c 9 Dec 2011 03:59:24 -0000 @@ -2220,7 +2220,7 @@ tcp_new_iss1(void *laddr, void *faddr, u */ if (tcp_iss_gotten_secret == false) { cprng_strong(kern_cprng, - tcp_iss_secret, sizeof(tcp_iss_secret)); + tcp_iss_secret, sizeof(tcp_iss_secret), 0); tcp_iss_gotten_secret = true; } Index: rump/dev/lib/librnd/Makefile =================================================================== RCS file: /cvsroot/src/sys/rump/dev/lib/librnd/Makefile,v retrieving revision 1.2 diff -u -p -r1.2 Makefile --- rump/dev/lib/librnd/Makefile 16 Feb 2010 20:42:45 -0000 1.2 +++ rump/dev/lib/librnd/Makefile 9 Dec 2011 03:59:24 -0000 @@ -5,7 +5,7 @@ LIB= rumpdev_rnd -SRCS= rnd.c rndpool.c +SRCS= rnd.c rndpseudo.c rndpool.c SRCS+= component.c Index: rump/librump/rumpkern/cprng_stub.c =================================================================== RCS file: /cvsroot/src/sys/rump/librump/rumpkern/cprng_stub.c,v retrieving revision 1.3 diff -u -p -r1.3 cprng_stub.c --- rump/librump/rumpkern/cprng_stub.c 28 Nov 2011 08:05:07 -0000 1.3 +++ rump/librump/rumpkern/cprng_stub.c 9 Dec 2011 03:59:24 -0000 @@ -59,11 +59,13 @@ cprng_init(void) return; } -cprng_strong_t *cprng_strong_create(const char *const name, int ipl, int flags) +cprng_strong_t * +cprng_strong_create(const char *const name, int ipl, int flags) { cprng_strong_t *c; - c = kmem_alloc(sizeof(*c), KM_NOSLEEP); + /* zero struct to zero counters we won't ever set with no DRBG */ + c = kmem_zalloc(sizeof(*c), KM_NOSLEEP); if (c == NULL) { return NULL; } @@ -72,11 +74,13 @@ cprng_strong_t *cprng_strong_create(cons if (c->flags & CPRNG_USE_CV) { cv_init(&c->cv, name); } + selinit(&c->selq); return c; } -size_t cprng_strong(cprng_strong_t *c, void *p, size_t len) +size_t +cprng_strong(cprng_strong_t *c, void *p, size_t len, int blocking) { mutex_enter(&c->mtx); cprng_fast(p, len); /* XXX! */ @@ -84,7 +88,8 @@ size_t cprng_strong(cprng_strong_t *c, v return len; } -void cprng_strong_destroy(cprng_strong_t *c) +void +cprng_strong_destroy(cprng_strong_t *c) { mutex_destroy(&c->mtx); cv_destroy(&c->cv); Index: sys/cprng.h =================================================================== RCS file: /cvsroot/src/sys/sys/cprng.h,v retrieving revision 1.2 diff -u -p -r1.2 cprng.h --- sys/cprng.h 28 Nov 2011 08:05:07 -0000 1.2 +++ sys/cprng.h 9 Dec 2011 03:59:24 -0000 @@ -32,10 +32,12 @@ #define _CPRNG_H #include +#include #include #include #include #include +#include /* * NIST SP800-90 says 2^19 bytes per request for the CTR_DRBG. @@ -76,13 +78,14 @@ uint64_t cprng_fast64(void); #endif typedef struct _cprng_strong { - kmutex_t mtx; - kcondvar_t cv; - NIST_CTR_DRBG drbg; - int flags; - char name[16]; - int reseed_pending; - rndsink_t reseed; + kmutex_t mtx; + kcondvar_t cv; + struct selinfo selq; + NIST_CTR_DRBG drbg; + int flags; + char name[16]; + int reseed_pending; + rndsink_t reseed; } cprng_strong_t; #define CPRNG_INIT_ANY 0x00000001 @@ -91,7 +94,7 @@ typedef struct _cprng_strong { cprng_strong_t *cprng_strong_create(const char *const, int, int); -size_t cprng_strong(cprng_strong_t *const, void *const, size_t); +size_t cprng_strong(cprng_strong_t *const, void *const, size_t, int); void cprng_strong_destroy(cprng_strong_t *); @@ -101,7 +104,7 @@ static inline uint32_t cprng_strong32(void) { uint32_t r; - cprng_strong(kern_cprng, &r, sizeof(r)); + cprng_strong(kern_cprng, &r, sizeof(r), 0); return r; } @@ -109,10 +112,23 @@ static inline uint64_t cprng_strong64(void) { uint64_t r; - cprng_strong(kern_cprng, &r, sizeof(r)); + cprng_strong(kern_cprng, &r, sizeof(r), 0); return r; } +static inline int +cprng_strong_ready(cprng_strong_t *c) +{ + int ret = 0; + + mutex_enter(&c->mtx); + if (c->drbg.reseed_counter < NIST_CTR_DRBG_RESEED_INTERVAL) { + ret = 1; + } + mutex_exit(&c->mtx); + return ret; +} + void cprng_init(void); int cprng_strong_getflags(cprng_strong_t *const); void cprng_strong_setflags(cprng_strong_t *const, int); Index: sys/param.h =================================================================== RCS file: /cvsroot/src/sys/sys/param.h,v retrieving revision 1.397 diff -u -p -r1.397 param.h --- sys/param.h 28 Nov 2011 08:05:07 -0000 1.397 +++ sys/param.h 9 Dec 2011 03:59:24 -0000 @@ -63,7 +63,7 @@ * 2.99.9 (299000900) */ -#define __NetBSD_Version__ 599005800 /* NetBSD 5.99.58 */ +#define __NetBSD_Version__ 599005900 /* NetBSD 5.99.59 */ #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \ (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)