tcp: bind() fix when many ports are bound

Port autoselection done by kernel only works when number of bound
sockets is under a threshold (typically 30000).

When this threshold is over, we must check if there is a conflict before
exiting first loop in inet_csk_get_port()

Change inet_csk_bind_conflict() to forbid two reuse-enabled sockets to
bind on same (address,port) tuple (with a non ANY address)

Same change for inet6_csk_bind_conflict()

Reported-by: Gaspar Chilingarov <gasparch@gmail.com>
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by Eric Dumazet and committed by David S. Miller fda48a0d 24acc689

+21 -10
+11 -5
net/ipv4/inet_connection_sock.c
··· 70 70 (!sk->sk_bound_dev_if || 71 71 !sk2->sk_bound_dev_if || 72 72 sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { 73 + const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); 74 + 73 75 if (!reuse || !sk2->sk_reuse || 74 76 sk2->sk_state == TCP_LISTEN) { 75 - const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); 76 77 if (!sk2_rcv_saddr || !sk_rcv_saddr || 77 78 sk2_rcv_saddr == sk_rcv_saddr) 78 79 break; 79 - } 80 + } else if (reuse && sk2->sk_reuse && 81 + sk2_rcv_saddr && 82 + sk2_rcv_saddr == sk_rcv_saddr) 83 + break; 80 84 } 81 85 } 82 86 return node != NULL; ··· 124 120 smallest_size = tb->num_owners; 125 121 smallest_rover = rover; 126 122 if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) { 127 - spin_unlock(&head->lock); 128 - snum = smallest_rover; 129 - goto have_snum; 123 + if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) { 124 + spin_unlock(&head->lock); 125 + snum = smallest_rover; 126 + goto have_snum; 127 + } 130 128 } 131 129 } 132 130 goto next;
+10 -5
net/ipv6/inet6_connection_sock.c
··· 42 42 if (sk != sk2 && 43 43 (!sk->sk_bound_dev_if || 44 44 !sk2->sk_bound_dev_if || 45 - sk->sk_bound_dev_if == sk2->sk_bound_dev_if) && 46 - (!sk->sk_reuse || !sk2->sk_reuse || 47 - sk2->sk_state == TCP_LISTEN) && 48 - ipv6_rcv_saddr_equal(sk, sk2)) 49 - break; 45 + sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { 46 + if ((!sk->sk_reuse || !sk2->sk_reuse || 47 + sk2->sk_state == TCP_LISTEN) && 48 + ipv6_rcv_saddr_equal(sk, sk2)) 49 + break; 50 + else if (sk->sk_reuse && sk2->sk_reuse && 51 + !ipv6_addr_any(inet6_rcv_saddr(sk2)) && 52 + ipv6_rcv_saddr_equal(sk, sk2)) 53 + break; 54 + } 50 55 } 51 56 52 57 return node != NULL;