Commit c191a836 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

tcp: disallow bind() to reuse addr/port

inet_csk_bind_conflict() logic currently disallows a bind() if
it finds a friend socket (a socket bound on same address/port)
satisfying a set of conditions :

1) Current (to be bound) socket doesnt have sk_reuse set
OR
2) other socket doesnt have sk_reuse set
OR
3) other socket is in LISTEN state

We should add the CLOSE state in the 3) condition, in order to avoid two
REUSEADDR sockets in CLOSE state with same local address/port, since
this can deny further operations.

Note : a prior patch tried to address the problem in a different (and
buggy) way. (commit fda48a0d tcp: bind() fix when many ports
are bound).
Reported-by: default avatarGaspar Chilingarov <gasparch@gmail.com>
Reported-by: default avatarDaniel Baluta <daniel.baluta@gmail.com>
Tested-by: default avatarDaniel Baluta <daniel.baluta@gmail.com>
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 42b82dc1
...@@ -73,7 +73,7 @@ int inet_csk_bind_conflict(const struct sock *sk, ...@@ -73,7 +73,7 @@ int inet_csk_bind_conflict(const struct sock *sk,
!sk2->sk_bound_dev_if || !sk2->sk_bound_dev_if ||
sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
if (!reuse || !sk2->sk_reuse || if (!reuse || !sk2->sk_reuse ||
sk2->sk_state == TCP_LISTEN) { ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) {
const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2); const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) || if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) ||
sk2_rcv_saddr == sk_rcv_saddr(sk)) sk2_rcv_saddr == sk_rcv_saddr(sk))
...@@ -122,7 +122,8 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) ...@@ -122,7 +122,8 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
(tb->num_owners < smallest_size || smallest_size == -1)) { (tb->num_owners < smallest_size || smallest_size == -1)) {
smallest_size = tb->num_owners; smallest_size = tb->num_owners;
smallest_rover = rover; smallest_rover = rover;
if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) { if (atomic_read(&hashinfo->bsockets) > (high - low) + 1 &&
!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
spin_unlock(&head->lock); spin_unlock(&head->lock);
snum = smallest_rover; snum = smallest_rover;
goto have_snum; goto have_snum;
......
...@@ -44,7 +44,7 @@ int inet6_csk_bind_conflict(const struct sock *sk, ...@@ -44,7 +44,7 @@ int inet6_csk_bind_conflict(const struct sock *sk,
!sk2->sk_bound_dev_if || !sk2->sk_bound_dev_if ||
sk->sk_bound_dev_if == sk2->sk_bound_dev_if) && sk->sk_bound_dev_if == sk2->sk_bound_dev_if) &&
(!sk->sk_reuse || !sk2->sk_reuse || (!sk->sk_reuse || !sk2->sk_reuse ||
sk2->sk_state == TCP_LISTEN) && ((1 << sk2->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) &&
ipv6_rcv_saddr_equal(sk, sk2)) ipv6_rcv_saddr_equal(sk, sk2))
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment