]> err.no Git - linux-2.6/blobdiff - drivers/char/random.c
random: remove cacheline alignment for locks
[linux-2.6] / drivers / char / random.c
index 32118598a71bd427c2d2071a3f2d9618c549a21f..973706e97e7756911fdbee21d14dde498d883be7 100644 (file)
@@ -395,7 +395,7 @@ module_param(debug, bool, 0644);
 
 struct entropy_store;
 struct entropy_store {
-       /* mostly-read data: */
+       /* read-only data: */
        struct poolinfo *poolinfo;
        __u32 *pool;
        const char *name;
@@ -403,7 +403,7 @@ struct entropy_store {
        struct entropy_store *pull;
 
        /* read-write data: */
-       spinlock_t lock ____cacheline_aligned_in_smp;
+       spinlock_t lock;
        unsigned add_ptr;
        int entropy_count;
        int input_rotate;
@@ -540,6 +540,10 @@ static void credit_entropy_store(struct entropy_store *r, int nbits)
                                  nbits, r->name);
        }
 
+       /* should we wake readers? */
+       if (r == &input_pool && r->entropy_count >= random_read_wakeup_thresh)
+               wake_up_interruptible(&random_read_wait);
+
        spin_unlock_irqrestore(&r->lock, flags);
 }
 
@@ -624,10 +628,6 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
                credit_entropy_store(&input_pool,
                                     min_t(int, fls(delta>>1), 11));
        }
-
-       if (input_pool.entropy_count >= random_read_wakeup_thresh)
-               wake_up_interruptible(&random_read_wait);
-
 out:
        preempt_enable();
 }
@@ -765,42 +765,42 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min,
 static void extract_buf(struct entropy_store *r, __u8 *out)
 {
        int i;
-       __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS];
+       __u32 extract[16], hash[5], workspace[SHA_WORKSPACE_WORDS];
+
+       /* Generate a hash across the pool, 16 words (512 bits) at a time */
+       sha_init(hash);
+       for (i = 0; i < r->poolinfo->poolwords; i += 16)
+               sha_transform(hash, (__u8 *)(r->pool + i), workspace);
 
-       sha_init(buf);
        /*
-        * As we hash the pool, we mix intermediate values of
-        * the hash back into the pool.  This eliminates
-        * backtracking attacks (where the attacker knows
-        * the state of the pool plus the current outputs, and
-        * attempts to find previous ouputs), unless the hash
-        * function can be inverted.
+        * We mix the hash back into the pool to prevent backtracking
+        * attacks (where the attacker knows the state of the pool
+        * plus the current outputs, and attempts to find previous
+        * ouputs), unless the hash function can be inverted. By
+        * mixing at least a SHA1 worth of hash data back, we make
+        * brute-forcing the feedback as hard as brute-forcing the
+        * hash.
         */
-       for (i = 0; i < r->poolinfo->poolwords; i += 16) {
-               /* hash blocks of 16 words = 512 bits */
-               sha_transform(buf, (__u8 *)(r->pool + i), buf + 5);
-               /* feed back portion of the resulting hash */
-               add_entropy_words(r, &buf[i % 5], 1);
-       }
+       __add_entropy_words(r, hash, 5, extract);
 
        /*
-        * To avoid duplicates, we atomically extract a
-        * portion of the pool while mixing, and hash one
-        * final time.
+        * To avoid duplicates, we atomically extract a portion of the
+        * pool while mixing, and hash one final time.
         */
-       __add_entropy_words(r, &buf[i % 5], 1, data);
-       sha_transform(buf, (__u8 *)data, buf + 5);
+       sha_transform(hash, (__u8 *)extract, workspace);
+       memset(extract, 0, sizeof(extract));
+       memset(workspace, 0, sizeof(workspace));
 
        /*
-        * In case the hash function has some recognizable
-        * output pattern, we fold it in half.
+        * In case the hash function has some recognizable output
+        * pattern, we fold it in half. Thus, we always feed back
+        * twice as much data as we output.
         */
-
-       buf[0] ^= buf[3];
-       buf[1] ^= buf[4];
-       buf[2] ^= rol32(buf[2], 16);
-       memcpy(out, buf, EXTRACT_SIZE);
-       memset(buf, 0, sizeof(buf));
+       hash[0] ^= hash[3];
+       hash[1] ^= hash[4];
+       hash[2] ^= rol32(hash[2], 16);
+       memcpy(out, hash, EXTRACT_SIZE);
+       memset(hash, 0, sizeof(hash));
 }
 
 static ssize_t extract_entropy(struct entropy_store *r, void *buf,
@@ -899,7 +899,7 @@ static void init_std_data(struct entropy_store *r)
                          sizeof(*(utsname()))/4);
 }
 
-static int __init rand_initialize(void)
+static int rand_initialize(void)
 {
        init_std_data(&input_pool);
        init_std_data(&blocking_pool);
@@ -1062,8 +1062,7 @@ static ssize_t random_write(struct file *file, const char __user *buffer,
        return (ssize_t)count;
 }
 
-static int random_ioctl(struct inode *inode, struct file *file,
-                       unsigned int cmd, unsigned long arg)
+static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 {
        int size, ent_count;
        int __user *p = (int __user *)arg;
@@ -1071,8 +1070,8 @@ static int random_ioctl(struct inode *inode, struct file *file,
 
        switch (cmd) {
        case RNDGETENTCNT:
-               ent_count = input_pool.entropy_count;
-               if (put_user(ent_count, p))
+               /* inherently racy, no point locking */
+               if (put_user(input_pool.entropy_count, p))
                        return -EFAULT;
                return 0;
        case RNDADDTOENTCNT:
@@ -1081,12 +1080,6 @@ static int random_ioctl(struct inode *inode, struct file *file,
                if (get_user(ent_count, p))
                        return -EFAULT;
                credit_entropy_store(&input_pool, ent_count);
-               /*
-                * Wake up waiting processes if we have enough
-                * entropy.
-                */
-               if (input_pool.entropy_count >= random_read_wakeup_thresh)
-                       wake_up_interruptible(&random_read_wait);
                return 0;
        case RNDADDENTROPY:
                if (!capable(CAP_SYS_ADMIN))
@@ -1102,21 +1095,13 @@ static int random_ioctl(struct inode *inode, struct file *file,
                if (retval < 0)
                        return retval;
                credit_entropy_store(&input_pool, ent_count);
-               /*
-                * Wake up waiting processes if we have enough
-                * entropy.
-                */
-               if (input_pool.entropy_count >= random_read_wakeup_thresh)
-                       wake_up_interruptible(&random_read_wait);
                return 0;
        case RNDZAPENTCNT:
        case RNDCLEARPOOL:
                /* Clear the entropy pool counters. */
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
-               init_std_data(&input_pool);
-               init_std_data(&blocking_pool);
-               init_std_data(&nonblocking_pool);
+               rand_initialize();
                return 0;
        default:
                return -EINVAL;
@@ -1127,13 +1112,13 @@ const struct file_operations random_fops = {
        .read  = random_read,
        .write = random_write,
        .poll  = random_poll,
-       .ioctl = random_ioctl,
+       .unlocked_ioctl = random_ioctl,
 };
 
 const struct file_operations urandom_fops = {
        .read  = urandom_read,
        .write = random_write,
-       .ioctl = random_ioctl,
+       .unlocked_ioctl = random_ioctl,
 };
 
 /***************************************************************