o Fix a horrible bug where small reads (< 8 bytes) would return the

wrong bytes.

o Improve the public interface; use void* instead of char* or u_int64_t
  to pass arbitrary data around.
Submitted by:	kris ("horrible bug")
This commit is contained in:
Mark Murray 2000-07-25 21:18:47 +00:00
parent f94bf02fdb
commit 7aa4389a6c
11 changed files with 103 additions and 52 deletions

View File

@ -42,11 +42,11 @@
/* hold the address of the routine which is actually called if
* the ramdomdev is loaded
*/
static void (*reap)(struct timespec *, u_int64_t, u_int, u_int, u_int) = NULL;
static void (*reap)(struct timespec *, void *, u_int, u_int, u_int, u_int) = NULL;
/* Initialise the harvester at load time */
void
random_init_harvester(void (*reaper)(struct timespec *, u_int64_t, u_int, u_int, u_int))
random_init_harvester(void (*reaper)(struct timespec *, void *, u_int, u_int, u_int, u_int))
{
reap = reaper;
}
@ -64,12 +64,12 @@ random_deinit_harvester(void)
* the entropy device.
*/
void
random_harvest(u_int64_t entropy, u_int bits, u_int frac, u_int origin)
random_harvest(void *entropy, u_int count, u_int bits, u_int frac, u_int origin)
{
struct timespec timebuf;
if (reap) {
nanotime(&timebuf);
(*reap)(&timebuf, entropy, bits, frac, origin);
(*reap)(&timebuf, entropy, count, bits, frac, origin);
}
}

View File

