summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Denker <jsd@av8n.com>2013-10-07 20:23:25 -0700
committerJohn Denker <jsd@av8n.com>2013-10-18 05:19:10 -0700
commit17cdcc57fab1a27229751d2ddde59ee1f3749af8 (patch)
tree8e9a16923cd3cb241ac4e342d937a26f358766db
parentc121dfb5fe8e49c2f4d867730c001a337f6d2813 (diff)
first attempt to make urandom less voracious;
also add scheme for looking at critical variables
-rw-r--r--drivers/char/random.c124
1 files changed, 113 insertions, 11 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 0d91fe5..e526d63 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -277,13 +277,28 @@
#define SEC_XFER_SIZE 512
#define EXTRACT_SIZE 10
+/* Choose 160 bits. Seems reasonable. Recommended in the Yarrow paper. */
+#define RESEED_BATCH 160 /* bits */
+
+/*
+ * The nonblocking output pool will not drag the input pool below this
+ * fill fraction:
+ */
+#define FILL_FRAC(X) ((X)*3/4)
+
#define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long))
+#define W2BYTE(X) ((X)*4) /* convert #words to #bytes */
+#define W2BIT(X) ((X)*32) /* convert #words to #bits */
+#define BIT2BYTE(X) ((X)/8) /* convert #bits to #bytes */
+#define BYTE2BIT(X) ((X)*8) /* convert #bytes to #bits */
/*
* The minimum number of bits of entropy before we wake up a read on
- * /dev/random. Should be enough to do a significant reseed.
+ * /dev/random.
+ * Can be changed at runtime via /proc/.
+ * The minimum value is RESEED_BATCH; enforced at runtime.
*/
-static int random_read_wakeup_thresh = 64;
+static int random_read_wakeup_thresh = RESEED_BATCH;
/*
* If the entropy count falls under this number of bits, then we
@@ -431,7 +446,9 @@ struct entropy_store {
unsigned add_ptr;
unsigned input_rotate;
int entropy_count;
- int entropy_total;
+ int entropy_total; /* entropy input; used only during initialization */
+ uint64_t extracted_subttl;
+ uint64_t extracted_total;
unsigned int initialized:1;
bool last_data_init;
__u8 last_data[EXTRACT_SIZE];
@@ -440,6 +457,11 @@ 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 uint64_t uint64_zero = 0;
+ static uint64_t uint64_max = ~((uint64_t)0);
+#endif
+static uint64_t play = sizeof(uint64_t)*10000 + sizeof(ulong)*100 + sizeof(int);
static struct entropy_store input_pool = {
.poolinfo = &poolinfo_table[0],
@@ -816,12 +838,12 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
if (r->pull && r->entropy_count < nbytes * 8 &&
r->entropy_count < r->poolinfo->POOLBITS) {
- /* If we're limited, always leave two wakeup worth's BITS */
- int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
+ /* If we're non-blocking, protect the reserved amount of entropy: */
+ int rsvd = r->limit ? 0 : FILL_FRAC(W2BYTE(r->pull->poolinfo->poolwords));
int bytes = nbytes;
- /* pull at least as many as BYTES as wakeup BITS */
- bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
+ /* Request a big-enough batch: */
+ bytes = max_t(int, bytes, BIT2BYTE(RESEED_BATCH));
/* but never more than the buffer size */
bytes = min_t(int, bytes, sizeof(tmp));
@@ -829,8 +851,7 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
"(%zu of %d requested)\n",
r->name, bytes * 8, nbytes * 8, r->entropy_count);
- bytes = extract_entropy(r->pull, tmp, bytes,
- random_read_wakeup_thresh / 8, rsvd);
+ bytes = extract_entropy(r->pull, tmp, bytes, BIT2BYTE(RESEED_BATCH), rsvd);
mix_pool_bytes(r, tmp, bytes, NULL);
credit_entropy_bits(r, bytes*8);
}
@@ -1007,6 +1028,10 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
/* Wipe data just returned from memory */
memset(tmp, 0, sizeof(tmp));
+ if (ret > 0) {
+ r->extracted_subttl += BYTE2BIT(ret);
+ r->extracted_total += BYTE2BIT(ret);
+ }
return ret;
}
@@ -1045,6 +1070,10 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
/* Wipe data just returned from memory */
memset(tmp, 0, sizeof(tmp));
+ if (ret > 0) {
+ r->extracted_subttl += BYTE2BIT(ret);
+ r->extracted_total += BYTE2BIT(ret);
+ }
return ret;
}
@@ -1081,7 +1110,7 @@ void get_random_bytes_arch(void *buf, int nbytes)
if (!arch_get_random_long(&v))
break;
-
+
memcpy(p, &v, chunk);
p += chunk;
nbytes -= chunk;
@@ -1110,6 +1139,8 @@ static void init_std_data(struct entropy_store *r)
r->entropy_count = 0;
r->entropy_total = 0;
+ r->extracted_subttl = 0;
+ r->extracted_total = 0;
r->last_data_init = false;
mix_pool_bytes(r, &now, sizeof(now), NULL);
for (i = r->poolinfo->POOLBYTES; i > 0; i -= sizeof(rv)) {
@@ -1367,7 +1398,8 @@ EXPORT_SYMBOL(generate_random_uuid);
#include <linux/sysctl.h>
-static int min_read_thresh = 8, min_write_thresh;
+static int min_read_thresh = RESEED_BATCH;
+static int min_write_thresh; /* shouldn't this have a value? */
static int max_read_thresh = INPUT_POOL_WORDS * 32;
static int max_write_thresh = INPUT_POOL_WORDS * 32;
static char sysctl_bootid[16];
@@ -1426,6 +1458,76 @@ struct ctl_table random_table[] = {
.data = &input_pool.entropy_count,
},
{
+ .procname = "entropy_avail_r",
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ .data = &blocking_pool.entropy_count,
+ },
+ {
+ .procname = "entropy_avail_ur",
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
+ .data = &nonblocking_pool.entropy_count,
+ },
+ {
+ .procname = "play_int",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .data = &play,
+ },
+ {
+ .procname = "play_long",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .data = &play,
+ },
+ {
+ .procname = "extracted_total",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .data = &input_pool.extracted_total,
+ },
+ {
+ .procname = "extracted_total_r",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .data = &blocking_pool.extracted_total,
+ },
+ {
+ .procname = "extracted_total_ur",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .data = &nonblocking_pool.extracted_total,
+ },
+ {
+ .procname = "extracted_subttl",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .data = &input_pool.extracted_subttl,
+ },
+ {
+ .procname = "extracted_subttl_r",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .data = &blocking_pool.extracted_subttl,
+ },
+ {
+ .procname = "extracted_subttl_ur",
+ .maxlen = sizeof(uint64_t),
+ .mode = 0644,
+ .proc_handler = proc_doulongvec_minmax,
+ .data = &nonblocking_pool.extracted_subttl,
+ },
+ {
.procname = "read_wakeup_threshold",
.data = &random_read_wakeup_thresh,
.maxlen = sizeof(int),