Skip to content

Commit 3744741

Browse files
committed
random32: add noise from network and scheduling activity
With the removal of the interrupt perturbations in previous random32 change (random32: make prandom_u32() output unpredictable), the PRNG has become 100% deterministic again. While SipHash is expected to be way more robust against brute force than the previous Tausworthe LFSR, there's still the risk that whoever has even one temporary access to the PRNG's internal state is able to predict all subsequent draws till the next reseed (roughly every minute). This may happen through a side channel attack or any data leak. This patch restores the spirit of commit f227e3e ("random32: update the net random state on interrupt and activity") in that it will perturb the internal PRNG's statee using externally collected noise, except that it will not pick that noise from the random pool's bits nor upon interrupt, but will rather combine a few elements along the Tx path that are collectively hard to predict, such as dev, skb and txq pointers, packet length and jiffies values. These ones are combined using a single round of SipHash into a single long variable that is mixed with the net_rand_state upon each invocation. The operation was inlined because it produces very small and efficient code, typically 3 xor, 2 add and 2 rol. The performance was measured to be the same (even very slightly better) than before the switch to SipHash; on a 6-core 12-thread Core i7-8700k equipped with a 40G NIC (i40e), the connection rate dropped from 556k/s to 555k/s while the SYN cookie rate grew from 5.38 Mpps to 5.45 Mpps. Link: https://lore.kernel.org/netdev/20200808152628.GA27941@SDF.ORG/ Cc: George Spelvin <lkml@sdf.org> Cc: Amit Klein <aksecurity@gmail.com> 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: Linus Torvalds <torvalds@linux-foundation.org> Cc: tytso@mit.edu Cc: Florian Westphal <fw@strlen.de> Cc: Marc Plumb <lkml.mplumb@gmail.com> Tested-by: Sedat Dilek <sedat.dilek@gmail.com> Signed-off-by: Willy Tarreau <w@1wt.eu>
1 parent c51f8f8 commit 3744741

4 files changed

Lines changed: 30 additions & 0 deletions

File tree

include/linux/prandom.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ void prandom_bytes(void *buf, size_t nbytes);
1616
void prandom_seed(u32 seed);
1717
void prandom_reseed_late(void);
1818

19+
DECLARE_PER_CPU(unsigned long, net_rand_noise);
20+
21+
#define PRANDOM_ADD_NOISE(a, b, c, d) \
22+
prandom_u32_add_noise((unsigned long)(a), (unsigned long)(b), \
23+
(unsigned long)(c), (unsigned long)(d))
24+
1925
#if BITS_PER_LONG == 64
2026
/*
2127
* The core SipHash round function. Each line can be executed in
@@ -50,6 +56,18 @@ void prandom_reseed_late(void);
5056
#error Unsupported BITS_PER_LONG
5157
#endif
5258

59+
static inline void prandom_u32_add_noise(unsigned long a, unsigned long b,
60+
unsigned long c, unsigned long d)
61+
{
62+
/*
63+
* This is not used cryptographically; it's just
64+
* a convenient 4-word hash function. (3 xor, 2 add, 2 rol)
65+
*/
66+
a ^= raw_cpu_read(net_rand_noise);
67+
PRND_SIPROUND(a, b, c, d);
68+
raw_cpu_write(net_rand_noise, d);
69+
}
70+
5371
struct rnd_state {
5472
__u32 s1, s2, s3, s4;
5573
};
@@ -99,6 +117,7 @@ static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
99117
state->s2 = __seed(i, 8U);
100118
state->s3 = __seed(i, 16U);
101119
state->s4 = __seed(i, 128U);
120+
PRANDOM_ADD_NOISE(state, i, 0, 0);
102121
}
103122

104123
/* Pseudo random number generator from numerical recipes. */

kernel/time/timer.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,6 +1706,8 @@ void update_process_times(int user_tick)
17061706
{
17071707
struct task_struct *p = current;
17081708

1709+
PRANDOM_ADD_NOISE(jiffies, user_tick, p, 0);
1710+
17091711
/* Note: this timer irq context must be accounted for as well. */
17101712
account_process_tick(p, user_tick);
17111713
run_local_timers();

lib/random32.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ struct siprand_state {
337337
};
338338

339339
static DEFINE_PER_CPU(struct siprand_state, net_rand_state) __latent_entropy;
340+
DEFINE_PER_CPU(unsigned long, net_rand_noise);
341+
EXPORT_PER_CPU_SYMBOL(net_rand_noise);
340342

341343
/*
342344
* This is the core CPRNG function. As "pseudorandom", this is not used
@@ -360,9 +362,12 @@ static DEFINE_PER_CPU(struct siprand_state, net_rand_state) __latent_entropy;
360362
static inline u32 siprand_u32(struct siprand_state *s)
361363
{
362364
unsigned long v0 = s->v0, v1 = s->v1, v2 = s->v2, v3 = s->v3;
365+
unsigned long n = raw_cpu_read(net_rand_noise);
363366

367+
v3 ^= n;
364368
PRND_SIPROUND(v0, v1, v2, v3);
365369
PRND_SIPROUND(v0, v1, v2, v3);
370+
v0 ^= n;
366371
s->v0 = v0; s->v1 = v1; s->v2 = v2; s->v3 = v3;
367372
return v1 + v3;
368373
}

net/core/dev.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
#include <linux/indirect_call_wrapper.h>
146146
#include <net/devlink.h>
147147
#include <linux/pm_runtime.h>
148+
#include <linux/prandom.h>
148149

149150
#include "net-sysfs.h"
150151

@@ -3558,6 +3559,7 @@ static int xmit_one(struct sk_buff *skb, struct net_device *dev,
35583559
dev_queue_xmit_nit(skb, dev);
35593560

35603561
len = skb->len;
3562+
PRANDOM_ADD_NOISE(skb, dev, txq, len + jiffies);
35613563
trace_net_dev_start_xmit(skb, dev);
35623564
rc = netdev_start_xmit(skb, dev, txq, more);
35633565
trace_net_dev_xmit(skb, rc, dev, len);
@@ -4130,6 +4132,7 @@ static int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
41304132
if (!skb)
41314133
goto out;
41324134

4135+
PRANDOM_ADD_NOISE(skb, dev, txq, jiffies);
41334136
HARD_TX_LOCK(dev, txq, cpu);
41344137

41354138
if (!netif_xmit_stopped(txq)) {
@@ -4195,6 +4198,7 @@ int dev_direct_xmit(struct sk_buff *skb, u16 queue_id)
41954198

41964199
skb_set_queue_mapping(skb, queue_id);
41974200
txq = skb_get_tx_queue(dev, skb);
4201+
PRANDOM_ADD_NOISE(skb, dev, txq, jiffies);
41984202

41994203
local_bh_disable();
42004204

0 commit comments

Comments
 (0)