@ -46,6 +46,7 @@
#include <dev/randomdev/yarrow.h>
static d_open_t random_open;
static d_read_t random_read;
static d_write_t random_write;
@ -54,7 +55,7 @@ static d_write_t random_write;
#define URANDOM_MINOR 4
static struct cdevsw random_cdevsw = {
/* open */ (d_open_t *)nullop,
/* open */ random_open,
/* close */ (d_close_t *)nullop,
/* read */ random_read,
/* write */ random_write,
@ -83,10 +84,19 @@ SYSCTL_INT(_kern_random_yarrow, OID_AUTO, bins, CTLFLAG_RW,
SYSCTL_INT(_kern_random_yarrow, OID_AUTO, fastthresh, CTLFLAG_RW,
&random_state.pool[0].thresh, 100, "Fast pool reseed threshhold");
SYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowthresh, CTLFLAG_RW,
&random_state.pool[1].thresh, 100, "Slow pool reseed threshhold");
&random_state.pool[1].thresh, 160, "Slow pool reseed threshhold");
SYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowoverthresh, CTLFLAG_RW,
&random_state.slowoverthresh, 2, "Slow pool over-threshhold reseed");
static int
random_open(dev_t dev, int flags, int fmt, struct proc *p)
{
if ((flags & FWRITE) && (securelevel > 0 || suser(p)))
return EPERM;
else
return 0;
}
static int
random_read(dev_t dev, struct uio *uio, int flag)
{

View File

@ -48,7 +48,7 @@
static void generator_gate(void);
static void reseed(int);
static void random_harvest_internal(struct timespec *, u_int64_t, u_int, u_int, enum esource);
static void random_harvest_internal(struct timespec *, void *, u_int, u_int, u_int, enum esource);
/* Structure holding the entropy state */
struct random_state random_state;
@ -216,13 +216,13 @@ reseed(int fastslow)
}
u_int
read_random(char *buf, u_int count)
read_random(void *buf, u_int count)
{
static u_int64_t genval;
static int cur = 0;
static int gate = 1;
u_int i;
u_int retval;
u_int64_t genval;
intrmask_t mask;
/* The reseed task must not be jumped on */
@ -241,7 +241,8 @@ read_random(char *buf, u_int count)
(unsigned char *)&genval,
sizeof(random_state.counter),
&random_state.key, random_state.ivec, BF_ENCRYPT);
memcpy(&buf[i], &genval, sizeof(random_state.counter));
memcpy((char *)buf + i, &genval,
sizeof(random_state.counter));
if (++random_state.outputblocks >= random_state.gengateinterval) {
generator_gate();
random_state.outputblocks = 0;
@ -268,8 +269,8 @@ read_random(char *buf, u_int count)
else {
retval = cur < count ? cur : count;
memcpy(buf,
(char *)&random_state.counter +
(sizeof(random_state.counter) - retval),
(char *)&genval +
(sizeof(random_state.counter) - cur),
retval);
cur -= retval;
}
@ -279,7 +280,7 @@ read_random(char *buf, u_int count)
}
void
write_random(char *buf, u_int count)
write_random(void *buf, u_int count)
{
u_int i;
intrmask_t mask;
@ -287,11 +288,21 @@ write_random(char *buf, u_int count)
/* The reseed task must not be jumped on */
mask = splsofttq();
for (i = 0; i < count/sizeof(u_int64_t); i++) {
/* arbitrarily break the input up into 8-byte chunks */
for (i = 0; i < count; i += 8) {
nanotime(&timebuf);
random_harvest_internal(&timebuf,
*(u_int64_t *)&buf[i*sizeof(u_int64_t)],
0, 0, RANDOM_WRITE);
random_harvest_internal(&timebuf, (char *)buf + i, 8, 0, 0,
RANDOM_WRITE);
}
/* Maybe the loop iterated at least once */
if (i > count)
i -= 8;
/* Get the last bytes even if the input length is not a multiple of 8 */
count %= 8;
if (count) {
nanotime(&timebuf);
random_harvest_internal(&timebuf, (char *)buf + i, count, 0, 0,
RANDOM_WRITE);
}
reseed(FAST);
splx(mask);
@ -329,7 +340,7 @@ generator_gate(void)
*/
static void
random_harvest_internal(struct timespec *timep, u_int64_t entropy,
random_harvest_internal(struct timespec *timep, void *entropy, u_int count,
u_int bits, u_int frac, enum esource origin)
{
u_int insert;
@ -338,6 +349,7 @@ random_harvest_internal(struct timespec *timep, u_int64_t entropy,
struct source *source;
struct pool *pool;
intrmask_t mask;
u_int64_t entropy_buf;
#ifdef DEBUG
printf("Random harvest\n");
@ -363,7 +375,12 @@ random_harvest_internal(struct timespec *timep, u_int64_t entropy,
bucket->nanotime = *timep;
/* the harvested entropy */
bucket->data = entropy;
count = count > sizeof(entropy_buf)
? sizeof(entropy_buf)
: count;
memcpy(&entropy_buf, entropy, count);
/* XOR it in to really foul up the works */
bucket->data ^= entropy_buf;
/* update the estimates - including "fractional bits" */
source->bits += bits;

View File

@ -42,10 +42,10 @@
void random_init(void);
void random_deinit(void);
void random_init_harvester(void (*)(struct timespec *, u_int64_t, u_int, u_int, enum esource));
void random_init_harvester(void (*)(struct timespec *, void *, u_int, u_int, u_int, enum esource));
void random_deinit_harvester(void);
void write_random(char *, u_int);
void write_random(void *, u_int);
/* This is the beastie that needs protecting. It contains all of the
* state that we are excited about.

View File

@ -42,11 +42,11 @@
/* hold the address of the routine which is actually called if
* the ramdomdev is loaded
*/
static void (*reap)(struct timespec *, u_int64_t, u_int, u_int, u_int) = NULL;
static void (*reap)(struct timespec *, void *, u_int, u_int, u_int, u_int) = NULL;
/* Initialise the harvester at load time */
void
random_init_harvester(void (*reaper)(struct timespec *, u_int64_t, u_int, u_int, u_int))
random_init_harvester(void (*reaper)(struct timespec *, void *, u_int, u_int, u_int, u_int))
{
reap = reaper;
}
@ -64,12 +64,12 @@ random_deinit_harvester(void)
* the entropy device.
*/
void
random_harvest(u_int64_t entropy, u_int bits, u_int frac, u_int origin)
random_harvest(void *entropy, u_int count, u_int bits, u_int frac, u_int origin)
{
struct timespec timebuf;
if (reap) {
nanotime(&timebuf);
(*reap)(&timebuf, entropy, bits, frac, origin);
(*reap)(&timebuf, entropy, count, bits, frac, origin);
}
}

View File

@ -46,6 +46,7 @@
#include <dev/randomdev/yarrow.h>
static d_open_t random_open;
static d_read_t random_read;
static d_write_t random_write;
@ -54,7 +55,7 @@ static d_write_t random_write;
#define URANDOM_MINOR 4
static struct cdevsw random_cdevsw = {
/* open */ (d_open_t *)nullop,
/* open */ random_open,
/* close */ (d_close_t *)nullop,
/* read */ random_read,
/* write */ random_write,
@ -83,10 +84,19 @@ SYSCTL_INT(_kern_random_yarrow, OID_AUTO, bins, CTLFLAG_RW,
SYSCTL_INT(_kern_random_yarrow, OID_AUTO, fastthresh, CTLFLAG_RW,
&random_state.pool[0].thresh, 100, "Fast pool reseed threshhold");
SYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowthresh, CTLFLAG_RW,
&random_state.pool[1].thresh, 100, "Slow pool reseed threshhold");
&random_state.pool[1].thresh, 160, "Slow pool reseed threshhold");
SYSCTL_INT(_kern_random_yarrow, OID_AUTO, slowoverthresh, CTLFLAG_RW,
&random_state.slowoverthresh, 2, "Slow pool over-threshhold reseed");
static int
random_open(dev_t dev, int flags, int fmt, struct proc *p)
{
if ((flags & FWRITE) && (securelevel > 0 || suser(p)))
return EPERM;
else
return 0;
}
static int
random_read(dev_t dev, struct uio *uio, int flag)
{

View File

@ -48,7 +48,7 @@
static void generator_gate(void);
static void reseed(int);
static void random_harvest_internal(struct timespec *, u_int64_t, u_int, u_int, enum esource);
static void random_harvest_internal(struct timespec *, void *, u_int, u_int, u_int, enum esource);
/* Structure holding the entropy state */
struct random_state random_state;
@ -216,13 +216,13 @@ reseed(int fastslow)
}
u_int
read_random(char *buf, u_int count)
read_random(void *buf, u_int count)
{
static u_int64_t genval;
static int cur = 0;
static int gate = 1;
u_int i;
u_int retval;
u_int64_t genval;
intrmask_t mask;
/* The reseed task must not be jumped on */
@ -241,7 +241,8 @@ read_random(char *buf, u_int count)
(unsigned char *)&genval,
sizeof(random_state.counter),
&random_state.key, random_state.ivec, BF_ENCRYPT);
memcpy(&buf[i], &genval, sizeof(random_state.counter));
memcpy((char *)buf + i, &genval,
sizeof(random_state.counter));
if (++random_state.outputblocks >= random_state.gengateinterval) {
generator_gate();
random_state.outputblocks = 0;
@ -268,8 +269,8 @@ read_random(char *buf, u_int count)
else {
retval = cur < count ? cur : count;
memcpy(buf,
(char *)&random_state.counter +
(sizeof(random_state.counter) - retval),
(char *)&genval +
(sizeof(random_state.counter) - cur),
retval);
cur -= retval;
}
@ -279,7 +280,7 @@ read_random(char *buf, u_int count)
}
void
write_random(char *buf, u_int count)
write_random(void *buf, u_int count)
{
u_int i;
intrmask_t mask;
@ -287,11 +288,21 @@ write_random(char *buf, u_int count)
/* The reseed task must not be jumped on */
mask = splsofttq();
for (i = 0; i < count/sizeof(u_int64_t); i++) {
/* arbitrarily break the input up into 8-byte chunks */
for (i = 0; i < count; i += 8) {
nanotime(&timebuf);
random_harvest_internal(&timebuf,
*(u_int64_t *)&buf[i*sizeof(u_int64_t)],
0, 0, RANDOM_WRITE);
random_harvest_internal(&timebuf, (char *)buf + i, 8, 0, 0,
RANDOM_WRITE);
}
/* Maybe the loop iterated at least once */
if (i > count)
i -= 8;
/* Get the last bytes even if the input length is not a multiple of 8 */
count %= 8;
if (count) {
nanotime(&timebuf);
random_harvest_internal(&timebuf, (char *)buf + i, count, 0, 0,
RANDOM_WRITE);
}
reseed(FAST);
splx(mask);
@ -329,7 +340,7 @@ generator_gate(void)
*/
static void
random_harvest_internal(struct timespec *timep, u_int64_t entropy,
random_harvest_internal(struct timespec *timep, void *entropy, u_int count,
u_int bits, u_int frac, enum esource origin)
{
u_int insert;
@ -338,6 +349,7 @@ random_harvest_internal(struct timespec *timep, u_int64_t entropy,
struct source *source;
struct pool *pool;
intrmask_t mask;
u_int64_t entropy_buf;
#ifdef DEBUG
printf("Random harvest\n");
@ -363,7 +375,12 @@ random_harvest_internal(struct timespec *timep, u_int64_t entropy,
bucket->nanotime = *timep;
/* the harvested entropy */
bucket->data = entropy;
count = count > sizeof(entropy_buf)
? sizeof(entropy_buf)
: count;
memcpy(&entropy_buf, entropy, count);
/* XOR it in to really foul up the works */
bucket->data ^= entropy_buf;
/* update the estimates - including "fractional bits" */
source->bits += bits;

View File

@ -42,10 +42,10 @@
void random_init(void);
void random_deinit(void);
void random_init_harvester(void (*)(struct timespec *, u_int64_t, u_int, u_int, enum esource));
void random_init_harvester(void (*)(struct timespec *, void *, u_int, u_int, u_int, enum esource));
void random_deinit_harvester(void);
void write_random(char *, u_int);
void write_random(void *, u_int);
/* This is the beastie that needs protecting. It contains all of the
* state that we are excited about.

View File

@ -2956,9 +2956,8 @@ scgetc(sc_softc_t *sc, u_int flags)
if (!(c & RELKEY))
sc_touch_scrn_saver();
/* do the /dev/random device a favour */
if (!(flags & SCGETC_CN))
random_harvest((u_int64_t)c, 1, 0, RANDOM_KEYBOARD);
random_harvest(&c, sizeof(c), 1, 0, RANDOM_KEYBOARD);
if (scp->kbd_mode != K_XLATE)
return KEYCHAR(c);

View File

@ -334,10 +334,7 @@ sysmouse_event(mouse_info_t *info)
sysmouse_tty);
}
/* do the /dev/random device a favour */
/* The nasty-looking cast is to force treatment of 8 u_chars */
/* in buf as a u_int64_t */
random_harvest(*((u_int64_t *)buf), 2, 0, RANDOM_MOUSE);
random_harvest(buf, sizeof(buf), 2, 0, RANDOM_MOUSE);
return mouse_status.flags;
}

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2000 Mark Murray
* Copyright (c) 2000 Mark R. V. Murray
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -31,10 +31,11 @@
#ifdef _KERNEL
u_int read_random(char *, u_int);
u_int read_random(void *, u_int);
enum esource { RANDOM_WRITE, RANDOM_KEYBOARD, RANDOM_MOUSE, ENTROPYSOURCE };
void random_harvest(u_int64_t, u_int, u_int, enum esource);
enum esource { RANDOM_WRITE, RANDOM_KEYBOARD, RANDOM_MOUSE, RANDOM_NET, \
ENTROPYSOURCE };
void random_harvest(void *, u_int, u_int, u_int, enum esource);
#endif