diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/hw_random/core.c | 47 | ||||
-rw-r--r-- | drivers/char/hw_random/virtio-rng.c | 10 | ||||
-rw-r--r-- | drivers/char/random.c | 17 |
3 files changed, 63 insertions, 11 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 334601cc81cf..c4419ea1ab07 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c | |||
@@ -55,16 +55,41 @@ static DEFINE_MUTEX(rng_mutex); | |||
55 | static int data_avail; | 55 | static int data_avail; |
56 | static u8 *rng_buffer; | 56 | static u8 *rng_buffer; |
57 | 57 | ||
58 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, | ||
59 | int wait); | ||
60 | |||
58 | static size_t rng_buffer_size(void) | 61 | static size_t rng_buffer_size(void) |
59 | { | 62 | { |
60 | return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; | 63 | return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; |
61 | } | 64 | } |
62 | 65 | ||
66 | static void add_early_randomness(struct hwrng *rng) | ||
67 | { | ||
68 | unsigned char bytes[16]; | ||
69 | int bytes_read; | ||
70 | |||
71 | /* | ||
72 | * Currently only virtio-rng cannot return data during device | ||
73 | * probe, and that's handled in virtio-rng.c itself. If there | ||
74 | * are more such devices, this call to rng_get_data can be | ||
75 | * made conditional here instead of doing it per-device. | ||
76 | */ | ||
77 | bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); | ||
78 | if (bytes_read > 0) | ||
79 | add_device_randomness(bytes, bytes_read); | ||
80 | } | ||
81 | |||
63 | static inline int hwrng_init(struct hwrng *rng) | 82 | static inline int hwrng_init(struct hwrng *rng) |
64 | { | 83 | { |
65 | if (!rng->init) | 84 | if (rng->init) { |
66 | return 0; | 85 | int ret; |
67 | return rng->init(rng); | 86 | |
87 | ret = rng->init(rng); | ||
88 | if (ret) | ||
89 | return ret; | ||
90 | } | ||
91 | add_early_randomness(rng); | ||
92 | return 0; | ||
68 | } | 93 | } |
69 | 94 | ||
70 | static inline void hwrng_cleanup(struct hwrng *rng) | 95 | static inline void hwrng_cleanup(struct hwrng *rng) |
@@ -304,8 +329,6 @@ int hwrng_register(struct hwrng *rng) | |||
304 | { | 329 | { |
305 | int err = -EINVAL; | 330 | int err = -EINVAL; |
306 | struct hwrng *old_rng, *tmp; | 331 | struct hwrng *old_rng, *tmp; |
307 | unsigned char bytes[16]; | ||
308 | int bytes_read; | ||
309 | 332 | ||
310 | if (rng->name == NULL || | 333 | if (rng->name == NULL || |
311 | (rng->data_read == NULL && rng->read == NULL)) | 334 | (rng->data_read == NULL && rng->read == NULL)) |
@@ -347,9 +370,17 @@ int hwrng_register(struct hwrng *rng) | |||
347 | INIT_LIST_HEAD(&rng->list); | 370 | INIT_LIST_HEAD(&rng->list); |
348 | list_add_tail(&rng->list, &rng_list); | 371 | list_add_tail(&rng->list, &rng_list); |
349 | 372 | ||
350 | bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1); | 373 | if (old_rng && !rng->init) { |
351 | if (bytes_read > 0) | 374 | /* |
352 | add_device_randomness(bytes, bytes_read); | 375 | * Use a new device's input to add some randomness to |
376 | * the system. If this rng device isn't going to be | ||
377 | * used right away, its init function hasn't been | ||
378 | * called yet; so only use the randomness from devices | ||
379 | * that don't need an init callback. | ||
380 | */ | ||
381 | add_early_randomness(rng); | ||
382 | } | ||
383 | |||
353 | out_unlock: | 384 | out_unlock: |
354 | mutex_unlock(&rng_mutex); | 385 | mutex_unlock(&rng_mutex); |
355 | out: | 386 | out: |
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c index f3e71501de54..e9b15bc18b4d 100644 --- a/drivers/char/hw_random/virtio-rng.c +++ b/drivers/char/hw_random/virtio-rng.c | |||
@@ -38,6 +38,8 @@ struct virtrng_info { | |||
38 | int index; | 38 | int index; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | static bool probe_done; | ||
42 | |||
41 | static void random_recv_done(struct virtqueue *vq) | 43 | static void random_recv_done(struct virtqueue *vq) |
42 | { | 44 | { |
43 | struct virtrng_info *vi = vq->vdev->priv; | 45 | struct virtrng_info *vi = vq->vdev->priv; |
@@ -67,6 +69,13 @@ static int virtio_read(struct hwrng *rng, void *buf, size_t size, bool wait) | |||
67 | int ret; | 69 | int ret; |
68 | struct virtrng_info *vi = (struct virtrng_info *)rng->priv; | 70 | struct virtrng_info *vi = (struct virtrng_info *)rng->priv; |
69 | 71 | ||
72 | /* | ||
73 | * Don't ask host for data till we're setup. This call can | ||
74 | * happen during hwrng_register(), after commit d9e7972619. | ||
75 | */ | ||
76 | if (unlikely(!probe_done)) | ||
77 | return 0; | ||
78 | |||
70 | if (!vi->busy) { | 79 | if (!vi->busy) { |
71 | vi->busy = true; | 80 | vi->busy = true; |
72 | init_completion(&vi->have_data); | 81 | init_completion(&vi->have_data); |
@@ -137,6 +146,7 @@ static int probe_common(struct virtio_device *vdev) | |||
137 | return err; | 146 | return err; |
138 | } | 147 | } |
139 | 148 | ||
149 | probe_done = true; | ||
140 | return 0; | 150 | return 0; |
141 | } | 151 | } |
142 | 152 | ||
diff --git a/drivers/char/random.c b/drivers/char/random.c index 0a7ac0a7b252..71529e196b84 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -641,7 +641,7 @@ retry: | |||
641 | } while (unlikely(entropy_count < pool_size-2 && pnfrac)); | 641 | } while (unlikely(entropy_count < pool_size-2 && pnfrac)); |
642 | } | 642 | } |
643 | 643 | ||
644 | if (entropy_count < 0) { | 644 | if (unlikely(entropy_count < 0)) { |
645 | pr_warn("random: negative entropy/overflow: pool %s count %d\n", | 645 | pr_warn("random: negative entropy/overflow: pool %s count %d\n", |
646 | r->name, entropy_count); | 646 | r->name, entropy_count); |
647 | WARN_ON(1); | 647 | WARN_ON(1); |
@@ -981,7 +981,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, | |||
981 | int reserved) | 981 | int reserved) |
982 | { | 982 | { |
983 | int entropy_count, orig; | 983 | int entropy_count, orig; |
984 | size_t ibytes; | 984 | size_t ibytes, nfrac; |
985 | 985 | ||
986 | BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); | 986 | BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); |
987 | 987 | ||
@@ -999,7 +999,17 @@ retry: | |||
999 | } | 999 | } |
1000 | if (ibytes < min) | 1000 | if (ibytes < min) |
1001 | ibytes = 0; | 1001 | ibytes = 0; |
1002 | if ((entropy_count -= ibytes << (ENTROPY_SHIFT + 3)) < 0) | 1002 | |
1003 | if (unlikely(entropy_count < 0)) { | ||
1004 | pr_warn("random: negative entropy count: pool %s count %d\n", | ||
1005 | r->name, entropy_count); | ||
1006 | WARN_ON(1); | ||
1007 | entropy_count = 0; | ||
1008 | } | ||
1009 | nfrac = ibytes << (ENTROPY_SHIFT + 3); | ||
1010 | if ((size_t) entropy_count > nfrac) | ||
1011 | entropy_count -= nfrac; | ||
1012 | else | ||
1003 | entropy_count = 0; | 1013 | entropy_count = 0; |
1004 | 1014 | ||
1005 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) | 1015 | if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) |
@@ -1376,6 +1386,7 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | |||
1376 | "with %d bits of entropy available\n", | 1386 | "with %d bits of entropy available\n", |
1377 | current->comm, nonblocking_pool.entropy_total); | 1387 | current->comm, nonblocking_pool.entropy_total); |
1378 | 1388 | ||
1389 | nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3)); | ||
1379 | ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); | 1390 | ret = extract_entropy_user(&nonblocking_pool, buf, nbytes); |
1380 | 1391 | ||
1381 | trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), | 1392 | trace_urandom_read(8 * nbytes, ENTROPY_BITS(&nonblocking_pool), |