commit 518120f41aec30bdde39caf58818e1e5d2d6a4a4 Author: Marc Dionne Date: Fri Jan 15 16:02:32 2016 -0400 soreuseport: Allow bind before setting SO_REUSEPORT If a socket is bound before the SO_REUSEPORT option is set, it will have no sk_reuseport_cb structure allocated and attached to it. If there is then an attempt to bind a second socket to the same port, the first socket will be found as matching and reuseport_add_sock will attempt to use the NULL sk_reuseport_cb pointer, resulting in an oops. Allocate sk_reuseport_cb in setsockopt if not already set. Also, don't preclude reusing a port because the sk has sk_reuseport_cb set. Signed-off-by: Marc Dionne diff --git a/net/core/sock.c b/net/core/sock.c index 5127023..587de5b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -724,6 +724,8 @@ int sock_setsockopt(struct socket *sock, int level, int optname, break; case SO_REUSEPORT: sk->sk_reuseport = valbool; + if (!rcu_access_pointer(sk->sk_reuseport_cb)) + reuseport_alloc(sk); break; case SO_TYPE: case SO_PROTOCOL: diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index dc45b53..13884b6 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -154,7 +154,6 @@ static int udp_lib_lport_inuse(struct net *net, __u16 num, (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && (!sk2->sk_reuseport || !sk->sk_reuseport || - rcu_access_pointer(sk->sk_reuseport_cb) || !uid_eq(uid, sock_i_uid(sk2))) && saddr_comp(sk, sk2, true)) { if (!bitmap) @@ -190,7 +189,6 @@ static int udp_lib_lport_inuse2(struct net *net, __u16 num, (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && (!sk2->sk_reuseport || !sk->sk_reuseport || - rcu_access_pointer(sk->sk_reuseport_cb) || !uid_eq(uid, sock_i_uid(sk2))) && saddr_comp(sk, sk2, true)) { res = 1;