Skip to content

Commit 1532ed0

Browse files
Xuanqiang Luokuba-moo
authored andcommitted
inet: Avoid ehash lookup race in inet_ehash_insert()
Since ehash lookups are lockless, if one CPU performs a lookup while another concurrently deletes and inserts (removing reqsk and inserting sk), the lookup may fail to find the socket, an RST may be sent. The call trace map is drawn as follows: CPU 0 CPU 1 ----- ----- inet_ehash_insert() spin_lock() sk_nulls_del_node_init_rcu(osk) __inet_lookup_established() (lookup failed) __sk_nulls_add_node_rcu(sk, list) spin_unlock() As both deletion and insertion operate on the same ehash chain, this patch introduces a new sk_nulls_replace_node_init_rcu() helper functions to implement atomic replacement. Fixes: 5e0724d ("tcp/dccp: fix hashdance race for passive sessions") Reviewed-by: Kuniyuki Iwashima <[email protected]> Reviewed-by: Jiayuan Chen <[email protected]> Signed-off-by: Xuanqiang Luo <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 9c46092 commit 1532ed0

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed

include/net/sock.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,19 @@ static inline bool sk_nulls_del_node_init_rcu(struct sock *sk)
856856
return rc;
857857
}
858858

859+
static inline bool sk_nulls_replace_node_init_rcu(struct sock *old,
860+
struct sock *new)
861+
{
862+
if (sk_hashed(old)) {
863+
hlist_nulls_replace_init_rcu(&old->sk_nulls_node,
864+
&new->sk_nulls_node);
865+
__sock_put(old);
866+
return true;
867+
}
868+
869+
return false;
870+
}
871+
859872
static inline void __sk_add_node(struct sock *sk, struct hlist_head *list)
860873
{
861874
hlist_add_head(&sk->sk_node, list);

net/ipv4/inet_hashtables.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -720,8 +720,11 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk)
720720
spin_lock(lock);
721721
if (osk) {
722722
WARN_ON_ONCE(sk->sk_hash != osk->sk_hash);
723-
ret = sk_nulls_del_node_init_rcu(osk);
724-
} else if (found_dup_sk) {
723+
ret = sk_nulls_replace_node_init_rcu(osk, sk);
724+
goto unlock;
725+
}
726+
727+
if (found_dup_sk) {
725728
*found_dup_sk = inet_ehash_lookup_by_sk(sk, list);
726729
if (*found_dup_sk)
727730
ret = false;
@@ -730,6 +733,7 @@ bool inet_ehash_insert(struct sock *sk, struct sock *osk, bool *found_dup_sk)
730733
if (ret)
731734
__sk_nulls_add_node_rcu(sk, list);
732735

736+
unlock:
733737
spin_unlock(lock);
734738

735739
return ret;

0 commit comments

Comments
 (0)