| From 18cead822be9b93064205c4e4b55d7bb7d4c1efb Mon Sep 17 00:00:00 2001 |
| From: Daniel Borkmann <dborkman@redhat.com> |
| Date: Mon, 11 Nov 2013 12:20:32 +0100 |
| Subject: random32: fix off-by-one in seeding requirement |
| |
| From: Daniel Borkmann <dborkman@redhat.com> |
| |
| [ Upstream commit 51c37a70aaa3f95773af560e6db3073520513912 ] |
| |
| For properly initialising the Tausworthe generator [1], we have |
| a strict seeding requirement, that is, s1 > 1, s2 > 7, s3 > 15. |
| |
| Commit 697f8d0348 ("random32: seeding improvement") introduced |
| a __seed() function that imposes boundary checks proposed by the |
| errata paper [2] to properly ensure above conditions. |
| |
| However, we're off by one, as the function is implemented as: |
| "return (x < m) ? x + m : x;", and called with __seed(X, 1), |
| __seed(X, 7), __seed(X, 15). Thus, an unwanted seed of 1, 7, 15 |
| would be possible, whereas the lower boundary should actually |
| be of at least 2, 8, 16, just as GSL does. Fix this, as otherwise |
| an initialization with an unwanted seed could have the effect |
| that Tausworthe's PRNG properties cannot not be ensured. |
| |
| Note that this PRNG is *not* used for cryptography in the kernel. |
| |
| [1] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps |
| [2] http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps |
| |
| Joint work with Hannes Frederic Sowa. |
| |
| Fixes: 697f8d0348a6 ("random32: seeding improvement") |
| Cc: Stephen Hemminger <stephen@networkplumber.org> |
| Cc: Florian Weimer <fweimer@redhat.com> |
| Cc: Theodore Ts'o <tytso@mit.edu> |
| Signed-off-by: Daniel Borkmann <dborkman@redhat.com> |
| Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| include/linux/random.h | 6 +++--- |
| lib/random32.c | 14 +++++++------- |
| 2 files changed, 10 insertions(+), 10 deletions(-) |
| |
| --- a/include/linux/random.h |
| +++ b/include/linux/random.h |
| @@ -50,9 +50,9 @@ static inline void prandom_seed_state(st |
| { |
| u32 i = (seed >> 32) ^ (seed << 10) ^ seed; |
| |
| - state->s1 = __seed(i, 1); |
| - state->s2 = __seed(i, 7); |
| - state->s3 = __seed(i, 15); |
| + state->s1 = __seed(i, 2); |
| + state->s2 = __seed(i, 8); |
| + state->s3 = __seed(i, 16); |
| } |
| |
| #ifdef CONFIG_ARCH_RANDOM |
| --- a/lib/random32.c |
| +++ b/lib/random32.c |
| @@ -141,7 +141,7 @@ void prandom_seed(u32 entropy) |
| */ |
| for_each_possible_cpu (i) { |
| struct rnd_state *state = &per_cpu(net_rand_state, i); |
| - state->s1 = __seed(state->s1 ^ entropy, 1); |
| + state->s1 = __seed(state->s1 ^ entropy, 2); |
| } |
| } |
| EXPORT_SYMBOL(prandom_seed); |
| @@ -158,9 +158,9 @@ static int __init prandom_init(void) |
| struct rnd_state *state = &per_cpu(net_rand_state,i); |
| |
| #define LCG(x) ((x) * 69069) /* super-duper LCG */ |
| - state->s1 = __seed(LCG(i + jiffies), 1); |
| - state->s2 = __seed(LCG(state->s1), 7); |
| - state->s3 = __seed(LCG(state->s2), 15); |
| + state->s1 = __seed(LCG(i + jiffies), 2); |
| + state->s2 = __seed(LCG(state->s1), 8); |
| + state->s3 = __seed(LCG(state->s2), 16); |
| |
| /* "warm it up" */ |
| prandom_u32_state(state); |
| @@ -187,9 +187,9 @@ static int __init prandom_reseed(void) |
| u32 seeds[3]; |
| |
| get_random_bytes(&seeds, sizeof(seeds)); |
| - state->s1 = __seed(seeds[0], 1); |
| - state->s2 = __seed(seeds[1], 7); |
| - state->s3 = __seed(seeds[2], 15); |
| + state->s1 = __seed(seeds[0], 2); |
| + state->s2 = __seed(seeds[1], 8); |
| + state->s3 = __seed(seeds[2], 16); |
| |
| /* mix it in */ |
| prandom_u32_state(state); |