-From foo@baz Thu 02 Jan 2020 11:13:41 AM CET
+From 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Fri, 13 Dec 2019 18:20:41 -0800
Subject: tcp/dccp: fix possible race __inet_lookup_established()
From: Eric Dumazet <edumazet@google.com>
-[ Upstream commit 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 ]
+commit 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 upstream.
Michal Kubecek and Firo Yang did a very nice analysis of crashes
happening in __inet_lookup_established().
Reviewed-by: Michal Kubecek <mkubecek@suse.cz>
Link: https://lore.kernel.org/netdev/20191120083919.GH27852@unicorn.suse.cz/
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
+Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
---
include/linux/rculist_nulls.h | 37 +++++++++++++++++++++++++++++++++++++
include/net/inet_hashtables.h | 12 +++++++++---
include/net/sock.h | 5 +++++
net/ipv4/inet_diag.c | 3 ++-
- net/ipv4/inet_hashtables.c | 15 +++++++--------
+ net/ipv4/inet_hashtables.c | 18 +++++++++---------
net/ipv4/tcp_ipv4.c | 7 ++++---
- 6 files changed, 64 insertions(+), 15 deletions(-)
+ net/ipv6/inet6_hashtables.c | 3 ++-
+ 7 files changed, 68 insertions(+), 17 deletions(-)
--- a/include/linux/rculist_nulls.h
+++ b/include/linux/rculist_nulls.h
if (!net_eq(sock_net(sk), net))
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
-@@ -442,10 +442,11 @@ static int inet_reuseport_add_sock(struc
+@@ -219,9 +219,10 @@ struct sock *__inet_lookup_listener(stru
+ int score, hiscore = 0, matches = 0, reuseport = 0;
+ bool exact_dif = inet_exact_dif_match(net, skb);
+ struct sock *sk, *result = NULL;
++ struct hlist_nulls_node *node;
+ u32 phash = 0;
+
+- sk_for_each_rcu(sk, &ilb->head) {
++ sk_nulls_for_each_rcu(sk, node, &ilb->nulls_head) {
+ score = compute_score(sk, net, hnum, daddr,
+ dif, sdif, exact_dif);
+ if (score > hiscore) {
+@@ -442,10 +443,11 @@ static int inet_reuseport_add_sock(struc
struct inet_listen_hashbucket *ilb)
{
struct inet_bind_bucket *tb = inet_csk(sk)->icsk_bind_hash;
if (sk2 != sk &&
sk2->sk_family == sk->sk_family &&
ipv6_only_sock(sk2) == ipv6_only_sock(sk) &&
-@@ -480,9 +481,9 @@ int __inet_hash(struct sock *sk, struct
+@@ -480,9 +482,9 @@ int __inet_hash(struct sock *sk, struct
}
if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport &&
sk->sk_family == AF_INET6)
sock_set_flag(sk, SOCK_RCU_FREE);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
unlock:
-@@ -525,10 +526,7 @@ void inet_unhash(struct sock *sk)
+@@ -525,10 +527,7 @@ void inet_unhash(struct sock *sk)
spin_lock_bh(lock);
if (rcu_access_pointer(sk->sk_reuseport_cb))
reuseport_detach_sock(sk);
if (done)
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
spin_unlock_bh(lock);
-@@ -664,7 +662,8 @@ void inet_hashinfo_init(struct inet_hash
+@@ -664,7 +663,8 @@ void inet_hashinfo_init(struct inet_hash
for (i = 0; i < INET_LHTABLE_SIZE; i++) {
spin_lock_init(&h->listening_hash[i].lock);
if (!net_eq(sock_net(sk), net))
continue;
if (sk->sk_family == st->family)
+--- a/net/ipv6/inet6_hashtables.c
++++ b/net/ipv6/inet6_hashtables.c
+@@ -137,9 +137,10 @@ struct sock *inet6_lookup_listener(struc
+ int score, hiscore = 0, matches = 0, reuseport = 0;
+ bool exact_dif = inet6_exact_dif_match(net, skb);
+ struct sock *sk, *result = NULL;
++ struct hlist_nulls_node *node;
+ u32 phash = 0;
+
+- sk_for_each(sk, &ilb->head) {
++ sk_nulls_for_each(sk, node, &ilb->nulls_head) {
+ score = compute_score(sk, net, hnum, daddr, dif, sdif, exact_dif);
+ if (score > hiscore) {
+ reuseport = sk->sk_reuseport;
-From foo@baz Wed 01 Jan 2020 10:36:29 PM CET
+From 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Fri, 13 Dec 2019 18:20:41 -0800
Subject: tcp/dccp: fix possible race __inet_lookup_established()
From: Eric Dumazet <edumazet@google.com>
-[ Upstream commit 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 ]
+commit 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 upstream.
Michal Kubecek and Firo Yang did a very nice analysis of crashes
happening in __inet_lookup_established().
Reviewed-by: Michal Kubecek <mkubecek@suse.cz>
Link: https://lore.kernel.org/netdev/20191120083919.GH27852@unicorn.suse.cz/
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
+Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
---
include/linux/rculist_nulls.h | 37 +++++++++++++++++++++++++++++++++++++
include/net/inet_hashtables.h | 12 +++++++++---
include/net/sock.h | 5 +++++
net/ipv4/inet_diag.c | 3 ++-
- net/ipv4/inet_hashtables.c | 16 ++++++++--------
+ net/ipv4/inet_hashtables.c | 19 ++++++++++---------
net/ipv4/tcp_ipv4.c | 7 ++++---
- 6 files changed, 65 insertions(+), 15 deletions(-)
+ net/ipv6/inet6_hashtables.c | 3 ++-
+ 7 files changed, 69 insertions(+), 17 deletions(-)
--- a/include/linux/rculist_nulls.h
+++ b/include/linux/rculist_nulls.h
if (!net_eq(sock_net(sk), net))
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
-@@ -560,10 +560,11 @@ static int inet_reuseport_add_sock(struc
+@@ -308,6 +308,7 @@ struct sock *__inet_lookup_listener(stru
+ bool exact_dif = inet_exact_dif_match(net, skb);
+ struct inet_listen_hashbucket *ilb2;
+ struct sock *sk, *result = NULL;
++ struct hlist_nulls_node *node;
+ int score, hiscore = 0;
+ unsigned int hash2;
+ u32 phash = 0;
+@@ -343,7 +344,7 @@ struct sock *__inet_lookup_listener(stru
+ goto done;
+
+ port_lookup:
+- sk_for_each_rcu(sk, &ilb->head) {
++ sk_nulls_for_each_rcu(sk, node, &ilb->nulls_head) {
+ score = compute_score(sk, net, hnum, daddr,
+ dif, sdif, exact_dif);
+ if (score > hiscore) {
+@@ -560,10 +561,11 @@ static int inet_reuseport_add_sock(struc
struct inet_listen_hashbucket *ilb)
{
struct inet_bind_bucket *tb = inet_csk(sk)->icsk_bind_hash;
if (sk2 != sk &&
sk2->sk_family == sk->sk_family &&
ipv6_only_sock(sk2) == ipv6_only_sock(sk) &&
-@@ -599,9 +600,9 @@ int __inet_hash(struct sock *sk, struct
+@@ -599,9 +601,9 @@ int __inet_hash(struct sock *sk, struct
}
if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport &&
sk->sk_family == AF_INET6)
inet_hash2(hashinfo, sk);
ilb->count++;
sock_set_flag(sk, SOCK_RCU_FREE);
-@@ -650,11 +651,9 @@ void inet_unhash(struct sock *sk)
+@@ -650,11 +652,9 @@ void inet_unhash(struct sock *sk)
reuseport_detach_sock(sk);
if (ilb) {
inet_unhash2(hashinfo, sk);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
unlock:
spin_unlock_bh(lock);
-@@ -790,7 +789,8 @@ void inet_hashinfo_init(struct inet_hash
+@@ -790,7 +790,8 @@ void inet_hashinfo_init(struct inet_hash
for (i = 0; i < INET_LHTABLE_SIZE; i++) {
spin_lock_init(&h->listening_hash[i].lock);
if (!net_eq(sock_net(sk), net))
continue;
if (sk->sk_family == afinfo->family)
+--- a/net/ipv6/inet6_hashtables.c
++++ b/net/ipv6/inet6_hashtables.c
+@@ -171,6 +171,7 @@ struct sock *inet6_lookup_listener(struc
+ bool exact_dif = inet6_exact_dif_match(net, skb);
+ struct inet_listen_hashbucket *ilb2;
+ struct sock *sk, *result = NULL;
++ struct hlist_nulls_node *node;
+ int score, hiscore = 0;
+ unsigned int hash2;
+ u32 phash = 0;
+@@ -206,7 +207,7 @@ struct sock *inet6_lookup_listener(struc
+ goto done;
+
+ port_lookup:
+- sk_for_each(sk, &ilb->head) {
++ sk_nulls_for_each(sk, node, &ilb->nulls_head) {
+ score = compute_score(sk, net, hnum, daddr, dif, sdif, exact_dif);
+ if (score > hiscore) {
+ if (sk->sk_reuseport) {
-From foo@baz Thu 02 Jan 2020 11:13:41 AM CET
+From 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 Mon Sep 17 00:00:00 2001
From: Eric Dumazet <edumazet@google.com>
Date: Fri, 13 Dec 2019 18:20:41 -0800
Subject: tcp/dccp: fix possible race __inet_lookup_established()
From: Eric Dumazet <edumazet@google.com>
-[ Upstream commit 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 ]
+commit 8dbd76e79a16b45b2ccb01d2f2e08dbf64e71e40 upstream.
Michal Kubecek and Firo Yang did a very nice analysis of crashes
happening in __inet_lookup_established().
Reviewed-by: Michal Kubecek <mkubecek@suse.cz>
Link: https://lore.kernel.org/netdev/20191120083919.GH27852@unicorn.suse.cz/
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
+Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
---
include/linux/rculist_nulls.h | 37 +++++++++++++++++++++++++++++++++++++
include/net/inet_hashtables.h | 12 +++++++++---
include/net/sock.h | 5 +++++
net/ipv4/inet_diag.c | 3 ++-
- net/ipv4/inet_hashtables.c | 15 +++++++--------
+ net/ipv4/inet_hashtables.c | 18 +++++++++---------
net/ipv4/tcp_ipv4.c | 7 ++++---
- 6 files changed, 64 insertions(+), 15 deletions(-)
+ net/ipv6/inet6_hashtables.c | 3 ++-
+ 7 files changed, 68 insertions(+), 17 deletions(-)
--- a/include/linux/rculist_nulls.h
+++ b/include/linux/rculist_nulls.h
if (!net_eq(sock_net(sk), net))
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
-@@ -441,10 +441,11 @@ static int inet_reuseport_add_sock(struc
+@@ -218,9 +218,10 @@ struct sock *__inet_lookup_listener(stru
+ int score, hiscore = 0, matches = 0, reuseport = 0;
+ bool exact_dif = inet_exact_dif_match(net, skb);
+ struct sock *sk, *result = NULL;
++ struct hlist_nulls_node *node;
+ u32 phash = 0;
+
+- sk_for_each_rcu(sk, &ilb->head) {
++ sk_nulls_for_each_rcu(sk, node, &ilb->nulls_head) {
+ score = compute_score(sk, net, hnum, daddr, dif, exact_dif);
+ if (score > hiscore) {
+ reuseport = sk->sk_reuseport;
+@@ -441,10 +442,11 @@ static int inet_reuseport_add_sock(struc
bool match_wildcard))
{
struct inet_bind_bucket *tb = inet_csk(sk)->icsk_bind_hash;
if (sk2 != sk &&
sk2->sk_family == sk->sk_family &&
ipv6_only_sock(sk2) == ipv6_only_sock(sk) &&
-@@ -482,9 +483,9 @@ int __inet_hash(struct sock *sk, struct
+@@ -482,9 +484,9 @@ int __inet_hash(struct sock *sk, struct
}
if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport &&
sk->sk_family == AF_INET6)
sock_set_flag(sk, SOCK_RCU_FREE);
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
unlock:
-@@ -527,10 +528,7 @@ void inet_unhash(struct sock *sk)
+@@ -527,10 +529,7 @@ void inet_unhash(struct sock *sk)
spin_lock_bh(lock);
if (rcu_access_pointer(sk->sk_reuseport_cb))
reuseport_detach_sock(sk);
if (done)
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
spin_unlock_bh(lock);
-@@ -666,7 +664,8 @@ void inet_hashinfo_init(struct inet_hash
+@@ -666,7 +665,8 @@ void inet_hashinfo_init(struct inet_hash
for (i = 0; i < INET_LHTABLE_SIZE; i++) {
spin_lock_init(&h->listening_hash[i].lock);
if (!net_eq(sock_net(sk), net))
continue;
if (sk->sk_family == st->family)
+--- a/net/ipv6/inet6_hashtables.c
++++ b/net/ipv6/inet6_hashtables.c
+@@ -133,9 +133,10 @@ struct sock *inet6_lookup_listener(struc
+ int score, hiscore = 0, matches = 0, reuseport = 0;
+ bool exact_dif = inet6_exact_dif_match(net, skb);
+ struct sock *sk, *result = NULL;
++ struct hlist_nulls_node *node;
+ u32 phash = 0;
+
+- sk_for_each(sk, &ilb->head) {
++ sk_nulls_for_each(sk, node, &ilb->nulls_head) {
+ score = compute_score(sk, net, hnum, daddr, dif, exact_dif);
+ if (score > hiscore) {
+ reuseport = sk->sk_reuseport;