Commit a98406e22c12e514bac28fec0a49dc793edaf3a8
Committed by
David S. Miller
1 parent
c1e60bd4fe
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
random32: improvements to prandom_bytes
This patch addresses a couple of minor items, mostly addesssing prandom_bytes(): 1) prandom_bytes{,_state}() should use size_t for length arguments, 2) We can use put_unaligned() when filling the array instead of open coding it [ perhaps some archs will further benefit from their own arch specific implementation when GCC cannot make up for it ], 3) Fix a typo, 4) Better use unsigned int as type for getting the arch seed, 5) Make use of prandom_u32_max() for timer slack. Regarding the change to put_unaligned(), callers of prandom_bytes() which internally invoke prandom_bytes_state(), don't bother as they expect the array to be filled randomly and don't have any control of the internal state what-so-ever (that's also why we have periodic reseeding there, etc), so they really don't care. Now for the direct callers of prandom_bytes_state(), which are solely located in test cases for MTD devices, that is, drivers/mtd/tests/{oobtest.c,pagetest.c,subpagetest.c}: These tests basically fill a test write-vector through prandom_bytes_state() with an a-priori defined seed each time and write that to a MTD device. Later on, they set up a read-vector and read back that blocks from the device. So in the verification phase, the write-vector is being re-setup [ so same seed and prandom_bytes_state() called ], and then memcmp()'ed against the read-vector to check if the data is the same. Akinobu, Lothar and I also tested this patch and it runs through the 3 relevant MTD test cases w/o any errors on the nandsim device (simulator for MTD devs) for x86_64, ppc64, ARM (i.MX28, i.MX53 and i.MX6): # modprobe nandsim first_id_byte=0x20 second_id_byte=0xac \ third_id_byte=0x00 fourth_id_byte=0x15 # modprobe mtd_oobtest dev=0 # modprobe mtd_pagetest dev=0 # modprobe mtd_subpagetest dev=0 We also don't have any users depending directly on a particular result of the PRNG (except the PRNG self-test itself), and that's just fine as it e.g. allowed us easily to do things like upgrading from taus88 to taus113. Signed-off-by: Daniel Borkmann <dborkman@redhat.com> Tested-by: Akinobu Mita <akinobu.mita@gmail.com> Tested-by: Lothar Waßmann <LW@KARO-electronics.de> Cc: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 2 changed files with 20 additions and 23 deletions Side-by-side Diff
include/linux/random.h
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 | unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len); |
27 | 27 | |
28 | 28 | u32 prandom_u32(void); |
29 | -void prandom_bytes(void *buf, int nbytes); | |
29 | +void prandom_bytes(void *buf, size_t nbytes); | |
30 | 30 | void prandom_seed(u32 seed); |
31 | 31 | void prandom_reseed_late(void); |
32 | 32 | |
... | ... | @@ -35,7 +35,7 @@ |
35 | 35 | }; |
36 | 36 | |
37 | 37 | u32 prandom_u32_state(struct rnd_state *state); |
38 | -void prandom_bytes_state(struct rnd_state *state, void *buf, int nbytes); | |
38 | +void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes); | |
39 | 39 | |
40 | 40 | /** |
41 | 41 | * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro) |
lib/random32.c
... | ... | @@ -37,6 +37,7 @@ |
37 | 37 | #include <linux/jiffies.h> |
38 | 38 | #include <linux/random.h> |
39 | 39 | #include <linux/sched.h> |
40 | +#include <asm/unaligned.h> | |
40 | 41 | |
41 | 42 | #ifdef CONFIG_RANDOM32_SELFTEST |
42 | 43 | static void __init prandom_state_selftest(void); |
43 | 44 | |
44 | 45 | |
45 | 46 | |
46 | 47 | |
... | ... | @@ -96,27 +97,23 @@ |
96 | 97 | * This is used for pseudo-randomness with no outside seeding. |
97 | 98 | * For more random results, use prandom_bytes(). |
98 | 99 | */ |
99 | -void prandom_bytes_state(struct rnd_state *state, void *buf, int bytes) | |
100 | +void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes) | |
100 | 101 | { |
101 | - unsigned char *p = buf; | |
102 | - int i; | |
102 | + u8 *ptr = buf; | |
103 | 103 | |
104 | - for (i = 0; i < round_down(bytes, sizeof(u32)); i += sizeof(u32)) { | |
105 | - u32 random = prandom_u32_state(state); | |
106 | - int j; | |
107 | - | |
108 | - for (j = 0; j < sizeof(u32); j++) { | |
109 | - p[i + j] = random; | |
110 | - random >>= BITS_PER_BYTE; | |
111 | - } | |
104 | + while (bytes >= sizeof(u32)) { | |
105 | + put_unaligned(prandom_u32_state(state), (u32 *) ptr); | |
106 | + ptr += sizeof(u32); | |
107 | + bytes -= sizeof(u32); | |
112 | 108 | } |
113 | - if (i < bytes) { | |
114 | - u32 random = prandom_u32_state(state); | |
115 | 109 | |
116 | - for (; i < bytes; i++) { | |
117 | - p[i] = random; | |
118 | - random >>= BITS_PER_BYTE; | |
119 | - } | |
110 | + if (bytes > 0) { | |
111 | + u32 rem = prandom_u32_state(state); | |
112 | + do { | |
113 | + *ptr++ = (u8) rem; | |
114 | + bytes--; | |
115 | + rem >>= BITS_PER_BYTE; | |
116 | + } while (bytes > 0); | |
120 | 117 | } |
121 | 118 | } |
122 | 119 | EXPORT_SYMBOL(prandom_bytes_state); |
... | ... | @@ -126,7 +123,7 @@ |
126 | 123 | * @buf: where to copy the pseudo-random bytes to |
127 | 124 | * @bytes: the requested number of bytes |
128 | 125 | */ |
129 | -void prandom_bytes(void *buf, int bytes) | |
126 | +void prandom_bytes(void *buf, size_t bytes) | |
130 | 127 | { |
131 | 128 | struct rnd_state *state = &get_cpu_var(net_rand_state); |
132 | 129 | |
... | ... | @@ -137,7 +134,7 @@ |
137 | 134 | |
138 | 135 | static void prandom_warmup(struct rnd_state *state) |
139 | 136 | { |
140 | - /* Calling RNG ten times to satify recurrence condition */ | |
137 | + /* Calling RNG ten times to satisfy recurrence condition */ | |
141 | 138 | prandom_u32_state(state); |
142 | 139 | prandom_u32_state(state); |
143 | 140 | prandom_u32_state(state); |
... | ... | @@ -152,7 +149,7 @@ |
152 | 149 | |
153 | 150 | static u32 __extract_hwseed(void) |
154 | 151 | { |
155 | - u32 val = 0; | |
152 | + unsigned int val = 0; | |
156 | 153 | |
157 | 154 | (void)(arch_get_random_seed_int(&val) || |
158 | 155 | arch_get_random_int(&val)); |
... | ... | @@ -228,7 +225,7 @@ |
228 | 225 | prandom_seed(entropy); |
229 | 226 | |
230 | 227 | /* reseed every ~60 seconds, in [40 .. 80) interval with slack */ |
231 | - expires = 40 + (prandom_u32() % 40); | |
228 | + expires = 40 + prandom_u32_max(40); | |
232 | 229 | seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC); |
233 | 230 | |
234 | 231 | add_timer(&seed_timer); |