summaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/random.c88
1 files changed, 49 insertions, 39 deletions
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,