Skip to content

Commit 3b0b4d2

Browse files
kraigatgooggregkh
authored andcommitted
soreuseport: fix initialization race
[ Upstream commit 1b5f962 ] Syzkaller stumbled upon a way to trigger WARNING: CPU: 1 PID: 13881 at net/core/sock_reuseport.c:41 reuseport_alloc+0x306/0x3b0 net/core/sock_reuseport.c:39 There are two initialization paths for the sock_reuseport structure in a socket: Through the udp/tcp bind paths of SO_REUSEPORT sockets or through SO_ATTACH_REUSEPORT_[CE]BPF before bind. The existing implementation assumedthat the socket lock protected both of these paths when it actually only protects the SO_ATTACH_REUSEPORT path. Syzkaller triggered this double allocation by running these paths concurrently. This patch moves the check for double allocation into the reuseport_alloc function which is protected by a global spin lock. Fixes: e32ea7e ("soreuseport: fast reuseport UDP socket selection") Fixes: c125e80 ("soreuseport: fast reuseport TCP socket selection") Signed-off-by: Craig Gallek <kraig@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 57ffb0e commit 3b0b4d2

3 files changed

Lines changed: 11 additions & 11 deletions

File tree

net/core/sock_reuseport.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,14 @@ int reuseport_alloc(struct sock *sk)
3636
* soft irq of receive path or setsockopt from process context
3737
*/
3838
spin_lock_bh(&reuseport_lock);
39-
WARN_ONCE(rcu_dereference_protected(sk->sk_reuseport_cb,
40-
lockdep_is_held(&reuseport_lock)),
41-
"multiple allocations for the same socket");
39+
40+
/* Allocation attempts can occur concurrently via the setsockopt path
41+
* and the bind/hash path. Nothing to do when we lose the race.
42+
*/
43+
if (rcu_dereference_protected(sk->sk_reuseport_cb,
44+
lockdep_is_held(&reuseport_lock)))
45+
goto out;
46+
4247
reuse = __reuseport_alloc(INIT_SOCKS);
4348
if (!reuse) {
4449
spin_unlock_bh(&reuseport_lock);
@@ -49,6 +54,7 @@ int reuseport_alloc(struct sock *sk)
4954
reuse->num_socks = 1;
5055
rcu_assign_pointer(sk->sk_reuseport_cb, reuse);
5156

57+
out:
5258
spin_unlock_bh(&reuseport_lock);
5359

5460
return 0;

net/ipv4/inet_hashtables.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -455,10 +455,7 @@ static int inet_reuseport_add_sock(struct sock *sk,
455455
return reuseport_add_sock(sk, sk2);
456456
}
457457

458-
/* Initial allocation may have already happened via setsockopt */
459-
if (!rcu_access_pointer(sk->sk_reuseport_cb))
460-
return reuseport_alloc(sk);
461-
return 0;
458+
return reuseport_alloc(sk);
462459
}
463460

464461
int __inet_hash(struct sock *sk, struct sock *osk,

net/ipv4/udp.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,7 @@ static int udp_reuseport_add_sock(struct sock *sk, struct udp_hslot *hslot,
222222
}
223223
}
224224

225-
/* Initial allocation may have already happened via setsockopt */
226-
if (!rcu_access_pointer(sk->sk_reuseport_cb))
227-
return reuseport_alloc(sk);
228-
return 0;
225+
return reuseport_alloc(sk);
229226
}
230227

231228
/**

0 commit comments

Comments
 (0)