diff mbox series

[SRU,Focal:oem-5.6] random32: update the net random state on interrupt and activity

Message ID 20200909200134.88614-1-cascardo@canonical.com
State New
Headers show
Series [SRU,Focal:oem-5.6] random32: update the net random state on interrupt and activity | expand

Commit Message

Thadeu Lima de Souza Cascardo Sept. 9, 2020, 8:01 p.m. UTC
From: Willy Tarreau <w@1wt.eu>

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>
(cherry picked from commit f227e3ec3b5cad859ad15666874405e8c1bbc1d4)
CVE-2020-16166
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
---
 drivers/char/random.c  | 1 +
 include/linux/random.h | 3 +++
 kernel/time/timer.c    | 8 ++++++++
 lib/random32.c         | 2 +-
 4 files changed, 13 insertions(+), 1 deletion(-)

Comments

Colin Ian King Sept. 9, 2020, 9:23 p.m. UTC | #1
On 09/09/2020 21:01, Thadeu Lima de Souza Cascardo wrote:
> From: Willy Tarreau <w@1wt.eu>
> 
> 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>
> (cherry picked from commit f227e3ec3b5cad859ad15666874405e8c1bbc1d4)
> CVE-2020-16166
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
> ---
>  drivers/char/random.c  | 1 +
>  include/linux/random.h | 3 +++
>  kernel/time/timer.c    | 8 ++++++++
>  lib/random32.c         | 2 +-
>  4 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/char/random.c b/drivers/char/random.c
> index 6cf5a5f416ff..eb5ed0455e34 100644
> --- a/drivers/char/random.c
> +++ b/drivers/char/random.c
> @@ -1249,6 +1249,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) &&
> diff --git a/include/linux/random.h b/include/linux/random.h
> index d319f9a1e429..114db225ac3e 100644
> --- a/include/linux/random.h
> +++ b/include/linux/random.h
> @@ -9,6 +9,7 @@
>  
>  #include <linux/list.h>
>  #include <linux/once.h>
> +#include <linux/percpu.h>
>  
>  #include <uapi/linux/random.h>
>  
> @@ -117,6 +118,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);
> diff --git a/kernel/time/timer.c b/kernel/time/timer.c
> index 4820823515e9..226da9217f26 100644
> --- a/kernel/time/timer.c
> +++ b/kernel/time/timer.c
> @@ -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>
> @@ -1731,6 +1732,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);
>  }
>  
>  /**
> diff --git a/lib/random32.c b/lib/random32.c
> index 763b920a6206..c4d317be2997 100644
> --- a/lib/random32.c
> +++ b/lib/random32.c
> @@ -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.
> 

That's an interesting fix to a subtle flaw.  Clean cherry pick; looks OK
to me.

Acked-by: Colin Ian King <colin.king@canonical.com>
Kleber Sacilotto de Souza Sept. 15, 2020, 9:56 a.m. UTC | #2
On 09.09.20 22:01, Thadeu Lima de Souza Cascardo wrote:
> From: Willy Tarreau <w@1wt.eu>
> 
> 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>
> (cherry picked from commit f227e3ec3b5cad859ad15666874405e8c1bbc1d4)
> CVE-2020-16166
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>

This commit introduces build errors/warnings in some non-x86 arches
which are fixed by the following commits:

0c83b277ada7 powerpc: Fix circular dependency between percpu.h and mmu.h
aa54ea903abb ARM: percpu.h: fix build error
1c9df907da83 random: fix circular include dependency on arm64 after addition of percpu.h
835d1c3a9879 arm64: Drop unnecessary include from asm/smp.h

We probably don't care about those as we build this kernel only
for amd64, but have you considered including the following fixup?

83bdc7275e62 random32: remove net_rand_state from the latent entropy gcc plugin


Kleber

> ---
>  drivers/char/random.c  | 1 +
>  include/linux/random.h | 3 +++
>  kernel/time/timer.c    | 8 ++++++++
>  lib/random32.c         | 2 +-
>  4 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/char/random.c b/drivers/char/random.c
> index 6cf5a5f416ff..eb5ed0455e34 100644
> --- a/drivers/char/random.c
> +++ b/drivers/char/random.c
> @@ -1249,6 +1249,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) &&
> diff --git a/include/linux/random.h b/include/linux/random.h
> index d319f9a1e429..114db225ac3e 100644
> --- a/include/linux/random.h
> +++ b/include/linux/random.h
> @@ -9,6 +9,7 @@
>  
>  #include <linux/list.h>
>  #include <linux/once.h>
> +#include <linux/percpu.h>
>  
>  #include <uapi/linux/random.h>
>  
> @@ -117,6 +118,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);
> diff --git a/kernel/time/timer.c b/kernel/time/timer.c
> index 4820823515e9..226da9217f26 100644
> --- a/kernel/time/timer.c
> +++ b/kernel/time/timer.c
> @@ -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>
> @@ -1731,6 +1732,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);
>  }
>  
>  /**
> diff --git a/lib/random32.c b/lib/random32.c
> index 763b920a6206..c4d317be2997 100644
> --- a/lib/random32.c
> +++ b/lib/random32.c
> @@ -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.
>
Thadeu Lima de Souza Cascardo Sept. 16, 2020, 4:20 p.m. UTC | #3
On Tue, Sep 15, 2020 at 11:56:42AM +0200, Kleber Souza wrote:
> On 09.09.20 22:01, Thadeu Lima de Souza Cascardo wrote:
> > From: Willy Tarreau <w@1wt.eu>
> > 
> > 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>
> > (cherry picked from commit f227e3ec3b5cad859ad15666874405e8c1bbc1d4)
> > CVE-2020-16166
> > Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
> 
> This commit introduces build errors/warnings in some non-x86 arches
> which are fixed by the following commits:
> 
> 0c83b277ada7 powerpc: Fix circular dependency between percpu.h and mmu.h
> aa54ea903abb ARM: percpu.h: fix build error
> 1c9df907da83 random: fix circular include dependency on arm64 after addition of percpu.h
> 835d1c3a9879 arm64: Drop unnecessary include from asm/smp.h
> 
> We probably don't care about those as we build this kernel only
> for amd64, but have you considered including the following fixup?
> 
> 83bdc7275e62 random32: remove net_rand_state from the latent entropy gcc plugin
> 

Yes, I took those into consideration and ignored because they wouldn't cause
problems with oem-5.6. So, I went with the minimal backport, tested that it
builds on all supported architectures (that is, only amd64), and decided to
close the issue for a kernel that won't live too much more.

Thanks.
Cascardo.

> 
> Kleber
> 
> > ---
> >  drivers/char/random.c  | 1 +
> >  include/linux/random.h | 3 +++
> >  kernel/time/timer.c    | 8 ++++++++
> >  lib/random32.c         | 2 +-
> >  4 files changed, 13 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/char/random.c b/drivers/char/random.c
> > index 6cf5a5f416ff..eb5ed0455e34 100644
> > --- a/drivers/char/random.c
> > +++ b/drivers/char/random.c
> > @@ -1249,6 +1249,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) &&
> > diff --git a/include/linux/random.h b/include/linux/random.h
> > index d319f9a1e429..114db225ac3e 100644
> > --- a/include/linux/random.h
> > +++ b/include/linux/random.h
> > @@ -9,6 +9,7 @@
> >  
> >  #include <linux/list.h>
> >  #include <linux/once.h>
> > +#include <linux/percpu.h>
> >  
> >  #include <uapi/linux/random.h>
> >  
> > @@ -117,6 +118,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);
> > diff --git a/kernel/time/timer.c b/kernel/time/timer.c
> > index 4820823515e9..226da9217f26 100644
> > --- a/kernel/time/timer.c
> > +++ b/kernel/time/timer.c
> > @@ -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>
> > @@ -1731,6 +1732,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);
> >  }
> >  
> >  /**
> > diff --git a/lib/random32.c b/lib/random32.c
> > index 763b920a6206..c4d317be2997 100644
> > --- a/lib/random32.c
> > +++ b/lib/random32.c
> > @@ -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.
> > 
>
Kleber Sacilotto de Souza Sept. 16, 2020, 4:22 p.m. UTC | #4
On 09.09.20 22:01, Thadeu Lima de Souza Cascardo wrote:
> From: Willy Tarreau <w@1wt.eu>
> 
> 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>
> (cherry picked from commit f227e3ec3b5cad859ad15666874405e8c1bbc1d4)
> CVE-2020-16166
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>

Thanks Thadeu for the additional clarification. The fix looks good to
me.

Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>

> ---
>  drivers/char/random.c  | 1 +
>  include/linux/random.h | 3 +++
>  kernel/time/timer.c    | 8 ++++++++
>  lib/random32.c         | 2 +-
>  4 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/char/random.c b/drivers/char/random.c
> index 6cf5a5f416ff..eb5ed0455e34 100644
> --- a/drivers/char/random.c
> +++ b/drivers/char/random.c
> @@ -1249,6 +1249,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) &&
> diff --git a/include/linux/random.h b/include/linux/random.h
> index d319f9a1e429..114db225ac3e 100644
> --- a/include/linux/random.h
> +++ b/include/linux/random.h
> @@ -9,6 +9,7 @@
>  
>  #include <linux/list.h>
>  #include <linux/once.h>
> +#include <linux/percpu.h>
>  
>  #include <uapi/linux/random.h>
>  
> @@ -117,6 +118,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);
> diff --git a/kernel/time/timer.c b/kernel/time/timer.c
> index 4820823515e9..226da9217f26 100644
> --- a/kernel/time/timer.c
> +++ b/kernel/time/timer.c
> @@ -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>
> @@ -1731,6 +1732,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);
>  }
>  
>  /**
> diff --git a/lib/random32.c b/lib/random32.c
> index 763b920a6206..c4d317be2997 100644
> --- a/lib/random32.c
> +++ b/lib/random32.c
> @@ -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.
>
Stefan Bader Sept. 17, 2020, 7:38 a.m. UTC | #5
On 09.09.20 22:01, Thadeu Lima de Souza Cascardo wrote:
> From: Willy Tarreau <w@1wt.eu>
> 
> 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>
> (cherry picked from commit f227e3ec3b5cad859ad15666874405e8c1bbc1d4)
> CVE-2020-16166
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
> ---
>  drivers/char/random.c  | 1 +
>  include/linux/random.h | 3 +++
>  kernel/time/timer.c    | 8 ++++++++
>  lib/random32.c         | 2 +-
>  4 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/char/random.c b/drivers/char/random.c
> index 6cf5a5f416ff..eb5ed0455e34 100644
> --- a/drivers/char/random.c
> +++ b/drivers/char/random.c
> @@ -1249,6 +1249,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) &&
> diff --git a/include/linux/random.h b/include/linux/random.h
> index d319f9a1e429..114db225ac3e 100644
> --- a/include/linux/random.h
> +++ b/include/linux/random.h
> @@ -9,6 +9,7 @@
>  
>  #include <linux/list.h>
>  #include <linux/once.h>
> +#include <linux/percpu.h>
>  
>  #include <uapi/linux/random.h>
>  
> @@ -117,6 +118,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);
> diff --git a/kernel/time/timer.c b/kernel/time/timer.c
> index 4820823515e9..226da9217f26 100644
> --- a/kernel/time/timer.c
> +++ b/kernel/time/timer.c
> @@ -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>
> @@ -1731,6 +1732,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);
>  }
>  
>  /**
> diff --git a/lib/random32.c b/lib/random32.c
> index 763b920a6206..c4d317be2997 100644
> --- a/lib/random32.c
> +++ b/lib/random32.c
> @@ -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.
>
Timo Aaltonen Sept. 22, 2020, 11:51 a.m. UTC | #6
On 9.9.2020 23.01, Thadeu Lima de Souza Cascardo wrote:
> From: Willy Tarreau <w@1wt.eu>
> 
> 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>
> (cherry picked from commit f227e3ec3b5cad859ad15666874405e8c1bbc1d4)
> CVE-2020-16166
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
> ---
>  drivers/char/random.c  | 1 +
>  include/linux/random.h | 3 +++
>  kernel/time/timer.c    | 8 ++++++++
>  lib/random32.c         | 2 +-
>  4 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/char/random.c b/drivers/char/random.c
> index 6cf5a5f416ff..eb5ed0455e34 100644
> --- a/drivers/char/random.c
> +++ b/drivers/char/random.c
> @@ -1249,6 +1249,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) &&
> diff --git a/include/linux/random.h b/include/linux/random.h
> index d319f9a1e429..114db225ac3e 100644
> --- a/include/linux/random.h
> +++ b/include/linux/random.h
> @@ -9,6 +9,7 @@
>  
>  #include <linux/list.h>
>  #include <linux/once.h>
> +#include <linux/percpu.h>
>  
>  #include <uapi/linux/random.h>
>  
> @@ -117,6 +118,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);
> diff --git a/kernel/time/timer.c b/kernel/time/timer.c
> index 4820823515e9..226da9217f26 100644
> --- a/kernel/time/timer.c
> +++ b/kernel/time/timer.c
> @@ -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>
> @@ -1731,6 +1732,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);
>  }
>  
>  /**
> diff --git a/lib/random32.c b/lib/random32.c
> index 763b920a6206..c4d317be2997 100644
> --- a/lib/random32.c
> +++ b/lib/random32.c
> @@ -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.
> 

applied to oem-5.6, thanks
diff mbox series

Patch

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 6cf5a5f416ff..eb5ed0455e34 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1249,6 +1249,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) &&
diff --git a/include/linux/random.h b/include/linux/random.h
index d319f9a1e429..114db225ac3e 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -9,6 +9,7 @@ 
 
 #include <linux/list.h>
 #include <linux/once.h>
+#include <linux/percpu.h>
 
 #include <uapi/linux/random.h>
 
@@ -117,6 +118,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);
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 4820823515e9..226da9217f26 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -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>
@@ -1731,6 +1732,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);
 }
 
 /**
diff --git a/lib/random32.c b/lib/random32.c
index 763b920a6206..c4d317be2997 100644
--- a/lib/random32.c
+++ b/lib/random32.c
@@ -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.