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 | ||
