Skip to content

Commit

Permalink
random32: update the net random state on interrupt and activity
Browse files Browse the repository at this point in the history
This modifies the first 32 bits out of the 128 bits of a random CPU's
net_rand_state on interrupt or CPU activity to complicate remote
observations that could lead to guessing the network RNG's internal
state.

Note that depending on some network devices' interrupt rate moderation
or binding, this re-seeding might happen on every packet or even almost
never.

In addition, with NOHZ some CPUs might not even get timer interrupts,
leaving their local state rarely updated, while they are running
networked processes making use of the random state.  For this reason, we
also perform this update in update_process_times() in order to at least
update the state when there is user or system activity, since it's the
only case we care about.

Reported-by: Amit Klein <aksecurity@gmail.com>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Eric Dumazet <edumazet@google.com>
Cc: "Jason A. Donenfeld" <Jason@zx2c4.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Kees Cook <keescook@chromium.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
wtarreau authored and torvalds committed Jul 29, 2020
1 parent 6ba1b00 commit f227e3e
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 1 deletion.
1 change: 1 addition & 0 deletions drivers/char/random.c
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,7 @@ void add_interrupt_randomness(int irq, int irq_flags)

fast_mix(fast_pool);
add_interrupt_bench(cycles);
this_cpu_add(net_rand_state.s1, fast_pool->pool[cycles & 3]);

if (unlikely(crng_init == 0)) {
if ((fast_pool->count >= 64) &&
Expand Down
3 changes: 3 additions & 0 deletions include/linux/random.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/once.h>
#include <linux/percpu.h>

#include <uapi/linux/random.h>

Expand Down Expand Up @@ -119,6 +120,8 @@ struct rnd_state {
__u32 s1, s2, s3, s4;
};

DECLARE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy;

u32 prandom_u32_state(struct rnd_state *state);
void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes);
void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state);
Expand Down
8 changes: 8 additions & 0 deletions kernel/time/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include <linux/sched/debug.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/random.h>

#include <linux/uaccess.h>
#include <asm/unistd.h>
Expand Down Expand Up @@ -1742,6 +1743,13 @@ void update_process_times(int user_tick)
scheduler_tick();
if (IS_ENABLED(CONFIG_POSIX_TIMERS))
run_posix_cpu_timers();

/* The current CPU might make use of net randoms without receiving IRQs
* to renew them often enough. Let's update the net_rand_state from a
* non-constant value that's not affine to the number of calls to make
* sure it's updated when there's some activity (we don't care in idle).
*/
this_cpu_add(net_rand_state.s1, rol32(jiffies, 24) + user_tick);
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/random32.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static inline void prandom_state_selftest(void)
}
#endif

static DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy;
DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy;

/**
* prandom_u32_state - seeded pseudo-random number generator.
Expand Down

0 comments on commit f227e3e

Please sign in to comment.