From 67c471f7fd31c53073b5c04c9555a882a1c5a7e9 Mon Sep 17 00:00:00 2001 From: John Denker Date: Wed, 9 Oct 2013 13:46:28 -0700 Subject: total entropy available; extraload blocking pool --- drivers/char/random.c | 88 ++++++++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/char/random.c b/drivers/char/random.c index d1a0acd..157a0b3 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -428,7 +428,7 @@ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); static struct fasync_struct *fasync; -static bool debug; +static bool debug = 0; module_param(debug, bool, 0644); #define DEBUG_ENT(fmt, arg...) do { \ if (debug) \ @@ -471,11 +471,6 @@ struct entropy_store { static __u32 input_pool_data[INPUT_POOL_WORDS]; static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; static __u32 nonblocking_pool_data[OUTPUT_POOL_WORDS]; -#ifdef NOTUSED - static ulonglong uint64_zero = 0; - static ulonglong uint64_max = ~((ulonglong)0); -#endif -static ulonglong play = sizeof(ulonglong)*10000 + sizeof(ulong)*100 + sizeof(int); static struct entropy_store input_pool = { .poolinfo = &poolinfo_table[0], @@ -856,24 +851,34 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, * In principle, this would cascade, pulling from other pools * even farther upstream, but as it stands there are only two * pools, so no cascade. + * + * It is conceivable that the caller's want_level could exceed + * POOL_BYTES, and this would not be ridiculous. + * Mild fixme: Handling of this case needs more thought. */ static void fill_pool( struct entropy_store *r, - size_t want_level /* measured in bytes */ + size_t want_level /* measured in BYTES */ ){ __u32 tmp[OUTPUT_POOL_WORDS]; - int rsvd = 0; /* measured in bits */ - int mybatch = 0; + int rsvd; /* measured in bits */ + int txbits; + int mybatch; int actual; /* measured in BYTES */ - int txbits = BYTE2BIT(want_level) - r->entropy_count; - if (r->entropy_count >= r->poolinfo->POOLBITS) return; /* already full */ + int headspace = r->poolinfo->POOLBITS - r->entropy_count; if (!r->pull) return; /* no upstream pool to pull from */ if (r->limit) { - /* - * Use the values from the declarations, above. - */ - // FIXME: Think about increasing the request - // when entropy if pleniful. +/* Here if we are limited i.e. blocking i.e. /dev/random i.e. TRNG. */ + int pullhead = r->pull->poolinfo->POOLBITS - r->pull->entropy_count; +/* Only the top 500 bits are free for extraloading: */ + int extraload = 500 - pullhead; +/* Don't extraload more than needed to fill the headspace: */ + extraload = min_t(int, extraload, headspace); + txbits = BYTE2BIT(want_level) - r->entropy_count; +/* Load what is actually requested, or extraload whatever is freely available: */ + txbits = max_t(int, txbits, extraload); + if (txbits <= 0) return; /* already have all we want */ + mybatch = rsvd = 0; } else { /* * Here if we are non-limited i.e. non-blocking i.e. urandom i.e. PRNG. @@ -894,17 +899,18 @@ static void fill_pool( rsvd = rsvd - appetite*rsvd/20; if (rsvd < 0) rsvd = 0; /* For the PRNG, make the request big enough to be "significant" to any attacker: */ - mybatch = RESEED_BATCH; + mybatch = txbits = RESEED_BATCH; } - txbits = max_t(int, txbits, mybatch); - /* but never more than our buffer size */ + /* Don't request more than fits in our buffer: */ txbits = min_t(int, txbits, 8*sizeof(tmp)); - DEBUG_ENT("About to reseed %s adding %d bits; " - "caller want_level: %zu prev level: %d\n", + DEBUG_ENT("About to reseed %s adding %d bits;" + " caller want_level: %zu prev level: %d" + " batch: %d rsvd: %d\n", r->name, txbits, - want_level * 8, r->entropy_count); + want_level * 8, r->entropy_count, + BIT2BYTE(mybatch), BIT2BYTE(rsvd)); if (txbits < 0) return; /* already full enough */ actual = extract_entropy(r->pull, tmp, BIT2BYTE(txbits), @@ -1405,7 +1411,9 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) switch (cmd) { case RNDGETENTCNT: /* inherently racy, no point locking */ - if (put_user(input_pool.entropy_count, p)) + if (put_user(input_pool.entropy_count + + blocking_pool.entropy_count + + nonblocking_pool.entropy_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1536,6 +1544,15 @@ static int proc_do_uuid(struct ctl_table *table, int write, return proc_dostring(&fake_table, write, buffer, lenp, ppos); } +static int total_entropy_count; +static int sum_entropy_count(struct ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos){ + total_entropy_count = input_pool.entropy_count + + blocking_pool.entropy_count + + nonblocking_pool.entropy_count; + return proc_dointvec(table, write, buffer, lenp, ppos); +} + static int sysctl_poolsize = INPUT_POOL_WORDS * 32; extern struct ctl_table random_table[]; struct ctl_table random_table[] = { @@ -1550,6 +1567,13 @@ struct ctl_table random_table[] = { .procname = "entropy_avail", .maxlen = sizeof(int), .mode = 0444, + .proc_handler = sum_entropy_count, + .data = &total_entropy_count, + }, + { + .procname = "entropy_avail_inp", + .maxlen = sizeof(int), + .mode = 0444, .proc_handler = proc_dointvec, .data = &input_pool.entropy_count, }, @@ -1568,21 +1592,7 @@ struct ctl_table random_table[] = { .data = &nonblocking_pool.entropy_count, }, { - .procname = "play_int", - .maxlen = sizeof(ulonglong), - .mode = 0644, - .proc_handler = proc_dointvec, - .data = &play, - }, - { - .procname = "play_long", - .maxlen = sizeof(ulonglong), - .mode = 0644, - .proc_handler = proc_doulonglongvec_minmax, - .data = &play, - }, - { - .procname = "extracted_total", + .procname = "extracted_total_inp", .maxlen = sizeof(ulonglong), .mode = 0644, .proc_handler = proc_doulonglongvec_minmax, @@ -1603,7 +1613,7 @@ struct ctl_table random_table[] = { .data = &nonblocking_pool.extracted_total, }, { - .procname = "extracted_subttl", + .procname = "extracted_subttl_inp", .maxlen = sizeof(ulonglong), .mode = 0644, .proc_handler = proc_doulonglongvec_minmax, -- cgit v1.2.3