From: "Theodore Ts'o" <tytso@mit.edu>
To: Matt Mackall <mpm@selenic.com>
Cc: Bernard Normier <bernard@zeroc.com>, linux-kernel@vger.kernel.org
Subject: Re: Concurrent access to /dev/urandom
Date: Fri, 10 Dec 2004 11:35:58 -0500 [thread overview]
Message-ID: <20041210163558.GB10639@thunk.org> (raw)
In-Reply-To: <20041210044759.GQ8876@waste.org>
On Thu, Dec 09, 2004 at 08:47:59PM -0800, Matt Mackall wrote:
>
> But it turns out that we can do this without hashing under the lock
> after all. What's important is that we mix and extract atomically.
> Something like this should be quite reasonable:
The core idea is good, but your patch has a bug in it; it bashes
add_ptr before it gets saved into r->add_ptr. Also, it's a more
complicated than it needed to be (which makes it harder to analyze
it). Finally, it won't work if the pool doesn't get initialized with
sufficient randomness in the init scripts, and there are too many
constant zero's in the pool. But this is easily fixed by using a
different initialization pattern.
How about this?
- Ted
This patch fixes a problem where /dev/urandom can return duplicate
values when two processors read from it at the same time. It relies
on the fact that we already are taking a lock in add_entropy_words(),
and atomically hashes in some freshly mixed in data into the returned
randomness.
Signed-off-by: Matt Mackall <mpm@selenic.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
--- 1.60/drivers/char/random.c 2004-11-18 17:23:14 -05:00
+++ edited/drivers/char/random.c 2004-12-10 11:23:55 -05:00
@@ -549,10 +549,13 @@ static int create_entropy_store(int size
/* Clear the entropy pool and associated counters. */
static void clear_entropy_store(struct entropy_store *r)
{
+ int i;
+
r->add_ptr = 0;
r->entropy_count = 0;
r->input_rotate = 0;
- memset(r->pool, 0, r->poolinfo.POOLBYTES);
+ for (i=0; i < r->poolinfo.poolwords; i++)
+ r->pool[i] = i;
}
#ifdef CONFIG_SYSCTL
static void free_entropy_store(struct entropy_store *r)
@@ -572,8 +575,8 @@ static void free_entropy_store(struct en
* it's cheap to do so and helps slightly in the expected case where
* the entropy is concentrated in the low-order bits.
*/
-static void add_entropy_words(struct entropy_store *r, const __u32 *in,
- int nwords)
+static void __add_entropy_words(struct entropy_store *r, const __u32 *in,
+ int nwords, __u32 out[16])
{
static __u32 const twist_table[8] = {
0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
@@ -626,9 +629,23 @@ static void add_entropy_words(struct ent
r->input_rotate = input_rotate;
r->add_ptr = add_ptr;
+ if (out) {
+ for (i = 0; i < 16; i++) {
+ out[i] = r->pool[add_ptr];
+ add_ptr = (add_ptr - 1) & wordmask;
+ }
+ }
+
spin_unlock_irqrestore(&r->lock, flags);
}
+static inline void add_entropy_words(struct entropy_store *r, const __u32 *in,
+ int nwords)
+{
+ __add_entropy_words(r, in, nwords, NULL);
+}
+
+
/*
* Credit (or debit) the entropy store with n bits of entropy
*/
@@ -1342,7 +1359,7 @@ static ssize_t extract_entropy(struct en
size_t nbytes, int flags)
{
ssize_t ret, i;
- __u32 tmp[TMP_BUF_SIZE];
+ __u32 tmp[TMP_BUF_SIZE], data[16];
__u32 x;
unsigned long cpuflags;
@@ -1422,7 +1439,15 @@ static ssize_t extract_entropy(struct en
HASH_TRANSFORM(tmp, r->pool+i);
add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1);
}
-
+
+ /*
+ * To avoid duplicates, we atomically extract a
+ * portion of the pool while mixing, and hash one
+ * final time.
+ */
+ __add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1, data);
+ HASH_TRANSFORM(tmp, data);
+
/*
* In case the hash function has some recognizable
* output pattern, we fold it in half.
next prev parent reply other threads:[~2004-12-10 16:37 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-27 20:45 Concurrent access to /dev/urandom Bernard Normier
2004-11-27 20:56 ` Jan Engelhardt
2004-11-27 21:15 ` Bernard Normier
2004-11-27 21:22 ` Jan Engelhardt
2004-11-28 20:58 ` Bernard Normier
2004-12-07 23:41 ` Bernard Normier
2004-12-08 1:28 ` Theodore Ts'o
2004-12-08 1:56 ` Bernard Normier
2004-12-08 19:21 ` Theodore Ts'o
2004-12-08 20:15 ` Bernard Normier
2004-12-08 21:56 ` Matt Mackall
2004-12-09 1:57 ` Theodore Ts'o
2004-12-09 2:46 ` andyliu
2004-12-09 4:55 ` Matt Mackall
2004-12-09 2:58 ` Matt Mackall
2004-12-09 21:29 ` Matt Mackall
2004-12-10 4:47 ` Matt Mackall
2004-12-10 16:35 ` Theodore Ts'o [this message]
2004-12-10 18:28 ` Matt Mackall
2004-12-10 21:28 ` Theodore Ts'o
2004-12-10 22:23 ` Matt Mackall
2004-12-11 0:22 ` Adam Heath
2004-12-11 1:10 ` Matt Mackall
2004-12-11 17:33 ` Theodore Ts'o
2004-12-11 19:58 ` Adam Heath
2004-12-11 20:40 ` Matt Mackall
2004-12-12 16:19 ` Pavel Machek
2004-12-11 0:19 ` Adam Heath
2004-12-09 3:10 ` David Lang
2004-12-09 4:52 ` Matt Mackall
2004-12-09 6:36 ` Theodore Ts'o
2004-11-29 22:47 ` Jon Masters
2004-11-29 23:14 ` Bernard Normier
2004-11-29 23:43 ` Sven-Haegar Koch
2004-11-30 2:31 ` David Schwartz
2004-11-30 4:14 ` Kyle Moffett
2004-11-30 8:23 ` Jan Engelhardt
2004-11-30 18:50 ` David Schwartz
2004-11-29 23:42 ` David Wagner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20041210163558.GB10639@thunk.org \
--to=tytso@mit.edu \
--cc=bernard@zeroc.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mpm@selenic.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox