From 9f886f4d1d292442b2f22a0a33321eae821bde40 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 25 Feb 2017 18:21:33 -0400 Subject: [PATCH 1/4] random: use a tighter cap in credit_entropy_bits_safe() This fixes a harmless UBSAN where root could potentially end up causing an overflow while bumping the entropy_total field (which is ignored once the entropy pool has been initialized, and this generally is completed during the boot sequence). This is marginal for the stable kernel series, but it's a really trivial patch, and it fixes UBSAN warning that might cause security folks to get overly excited for no reason. Signed-off-by: Theodore Ts'o Reported-by: Chen Feng Cc: stable@vger.kernel.org --- drivers/char/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index e5b3d3ba4660..11c23ca57430 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -732,7 +732,7 @@ retry: static int credit_entropy_bits_safe(struct entropy_store *r, int nbits) { - const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); + const int nbits_max = r->poolinfo->poolwords * 32; if (nbits < 0) return -EINVAL; From 25e3fca492035a2e1d4ac6e3b1edd9c1acd48897 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Feb 2018 23:07:46 +0100 Subject: [PATCH 2/4] random: always fill buffer in get_random_bytes_wait In the unfortunate event that a developer fails to check the return value of get_random_bytes_wait, or simply wants to make a "best effort" attempt, for whatever that's worth, it's much better to still fill the buffer with _something_ rather than catastrophically failing in the case of an interruption. This is both a defense in depth measure against inevitable programming bugs, as well as a means of making the API a bit more useful. Signed-off-by: Jason A. Donenfeld Signed-off-by: Theodore Ts'o --- include/linux/random.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/linux/random.h b/include/linux/random.h index 4024f7d9c77d..2ddf13b4281e 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -85,10 +85,8 @@ static inline unsigned long get_random_canary(void) static inline int get_random_bytes_wait(void *buf, int nbytes) { int ret = wait_for_random_bytes(); - if (unlikely(ret)) - return ret; get_random_bytes(buf, nbytes); - return 0; + return ret; } #define declare_get_random_var_wait(var) \ From e8e8a2e47db6bb85bb0cb21e77b5c6aaedf864b4 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Wed, 28 Feb 2018 13:43:28 -0800 Subject: [PATCH 3/4] random: optimize add_interrupt_randomness add_interrupt_randomess always wakes up code blocking on /dev/random. This wake up is done unconditionally. Unfortunately this means all interrupts take the wait queue spinlock, which can be rather expensive on large systems processing lots of interrupts. We saw 1% cpu time spinning on this on a large macro workload running on a large system. I believe it's a recent regression (?) Always check if there is a waiter on the wait queue before waking up. This check can be done without taking a spinlock. 1.06% 10460 [kernel.vmlinux] [k] native_queued_spin_lock_slowpath | ---native_queued_spin_lock_slowpath | --0.57%--_raw_spin_lock_irqsave | --0.56%--__wake_up_common_lock credit_entropy_bits add_interrupt_randomness handle_irq_event_percpu handle_irq_event handle_edge_irq handle_irq do_IRQ common_interrupt Signed-off-by: Andi Kleen Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 11c23ca57430..ee0c0d18f1eb 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -709,7 +709,8 @@ retry: } /* should we wake readers? */ - if (entropy_bits >= random_read_wakeup_bits) { + if (entropy_bits >= random_read_wakeup_bits && + wq_has_sleeper(&random_read_wait)) { wake_up_interruptible(&random_read_wait); kill_fasync(&fasync, SIGIO, POLL_IN); } From 5e747dd9be54be190dd6ebeebf4a4a01ba765625 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 1 Mar 2018 00:22:47 +0100 Subject: [PATCH 4/4] drivers/char/random.c: remove unused dont_count_entropy Ever since "random: kill dead extract_state struct" [1], the dont_count_entropy member of struct timer_rand_state has been effectively unused. Since it hasn't found a new use in 12 years, it's probably safe to finally kill it. [1] Pre-git, https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git/commit/?id=c1c48e61c251f57e7a3f1bf11b3c462b2de9dcb5 Signed-off-by: Rasmus Villemoes Signed-off-by: Theodore Ts'o --- drivers/char/random.c | 47 ++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index ee0c0d18f1eb..e027e7fa1472 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -964,7 +964,6 @@ static ssize_t extract_crng_user(void __user *buf, size_t nbytes) struct timer_rand_state { cycles_t last_time; long last_delta, last_delta2; - unsigned dont_count_entropy:1; }; #define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, }; @@ -1030,35 +1029,33 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * We take into account the first, second and third-order deltas * in order to make our estimate. */ + delta = sample.jiffies - state->last_time; + state->last_time = sample.jiffies; - if (!state->dont_count_entropy) { - delta = sample.jiffies - state->last_time; - state->last_time = sample.jiffies; + delta2 = delta - state->last_delta; + state->last_delta = delta; - delta2 = delta - state->last_delta; - state->last_delta = delta; + delta3 = delta2 - state->last_delta2; + state->last_delta2 = delta2; - delta3 = delta2 - state->last_delta2; - state->last_delta2 = delta2; + if (delta < 0) + delta = -delta; + if (delta2 < 0) + delta2 = -delta2; + if (delta3 < 0) + delta3 = -delta3; + if (delta > delta2) + delta = delta2; + if (delta > delta3) + delta = delta3; - if (delta < 0) - delta = -delta; - if (delta2 < 0) - delta2 = -delta2; - if (delta3 < 0) - delta3 = -delta3; - if (delta > delta2) - delta = delta2; - if (delta > delta3) - delta = delta3; + /* + * delta is now minimum absolute delta. + * Round down by 1 bit on general principles, + * and limit entropy entimate to 12 bits. + */ + credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); - /* - * delta is now minimum absolute delta. - * Round down by 1 bit on general principles, - * and limit entropy entimate to 12 bits. - */ - credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); - } preempt_enable(); }