random: cap the rate which the /dev/urandom pool gets reseeded
authorTheodore Ts'o <tytso@mit.edu>
Sun, 22 Sep 2013 19:14:32 +0000 (15:14 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 10 Oct 2013 18:32:19 +0000 (14:32 -0400)
In order to avoid draining the input pool of its entropy at too high
of a rate, enforce a minimum time interval between reseedings of the
urandom pool.  This is set to 60 seconds by default.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
drivers/char/random.c

index b8809d4..a68b4a0 100644 (file)
@@ -306,6 +306,13 @@ static int random_read_wakeup_thresh = 64;
  */
 static int random_write_wakeup_thresh = 128;
 
+/*
+ * The minimum number of seconds between urandom pool resending.  We
+ * do this to limit the amount of entropy that can be drained from the
+ * input pool even if there are heavy demands on /dev/urandom.
+ */
+static int random_min_urandom_seed = 60;
+
 /*
  * When the input pool goes over trickle_thresh, start dropping most
  * samples to avoid wasting CPU time and reduce lock contention.
@@ -438,6 +445,7 @@ struct entropy_store {
        struct entropy_store *pull;
 
        /* read-write data: */
+       unsigned long last_pulled;
        spinlock_t lock;
        unsigned short add_ptr;
        unsigned short input_rotate;
@@ -887,6 +895,14 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
 {
        __u32   tmp[OUTPUT_POOL_WORDS];
 
+       if (r->limit == 0 && random_min_urandom_seed) {
+               unsigned long now = jiffies;
+
+               if (time_before(now,
+                               r->last_pulled + random_min_urandom_seed * HZ))
+                       return;
+               r->last_pulled = now;
+       }
        if (r->pull &&
            r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) &&
            r->entropy_count < r->poolinfo->poolfracbits) {
@@ -1190,6 +1206,7 @@ static void init_std_data(struct entropy_store *r)
        r->entropy_count = 0;
        r->entropy_total = 0;
        r->last_data_init = 0;
+       r->last_pulled = jiffies;
        mix_pool_bytes(r, &now, sizeof(now), NULL);
        for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) {
                if (!arch_get_random_long(&rv))
@@ -1540,6 +1557,13 @@ struct ctl_table random_table[] = {
                .extra1         = &min_write_thresh,
                .extra2         = &max_write_thresh,
        },
+       {
+               .procname       = "urandom_min_reseed_secs",
+               .data           = &random_min_urandom_seed,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        {
                .procname       = "boot_id",
                .data           = &sysctl_bootid,