diff options
author | David S. Miller <davem@davemloft.net> | 2013-10-19 19:45:46 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-10-19 19:45:46 -0400 |
commit | 7dcade390860712551a4feb080911d5002226188 (patch) | |
tree | 68768a3e760a90b2b13a8e7a83d573c0e63a4a35 /net | |
parent | 53481da372851a5506deb5247302f75459b472b4 (diff) | |
parent | e34c9a69970d8664a36b46e6445a7cc879111cfd (diff) |
Merge branch 'net_get_random_once'
Hannes Frederic Sowa says:
====================
This series implements support for delaying the initialization of secret
keys, e.g. used for hashing, for as long as possible. This functionality
is implemented by a new macro, net_get_random_bytes.
I already used it to protect the socket hashes, the syncookie secret
(most important) and the tcp_fastopen secrets.
Changelog:
v2) Use static_keys in net_get_random_once to have as minimal impact to
the fast-path as possible.
v3) added patch "static_key: WARN on usage before jump_label_init was called":
Patch "x86/jump_label: expect default_nop if static_key gets enabled
on boot-up" relaxes the checks for using static_key primitives before
jump_label_init. So tighten them first.
v4) Update changelog on the patch "static_key: WARN on usage before
jump_label_init was called"
Included patches:
ipv4: split inet_ehashfn to hash functions per compilation unit
ipv6: split inet6_ehashfn to hash functions per compilation unit
static_key: WARN on usage before jump_label_init was called
x86/jump_label: expect default_nop if static_key gets enabled on boot-up
net: introduce new macro net_get_random_once
inet: split syncookie keys for ipv4 and ipv6 and initialize with net_get_random_once
inet: convert inet_ehash_secret and ipv6_hash_secret to net_get_random_once
tcp: switch tcp_fastopen key generation to net_get_random_once
net: switch net_secret key generation to net_get_random_once
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/secure_seq.c | 14 | ||||
-rw-r--r-- | net/core/utils.c | 48 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 27 | ||||
-rw-r--r-- | net/ipv4/inet_hashtables.c | 25 | ||||
-rw-r--r-- | net/ipv4/syncookies.c | 15 | ||||
-rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_fastopen.c | 27 | ||||
-rw-r--r-- | net/ipv4/udp.c | 20 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 5 | ||||
-rw-r--r-- | net/ipv6/inet6_hashtables.c | 33 | ||||
-rw-r--r-- | net/ipv6/syncookies.c | 12 | ||||
-rw-r--r-- | net/ipv6/udp.c | 31 | ||||
-rw-r--r-- | net/rds/connection.c | 12 |
13 files changed, 195 insertions, 79 deletions
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c index 3f1ec1586ae1..b02fd16b8942 100644 --- a/net/core/secure_seq.c +++ b/net/core/secure_seq.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/hrtimer.h> | 7 | #include <linux/hrtimer.h> |
8 | #include <linux/ktime.h> | 8 | #include <linux/ktime.h> |
9 | #include <linux/string.h> | 9 | #include <linux/string.h> |
10 | #include <linux/net.h> | ||
10 | 11 | ||
11 | #include <net/secure_seq.h> | 12 | #include <net/secure_seq.h> |
12 | 13 | ||
@@ -16,18 +17,7 @@ static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned; | |||
16 | 17 | ||
17 | static void net_secret_init(void) | 18 | static void net_secret_init(void) |
18 | { | 19 | { |
19 | u32 tmp; | 20 | net_get_random_once(net_secret, sizeof(net_secret)); |
20 | int i; | ||
21 | |||
22 | if (likely(net_secret[0])) | ||
23 | return; | ||
24 | |||
25 | for (i = NET_SECRET_SIZE; i > 0;) { | ||
26 | do { | ||
27 | get_random_bytes(&tmp, sizeof(tmp)); | ||
28 | } while (!tmp); | ||
29 | cmpxchg(&net_secret[--i], 0, tmp); | ||
30 | } | ||
31 | } | 21 | } |
32 | 22 | ||
33 | #ifdef CONFIG_INET | 23 | #ifdef CONFIG_INET |
diff --git a/net/core/utils.c b/net/core/utils.c index aa88e23fc87a..bf09371e19b1 100644 --- a/net/core/utils.c +++ b/net/core/utils.c | |||
@@ -338,3 +338,51 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, | |||
338 | csum_unfold(*sum))); | 338 | csum_unfold(*sum))); |
339 | } | 339 | } |
340 | EXPORT_SYMBOL(inet_proto_csum_replace16); | 340 | EXPORT_SYMBOL(inet_proto_csum_replace16); |
341 | |||
342 | struct __net_random_once_work { | ||
343 | struct work_struct work; | ||
344 | struct static_key *key; | ||
345 | }; | ||
346 | |||
347 | static void __net_random_once_deferred(struct work_struct *w) | ||
348 | { | ||
349 | struct __net_random_once_work *work = | ||
350 | container_of(w, struct __net_random_once_work, work); | ||
351 | if (!static_key_enabled(work->key)) | ||
352 | static_key_slow_inc(work->key); | ||
353 | kfree(work); | ||
354 | } | ||
355 | |||
356 | static void __net_random_once_disable_jump(struct static_key *key) | ||
357 | { | ||
358 | struct __net_random_once_work *w; | ||
359 | |||
360 | w = kmalloc(sizeof(*w), GFP_ATOMIC); | ||
361 | if (!w) | ||
362 | return; | ||
363 | |||
364 | INIT_WORK(&w->work, __net_random_once_deferred); | ||
365 | w->key = key; | ||
366 | schedule_work(&w->work); | ||
367 | } | ||
368 | |||
369 | bool __net_get_random_once(void *buf, int nbytes, bool *done, | ||
370 | struct static_key *done_key) | ||
371 | { | ||
372 | static DEFINE_SPINLOCK(lock); | ||
373 | |||
374 | spin_lock_bh(&lock); | ||
375 | if (*done) { | ||
376 | spin_unlock_bh(&lock); | ||
377 | return false; | ||
378 | } | ||
379 | |||
380 | get_random_bytes(buf, nbytes); | ||
381 | *done = true; | ||
382 | spin_unlock_bh(&lock); | ||
383 | |||
384 | __net_random_once_disable_jump(done_key); | ||
385 | |||
386 | return true; | ||
387 | } | ||
388 | EXPORT_SYMBOL(__net_get_random_once); | ||
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4049906010f7..9433a6186f54 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -245,29 +245,6 @@ out: | |||
245 | } | 245 | } |
246 | EXPORT_SYMBOL(inet_listen); | 246 | EXPORT_SYMBOL(inet_listen); |
247 | 247 | ||
248 | u32 inet_ehash_secret __read_mostly; | ||
249 | EXPORT_SYMBOL(inet_ehash_secret); | ||
250 | |||
251 | u32 ipv6_hash_secret __read_mostly; | ||
252 | EXPORT_SYMBOL(ipv6_hash_secret); | ||
253 | |||
254 | /* | ||
255 | * inet_ehash_secret must be set exactly once, and to a non nul value | ||
256 | * ipv6_hash_secret must be set exactly once. | ||
257 | */ | ||
258 | void build_ehash_secret(void) | ||
259 | { | ||
260 | u32 rnd; | ||
261 | |||
262 | do { | ||
263 | get_random_bytes(&rnd, sizeof(rnd)); | ||
264 | } while (rnd == 0); | ||
265 | |||
266 | if (cmpxchg(&inet_ehash_secret, 0, rnd) == 0) | ||
267 | get_random_bytes(&ipv6_hash_secret, sizeof(ipv6_hash_secret)); | ||
268 | } | ||
269 | EXPORT_SYMBOL(build_ehash_secret); | ||
270 | |||
271 | /* | 248 | /* |
272 | * Create an inet socket. | 249 | * Create an inet socket. |
273 | */ | 250 | */ |
@@ -284,10 +261,6 @@ static int inet_create(struct net *net, struct socket *sock, int protocol, | |||
284 | int try_loading_module = 0; | 261 | int try_loading_module = 0; |
285 | int err; | 262 | int err; |
286 | 263 | ||
287 | if (unlikely(!inet_ehash_secret)) | ||
288 | if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) | ||
289 | build_ehash_secret(); | ||
290 | |||
291 | sock->state = SS_UNCONNECTED; | 264 | sock->state = SS_UNCONNECTED; |
292 | 265 | ||
293 | /* Look for the requested type/protocol pair. */ | 266 | /* Look for the requested type/protocol pair. */ |
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index a4b66bbe4f21..8b9cf279450d 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
@@ -24,6 +24,31 @@ | |||
24 | #include <net/secure_seq.h> | 24 | #include <net/secure_seq.h> |
25 | #include <net/ip.h> | 25 | #include <net/ip.h> |
26 | 26 | ||
27 | static unsigned int inet_ehashfn(struct net *net, const __be32 laddr, | ||
28 | const __u16 lport, const __be32 faddr, | ||
29 | const __be16 fport) | ||
30 | { | ||
31 | static u32 inet_ehash_secret __read_mostly; | ||
32 | |||
33 | net_get_random_once(&inet_ehash_secret, sizeof(inet_ehash_secret)); | ||
34 | |||
35 | return __inet_ehashfn(laddr, lport, faddr, fport, | ||
36 | inet_ehash_secret + net_hash_mix(net)); | ||
37 | } | ||
38 | |||
39 | |||
40 | static unsigned int inet_sk_ehashfn(const struct sock *sk) | ||
41 | { | ||
42 | const struct inet_sock *inet = inet_sk(sk); | ||
43 | const __be32 laddr = inet->inet_rcv_saddr; | ||
44 | const __u16 lport = inet->inet_num; | ||
45 | const __be32 faddr = inet->inet_daddr; | ||
46 | const __be16 fport = inet->inet_dport; | ||
47 | struct net *net = sock_net(sk); | ||
48 | |||
49 | return inet_ehashfn(net, laddr, lport, faddr, fport); | ||
50 | } | ||
51 | |||
27 | /* | 52 | /* |
28 | * Allocate and initialize a new local port bind bucket. | 53 | * Allocate and initialize a new local port bind bucket. |
29 | * The bindhash mutex for snum's hash chain must be held here. | 54 | * The bindhash mutex for snum's hash chain must be held here. |
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 3b64c59b4109..b95331e6c077 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c | |||
@@ -25,15 +25,7 @@ | |||
25 | 25 | ||
26 | extern int sysctl_tcp_syncookies; | 26 | extern int sysctl_tcp_syncookies; |
27 | 27 | ||
28 | __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; | 28 | static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; |
29 | EXPORT_SYMBOL(syncookie_secret); | ||
30 | |||
31 | static __init int init_syncookies(void) | ||
32 | { | ||
33 | get_random_bytes(syncookie_secret, sizeof(syncookie_secret)); | ||
34 | return 0; | ||
35 | } | ||
36 | __initcall(init_syncookies); | ||
37 | 29 | ||
38 | #define COOKIEBITS 24 /* Upper bits store count */ | 30 | #define COOKIEBITS 24 /* Upper bits store count */ |
39 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) | 31 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) |
@@ -44,8 +36,11 @@ static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], | |||
44 | static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, | 36 | static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, |
45 | u32 count, int c) | 37 | u32 count, int c) |
46 | { | 38 | { |
47 | __u32 *tmp = __get_cpu_var(ipv4_cookie_scratch); | 39 | __u32 *tmp; |
40 | |||
41 | net_get_random_once(syncookie_secret, sizeof(syncookie_secret)); | ||
48 | 42 | ||
43 | tmp = __get_cpu_var(ipv4_cookie_scratch); | ||
49 | memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c])); | 44 | memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c])); |
50 | tmp[0] = (__force u32)saddr; | 45 | tmp[0] = (__force u32)saddr; |
51 | tmp[1] = (__force u32)daddr; | 46 | tmp[1] = (__force u32)daddr; |
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c08f096d46b5..4b161d5aba0b 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c | |||
@@ -274,6 +274,11 @@ static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, | |||
274 | ret = -EINVAL; | 274 | ret = -EINVAL; |
275 | goto bad_key; | 275 | goto bad_key; |
276 | } | 276 | } |
277 | /* Generate a dummy secret but don't publish it. This | ||
278 | * is needed so we don't regenerate a new key on the | ||
279 | * first invocation of tcp_fastopen_cookie_gen | ||
280 | */ | ||
281 | tcp_fastopen_init_key_once(false); | ||
277 | tcp_fastopen_reset_cipher(user_key, TCP_FASTOPEN_KEY_LENGTH); | 282 | tcp_fastopen_reset_cipher(user_key, TCP_FASTOPEN_KEY_LENGTH); |
278 | } | 283 | } |
279 | 284 | ||
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index ab7bd35bb312..766032b4a6c3 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c | |||
@@ -14,6 +14,20 @@ struct tcp_fastopen_context __rcu *tcp_fastopen_ctx; | |||
14 | 14 | ||
15 | static DEFINE_SPINLOCK(tcp_fastopen_ctx_lock); | 15 | static DEFINE_SPINLOCK(tcp_fastopen_ctx_lock); |
16 | 16 | ||
17 | void tcp_fastopen_init_key_once(bool publish) | ||
18 | { | ||
19 | static u8 key[TCP_FASTOPEN_KEY_LENGTH]; | ||
20 | |||
21 | /* tcp_fastopen_reset_cipher publishes the new context | ||
22 | * atomically, so we allow this race happening here. | ||
23 | * | ||
24 | * All call sites of tcp_fastopen_cookie_gen also check | ||
25 | * for a valid cookie, so this is an acceptable risk. | ||
26 | */ | ||
27 | if (net_get_random_once(key, sizeof(key)) && publish) | ||
28 | tcp_fastopen_reset_cipher(key, sizeof(key)); | ||
29 | } | ||
30 | |||
17 | static void tcp_fastopen_ctx_free(struct rcu_head *head) | 31 | static void tcp_fastopen_ctx_free(struct rcu_head *head) |
18 | { | 32 | { |
19 | struct tcp_fastopen_context *ctx = | 33 | struct tcp_fastopen_context *ctx = |
@@ -70,6 +84,8 @@ void tcp_fastopen_cookie_gen(__be32 src, __be32 dst, | |||
70 | __be32 path[4] = { src, dst, 0, 0 }; | 84 | __be32 path[4] = { src, dst, 0, 0 }; |
71 | struct tcp_fastopen_context *ctx; | 85 | struct tcp_fastopen_context *ctx; |
72 | 86 | ||
87 | tcp_fastopen_init_key_once(true); | ||
88 | |||
73 | rcu_read_lock(); | 89 | rcu_read_lock(); |
74 | ctx = rcu_dereference(tcp_fastopen_ctx); | 90 | ctx = rcu_dereference(tcp_fastopen_ctx); |
75 | if (ctx) { | 91 | if (ctx) { |
@@ -78,14 +94,3 @@ void tcp_fastopen_cookie_gen(__be32 src, __be32 dst, | |||
78 | } | 94 | } |
79 | rcu_read_unlock(); | 95 | rcu_read_unlock(); |
80 | } | 96 | } |
81 | |||
82 | static int __init tcp_fastopen_init(void) | ||
83 | { | ||
84 | __u8 key[TCP_FASTOPEN_KEY_LENGTH]; | ||
85 | |||
86 | get_random_bytes(key, sizeof(key)); | ||
87 | tcp_fastopen_reset_cipher(key, sizeof(key)); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | late_initcall(tcp_fastopen_init); | ||
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9f27bb800607..89909dd730dd 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -407,6 +407,18 @@ static inline int compute_score2(struct sock *sk, struct net *net, | |||
407 | return score; | 407 | return score; |
408 | } | 408 | } |
409 | 409 | ||
410 | static unsigned int udp_ehashfn(struct net *net, const __be32 laddr, | ||
411 | const __u16 lport, const __be32 faddr, | ||
412 | const __be16 fport) | ||
413 | { | ||
414 | static u32 udp_ehash_secret __read_mostly; | ||
415 | |||
416 | net_get_random_once(&udp_ehash_secret, sizeof(udp_ehash_secret)); | ||
417 | |||
418 | return __inet_ehashfn(laddr, lport, faddr, fport, | ||
419 | udp_ehash_secret + net_hash_mix(net)); | ||
420 | } | ||
421 | |||
410 | 422 | ||
411 | /* called with read_rcu_lock() */ | 423 | /* called with read_rcu_lock() */ |
412 | static struct sock *udp4_lib_lookup2(struct net *net, | 424 | static struct sock *udp4_lib_lookup2(struct net *net, |
@@ -430,8 +442,8 @@ begin: | |||
430 | badness = score; | 442 | badness = score; |
431 | reuseport = sk->sk_reuseport; | 443 | reuseport = sk->sk_reuseport; |
432 | if (reuseport) { | 444 | if (reuseport) { |
433 | hash = inet_ehashfn(net, daddr, hnum, | 445 | hash = udp_ehashfn(net, daddr, hnum, |
434 | saddr, sport); | 446 | saddr, sport); |
435 | matches = 1; | 447 | matches = 1; |
436 | } | 448 | } |
437 | } else if (score == badness && reuseport) { | 449 | } else if (score == badness && reuseport) { |
@@ -511,8 +523,8 @@ begin: | |||
511 | badness = score; | 523 | badness = score; |
512 | reuseport = sk->sk_reuseport; | 524 | reuseport = sk->sk_reuseport; |
513 | if (reuseport) { | 525 | if (reuseport) { |
514 | hash = inet_ehashfn(net, daddr, hnum, | 526 | hash = udp_ehashfn(net, daddr, hnum, |
515 | saddr, sport); | 527 | saddr, sport); |
516 | matches = 1; | 528 | matches = 1; |
517 | } | 529 | } |
518 | } else if (score == badness && reuseport) { | 530 | } else if (score == badness && reuseport) { |
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index a2cb07cd3850..20af1fb81c83 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c | |||
@@ -110,11 +110,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol, | |||
110 | int try_loading_module = 0; | 110 | int try_loading_module = 0; |
111 | int err; | 111 | int err; |
112 | 112 | ||
113 | if (sock->type != SOCK_RAW && | ||
114 | sock->type != SOCK_DGRAM && | ||
115 | !inet_ehash_secret) | ||
116 | build_ehash_secret(); | ||
117 | |||
118 | /* Look for the requested type/protocol pair. */ | 113 | /* Look for the requested type/protocol pair. */ |
119 | lookup_protocol: | 114 | lookup_protocol: |
120 | err = -ESOCKTNOSUPPORT; | 115 | err = -ESOCKTNOSUPPORT; |
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 842d833dfc18..262e13c02ec2 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c | |||
@@ -23,6 +23,39 @@ | |||
23 | #include <net/secure_seq.h> | 23 | #include <net/secure_seq.h> |
24 | #include <net/ip.h> | 24 | #include <net/ip.h> |
25 | 25 | ||
26 | static unsigned int inet6_ehashfn(struct net *net, | ||
27 | const struct in6_addr *laddr, | ||
28 | const u16 lport, | ||
29 | const struct in6_addr *faddr, | ||
30 | const __be16 fport) | ||
31 | { | ||
32 | static u32 inet6_ehash_secret __read_mostly; | ||
33 | static u32 ipv6_hash_secret __read_mostly; | ||
34 | |||
35 | u32 lhash, fhash; | ||
36 | |||
37 | net_get_random_once(&inet6_ehash_secret, sizeof(inet6_ehash_secret)); | ||
38 | net_get_random_once(&ipv6_hash_secret, sizeof(ipv6_hash_secret)); | ||
39 | |||
40 | lhash = (__force u32)laddr->s6_addr32[3]; | ||
41 | fhash = __ipv6_addr_jhash(faddr, ipv6_hash_secret); | ||
42 | |||
43 | return __inet6_ehashfn(lhash, lport, fhash, fport, | ||
44 | inet6_ehash_secret + net_hash_mix(net)); | ||
45 | } | ||
46 | |||
47 | static int inet6_sk_ehashfn(const struct sock *sk) | ||
48 | { | ||
49 | const struct inet_sock *inet = inet_sk(sk); | ||
50 | const struct in6_addr *laddr = &sk->sk_v6_rcv_saddr; | ||
51 | const struct in6_addr *faddr = &sk->sk_v6_daddr; | ||
52 | const __u16 lport = inet->inet_num; | ||
53 | const __be16 fport = inet->inet_dport; | ||
54 | struct net *net = sock_net(sk); | ||
55 | |||
56 | return inet6_ehashfn(net, laddr, lport, faddr, fport); | ||
57 | } | ||
58 | |||
26 | int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw) | 59 | int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw) |
27 | { | 60 | { |
28 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; | 61 | struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; |
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index d04d3f1dd9b7..535a3ad262f1 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #define COOKIEBITS 24 /* Upper bits store count */ | 24 | #define COOKIEBITS 24 /* Upper bits store count */ |
25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) | 25 | #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) |
26 | 26 | ||
27 | static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS]; | ||
28 | |||
27 | /* RFC 2460, Section 8.3: | 29 | /* RFC 2460, Section 8.3: |
28 | * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..] | 30 | * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..] |
29 | * | 31 | * |
@@ -61,14 +63,18 @@ static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], | |||
61 | static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, | 63 | static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr, |
62 | __be16 sport, __be16 dport, u32 count, int c) | 64 | __be16 sport, __be16 dport, u32 count, int c) |
63 | { | 65 | { |
64 | __u32 *tmp = __get_cpu_var(ipv6_cookie_scratch); | 66 | __u32 *tmp; |
67 | |||
68 | net_get_random_once(syncookie6_secret, sizeof(syncookie6_secret)); | ||
69 | |||
70 | tmp = __get_cpu_var(ipv6_cookie_scratch); | ||
65 | 71 | ||
66 | /* | 72 | /* |
67 | * we have 320 bits of information to hash, copy in the remaining | 73 | * we have 320 bits of information to hash, copy in the remaining |
68 | * 192 bits required for sha_transform, from the syncookie_secret | 74 | * 192 bits required for sha_transform, from the syncookie6_secret |
69 | * and overwrite the digest with the secret | 75 | * and overwrite the digest with the secret |
70 | */ | 76 | */ |
71 | memcpy(tmp + 10, syncookie_secret[c], 44); | 77 | memcpy(tmp + 10, syncookie6_secret[c], 44); |
72 | memcpy(tmp, saddr, 16); | 78 | memcpy(tmp, saddr, 16); |
73 | memcpy(tmp + 4, daddr, 16); | 79 | memcpy(tmp + 4, daddr, 16); |
74 | tmp[8] = ((__force u32)sport << 16) + (__force u32)dport; | 80 | tmp[8] = ((__force u32)sport << 16) + (__force u32)dport; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b496de19a341..44fc4e3d661f 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -53,6 +53,29 @@ | |||
53 | #include <trace/events/skb.h> | 53 | #include <trace/events/skb.h> |
54 | #include "udp_impl.h" | 54 | #include "udp_impl.h" |
55 | 55 | ||
56 | static unsigned int udp6_ehashfn(struct net *net, | ||
57 | const struct in6_addr *laddr, | ||
58 | const u16 lport, | ||
59 | const struct in6_addr *faddr, | ||
60 | const __be16 fport) | ||
61 | { | ||
62 | static u32 udp6_ehash_secret __read_mostly; | ||
63 | static u32 udp_ipv6_hash_secret __read_mostly; | ||
64 | |||
65 | u32 lhash, fhash; | ||
66 | |||
67 | net_get_random_once(&udp6_ehash_secret, | ||
68 | sizeof(udp6_ehash_secret)); | ||
69 | net_get_random_once(&udp_ipv6_hash_secret, | ||
70 | sizeof(udp_ipv6_hash_secret)); | ||
71 | |||
72 | lhash = (__force u32)laddr->s6_addr32[3]; | ||
73 | fhash = __ipv6_addr_jhash(faddr, udp_ipv6_hash_secret); | ||
74 | |||
75 | return __inet6_ehashfn(lhash, lport, fhash, fport, | ||
76 | udp_ipv6_hash_secret + net_hash_mix(net)); | ||
77 | } | ||
78 | |||
56 | int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | 79 | int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) |
57 | { | 80 | { |
58 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 81 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
@@ -214,8 +237,8 @@ begin: | |||
214 | badness = score; | 237 | badness = score; |
215 | reuseport = sk->sk_reuseport; | 238 | reuseport = sk->sk_reuseport; |
216 | if (reuseport) { | 239 | if (reuseport) { |
217 | hash = inet6_ehashfn(net, daddr, hnum, | 240 | hash = udp6_ehashfn(net, daddr, hnum, |
218 | saddr, sport); | 241 | saddr, sport); |
219 | matches = 1; | 242 | matches = 1; |
220 | } else if (score == SCORE2_MAX) | 243 | } else if (score == SCORE2_MAX) |
221 | goto exact_match; | 244 | goto exact_match; |
@@ -295,8 +318,8 @@ begin: | |||
295 | badness = score; | 318 | badness = score; |
296 | reuseport = sk->sk_reuseport; | 319 | reuseport = sk->sk_reuseport; |
297 | if (reuseport) { | 320 | if (reuseport) { |
298 | hash = inet6_ehashfn(net, daddr, hnum, | 321 | hash = udp6_ehashfn(net, daddr, hnum, |
299 | saddr, sport); | 322 | saddr, sport); |
300 | matches = 1; | 323 | matches = 1; |
301 | } | 324 | } |
302 | } else if (score == badness && reuseport) { | 325 | } else if (score == badness && reuseport) { |
diff --git a/net/rds/connection.c b/net/rds/connection.c index 642ad42c416b..378c3a6acf84 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c | |||
@@ -51,10 +51,16 @@ static struct kmem_cache *rds_conn_slab; | |||
51 | 51 | ||
52 | static struct hlist_head *rds_conn_bucket(__be32 laddr, __be32 faddr) | 52 | static struct hlist_head *rds_conn_bucket(__be32 laddr, __be32 faddr) |
53 | { | 53 | { |
54 | static u32 rds_hash_secret __read_mostly; | ||
55 | |||
56 | unsigned long hash; | ||
57 | |||
58 | net_get_random_once(&rds_hash_secret, sizeof(rds_hash_secret)); | ||
59 | |||
54 | /* Pass NULL, don't need struct net for hash */ | 60 | /* Pass NULL, don't need struct net for hash */ |
55 | unsigned long hash = inet_ehashfn(NULL, | 61 | hash = __inet_ehashfn(be32_to_cpu(laddr), 0, |
56 | be32_to_cpu(laddr), 0, | 62 | be32_to_cpu(faddr), 0, |
57 | be32_to_cpu(faddr), 0); | 63 | rds_hash_secret); |
58 | return &rds_conn_hash[hash & RDS_CONNECTION_HASH_MASK]; | 64 | return &rds_conn_hash[hash & RDS_CONNECTION_HASH_MASK]; |
59 | } | 65 | } |
60 | 66 | ||