Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/random/random_harvestq.c
Show First 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | |||||
} harvest_context; | } harvest_context; | ||||
static struct kproc_desc random_proc_kp = { | static struct kproc_desc random_proc_kp = { | ||||
"rand_harvestq", | "rand_harvestq", | ||||
random_kthread, | random_kthread, | ||||
&harvest_context.hc_kthread_proc, | &harvest_context.hc_kthread_proc, | ||||
}; | }; | ||||
/* Pass the given event straight through to Fortuna/Yarrow/Whatever. */ | /* Pass the given event straight through to Fortuna/Whatever. */ | ||||
static __inline void | static __inline void | ||||
random_harvestq_fast_process_event(struct harvest_event *event) | random_harvestq_fast_process_event(struct harvest_event *event) | ||||
{ | { | ||||
#if defined(RANDOM_LOADABLE) | #if defined(RANDOM_LOADABLE) | ||||
RANDOM_CONFIG_S_LOCK(); | RANDOM_CONFIG_S_LOCK(); | ||||
if (p_random_alg_context) | if (p_random_alg_context) | ||||
#endif | #endif | ||||
p_random_alg_context->ra_event_processor(event); | p_random_alg_context->ra_event_processor(event); | ||||
Show All 21 Lines | while (harvest_context.hc_entropy_ring.out != harvest_context.hc_entropy_ring.in) { | ||||
harvest_context.hc_entropy_ring.out = ring_out; | harvest_context.hc_entropy_ring.out = ring_out; | ||||
if (!--maxloop) | if (!--maxloop) | ||||
break; | break; | ||||
} | } | ||||
random_sources_feed(); | random_sources_feed(); | ||||
/* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */ | /* XXX: FIX!! Increase the high-performance data rate? Need some measurements first. */ | ||||
for (i = 0; i < RANDOM_ACCUM_MAX; i++) { | for (i = 0; i < RANDOM_ACCUM_MAX; i++) { | ||||
if (harvest_context.hc_entropy_fast_accumulator.buf[i]) { | if (harvest_context.hc_entropy_fast_accumulator.buf[i]) { | ||||
random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), 4, RANDOM_UMA); | random_harvest_direct(harvest_context.hc_entropy_fast_accumulator.buf + i, sizeof(harvest_context.hc_entropy_fast_accumulator.buf[0]), RANDOM_UMA); | ||||
harvest_context.hc_entropy_fast_accumulator.buf[i] = 0; | harvest_context.hc_entropy_fast_accumulator.buf[i] = 0; | ||||
} | } | ||||
} | } | ||||
/* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */ | /* XXX: FIX!! This is a *great* place to pass hardware/live entropy to random(9) */ | ||||
tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1)); | tsleep_sbt(&harvest_context.hc_kthread_proc, 0, "-", SBT_1S/10, 0, C_PREL(1)); | ||||
} | } | ||||
random_kthread_control = -1; | random_kthread_control = -1; | ||||
wakeup(&harvest_context.hc_kthread_proc); | wakeup(&harvest_context.hc_kthread_proc); | ||||
kproc_exit(0); | kproc_exit(0); | ||||
/* NOTREACHED */ | /* NOTREACHED */ | ||||
} | } | ||||
/* This happens well after SI_SUB_RANDOM */ | /* This happens well after SI_SUB_RANDOM */ | ||||
SYSINIT(random_device_h_proc, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, kproc_start, | SYSINIT(random_device_h_proc, SI_SUB_KICK_SCHEDULER, SI_ORDER_ANY, kproc_start, | ||||
&random_proc_kp); | &random_proc_kp); | ||||
/* | /* | ||||
* Run through all fast sources reading entropy for the given | * Run through all fast sources reading entropy for the given | ||||
* number of rounds, which should be a multiple of the number | * number of rounds, which should be a multiple of the number | ||||
* of entropy accumulation pools in use; 2 for Yarrow and 32 | * of entropy accumulation pools in use; it is 32 for Fortuna. | ||||
* for Fortuna. | |||||
*/ | */ | ||||
static void | static void | ||||
random_sources_feed(void) | random_sources_feed(void) | ||||
{ | { | ||||
uint32_t entropy[HARVESTSIZE]; | uint32_t entropy[HARVESTSIZE]; | ||||
struct random_sources *rrs; | struct random_sources *rrs; | ||||
u_int i, n, local_read_rate; | u_int i, n, local_read_rate; | ||||
Show All 19 Lines | for (i = 0; i < p_random_alg_context->ra_poolcount*local_read_rate; i++) { | ||||
* the underlying hardware entropy source might not always return | * the underlying hardware entropy source might not always return | ||||
* random numbers. Accept this but make a noise. If too much happens, | * random numbers. Accept this but make a noise. If too much happens, | ||||
* can that source be trusted? | * can that source be trusted? | ||||
*/ | */ | ||||
if (n == 0) { | if (n == 0) { | ||||
printf("%s: rs_read for hardware device '%s' returned no entropy.\n", __func__, rrs->rrs_source->rs_ident); | printf("%s: rs_read for hardware device '%s' returned no entropy.\n", __func__, rrs->rrs_source->rs_ident); | ||||
continue; | continue; | ||||
} | } | ||||
random_harvest_direct(entropy, n, (n*8)/2, rrs->rrs_source->rs_source); | random_harvest_direct(entropy, n, rrs->rrs_source->rs_source); | ||||
} | } | ||||
} | } | ||||
explicit_bzero(entropy, sizeof(entropy)); | explicit_bzero(entropy, sizeof(entropy)); | ||||
#if defined(RANDOM_LOADABLE) | #if defined(RANDOM_LOADABLE) | ||||
} | } | ||||
RANDOM_CONFIG_S_UNLOCK(); | RANDOM_CONFIG_S_UNLOCK(); | ||||
#endif | #endif | ||||
} | } | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | random_harvestq_init(void *unused __unused) | ||||
RANDOM_HARVEST_INIT_LOCK(); | RANDOM_HARVEST_INIT_LOCK(); | ||||
harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0; | harvest_context.hc_entropy_ring.in = harvest_context.hc_entropy_ring.out = 0; | ||||
} | } | ||||
SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL); | SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_SECOND, random_harvestq_init, NULL); | ||||
/* | /* | ||||
* This is used to prime the RNG by grabbing any early random stuff | * This is used to prime the RNG by grabbing any early random stuff | ||||
* known to the kernel, and inserting it directly into the hashing | * known to the kernel, and inserting it directly into the hashing | ||||
* module, e.g. Fortuna or Yarrow. | * module, currently Fortuna. | ||||
*/ | */ | ||||
/* ARGSUSED */ | /* ARGSUSED */ | ||||
static void | static void | ||||
random_harvestq_prime(void *unused __unused) | random_harvestq_prime(void *unused __unused) | ||||
{ | { | ||||
struct harvest_event event; | struct harvest_event event; | ||||
size_t count, size, i; | size_t count, size, i; | ||||
uint8_t *keyfile, *data; | uint8_t *keyfile, *data; | ||||
Show All 17 Lines | if (keyfile != NULL) { | ||||
} | } | ||||
/* Trim the size. If the admin has a file with a funny size, we lose some. Tough. */ | /* Trim the size. If the admin has a file with a funny size, we lose some. Tough. */ | ||||
size -= (size % sizeof(event.he_entropy)); | size -= (size % sizeof(event.he_entropy)); | ||||
if (data != NULL && size != 0) { | if (data != NULL && size != 0) { | ||||
for (i = 0; i < size; i += sizeof(event.he_entropy)) { | for (i = 0; i < size; i += sizeof(event.he_entropy)) { | ||||
count = sizeof(event.he_entropy); | count = sizeof(event.he_entropy); | ||||
event.he_somecounter = (uint32_t)get_cyclecount(); | event.he_somecounter = (uint32_t)get_cyclecount(); | ||||
event.he_size = count; | event.he_size = count; | ||||
event.he_bits = count/4; /* Underestimate the size for Yarrow */ | |||||
event.he_source = RANDOM_CACHED; | event.he_source = RANDOM_CACHED; | ||||
event.he_destination = harvest_context.hc_destination[0]++; | event.he_destination = harvest_context.hc_destination[0]++; | ||||
memcpy(event.he_entropy, data + i, sizeof(event.he_entropy)); | memcpy(event.he_entropy, data + i, sizeof(event.he_entropy)); | ||||
random_harvestq_fast_process_event(&event); | random_harvestq_fast_process_event(&event); | ||||
explicit_bzero(&event, sizeof(event)); | explicit_bzero(&event, sizeof(event)); | ||||
} | } | ||||
explicit_bzero(data, size); | explicit_bzero(data, size); | ||||
if (bootverbose) | if (bootverbose) | ||||
Show All 28 Lines | |||||
* check a few lines below. This includes the "always-on" sources | * check a few lines below. This includes the "always-on" sources | ||||
* like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. | * like the Intel "rdrand" or the VIA Nehamiah "xstore" sources. | ||||
*/ | */ | ||||
/* XXXRW: get_cyclecount() is cheap on most modern hardware, where cycle | /* 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 | * counters are built in, but on older hardware it will do a real time clock | ||||
* read which can be quite expensive. | * read which can be quite expensive. | ||||
*/ | */ | ||||
void | void | ||||
random_harvest_queue_(const void *entropy, u_int size, u_int bits, | random_harvest_queue_(const void *entropy, u_int size, enum random_entropy_source origin) | ||||
enum random_entropy_source origin) | |||||
{ | { | ||||
struct harvest_event *event; | struct harvest_event *event; | ||||
u_int ring_in; | u_int ring_in; | ||||
KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); | KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); | ||||
RANDOM_HARVEST_LOCK(); | RANDOM_HARVEST_LOCK(); | ||||
ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX; | ring_in = (harvest_context.hc_entropy_ring.in + 1)%RANDOM_RING_MAX; | ||||
if (ring_in != harvest_context.hc_entropy_ring.out) { | if (ring_in != harvest_context.hc_entropy_ring.out) { | ||||
/* The ring is not full */ | /* The ring is not full */ | ||||
event = harvest_context.hc_entropy_ring.ring + ring_in; | event = harvest_context.hc_entropy_ring.ring + ring_in; | ||||
event->he_somecounter = (uint32_t)get_cyclecount(); | event->he_somecounter = (uint32_t)get_cyclecount(); | ||||
event->he_source = origin; | event->he_source = origin; | ||||
event->he_destination = harvest_context.hc_destination[origin]++; | event->he_destination = harvest_context.hc_destination[origin]++; | ||||
event->he_bits = bits; | |||||
if (size <= sizeof(event->he_entropy)) { | if (size <= sizeof(event->he_entropy)) { | ||||
event->he_size = size; | event->he_size = size; | ||||
memcpy(event->he_entropy, entropy, size); | memcpy(event->he_entropy, entropy, size); | ||||
} | } | ||||
else { | else { | ||||
/* Big event, so squash it */ | /* Big event, so squash it */ | ||||
event->he_size = sizeof(event->he_entropy[0]); | event->he_size = sizeof(event->he_entropy[0]); | ||||
event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event); | event->he_entropy[0] = jenkins_hash(entropy, size, (uint32_t)(uintptr_t)event); | ||||
} | } | ||||
harvest_context.hc_entropy_ring.in = ring_in; | harvest_context.hc_entropy_ring.in = ring_in; | ||||
} | } | ||||
RANDOM_HARVEST_UNLOCK(); | RANDOM_HARVEST_UNLOCK(); | ||||
} | } | ||||
/*- | /*- | ||||
* Entropy harvesting fast routine. | * Entropy harvesting fast routine. | ||||
* | * | ||||
* This is supposed to be very fast; do not do anything slow in here! | * This is supposed to be very fast; do not do anything slow in here! | ||||
* This is the right place for high-rate harvested data. | * This is the right place for high-rate harvested data. | ||||
*/ | */ | ||||
void | void | ||||
random_harvest_fast_(const void *entropy, u_int size, u_int bits) | random_harvest_fast_(const void *entropy, u_int size) | ||||
{ | { | ||||
u_int pos; | u_int pos; | ||||
pos = harvest_context.hc_entropy_fast_accumulator.pos; | pos = harvest_context.hc_entropy_fast_accumulator.pos; | ||||
harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, size, (uint32_t)get_cyclecount()); | harvest_context.hc_entropy_fast_accumulator.buf[pos] ^= jenkins_hash(entropy, size, (uint32_t)get_cyclecount()); | ||||
harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX; | harvest_context.hc_entropy_fast_accumulator.pos = (pos + 1)%RANDOM_ACCUM_MAX; | ||||
} | } | ||||
/*- | /*- | ||||
* Entropy harvesting direct routine. | * Entropy harvesting direct routine. | ||||
* | * | ||||
* This is not supposed to be fast, but will only be used during | * This is not supposed to be fast, but will only be used during | ||||
* (e.g.) booting when initial entropy is being gathered. | * (e.g.) booting when initial entropy is being gathered. | ||||
*/ | */ | ||||
void | void | ||||
random_harvest_direct_(const void *entropy, u_int size, u_int bits, enum random_entropy_source origin) | random_harvest_direct_(const void *entropy, u_int size, enum random_entropy_source origin) | ||||
{ | { | ||||
struct harvest_event event; | struct harvest_event event; | ||||
KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); | KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, ("%s: origin %d invalid\n", __func__, origin)); | ||||
size = MIN(size, sizeof(event.he_entropy)); | size = MIN(size, sizeof(event.he_entropy)); | ||||
event.he_somecounter = (uint32_t)get_cyclecount(); | event.he_somecounter = (uint32_t)get_cyclecount(); | ||||
event.he_size = size; | event.he_size = size; | ||||
event.he_bits = bits; | |||||
event.he_source = origin; | event.he_source = origin; | ||||
event.he_destination = harvest_context.hc_destination[origin]++; | event.he_destination = harvest_context.hc_destination[origin]++; | ||||
memcpy(event.he_entropy, entropy, size); | memcpy(event.he_entropy, entropy, size); | ||||
random_harvestq_fast_process_event(&event); | random_harvestq_fast_process_event(&event); | ||||
explicit_bzero(&event, sizeof(event)); | explicit_bzero(&event, sizeof(event)); | ||||
} | } | ||||
void | void | ||||
Show All 14 Lines |