Skip to content

Commit

Permalink
tcp: Fix bind() regression for v4-mapped-v6 non-wildcard address.
Browse files Browse the repository at this point in the history
Since bhash2 was introduced, the example below does not work as expected.
These two bind() should conflict, but the 2nd bind() now succeeds.

  from socket import *

  s1 = socket(AF_INET6, SOCK_STREAM)
  s1.bind(('::ffff:127.0.0.1', 0))

  s2 = socket(AF_INET, SOCK_STREAM)
  s2.bind(('127.0.0.1', s1.getsockname()[1]))

During the 2nd bind() in inet_csk_get_port(), inet_bind2_bucket_find()
fails to find the 1st socket's tb2, so inet_bind2_bucket_create() allocates
a new tb2 for the 2nd socket.  Then, we call inet_csk_bind_conflict() that
checks conflicts in the new tb2 by inet_bhash2_conflict().  However, the
new tb2 does not include the 1st socket, thus the bind() finally succeeds.

In this case, inet_bind2_bucket_match() must check if AF_INET6 tb2 has
the conflicting v4-mapped-v6 address so that inet_bind2_bucket_find()
returns the 1st socket's tb2.

Note that if we bind two sockets to 127.0.0.1 and then ::FFFF:127.0.0.1,
the 2nd bind() fails properly for the same reason mentinoed in the previous
commit.

Fixes: 28044fc ("net: Add a bhash2 table hashed by port and address")
Signed-off-by: Kuniyuki Iwashima <[email protected]>
Reviewed-by: Eric Dumazet <[email protected]>
Acked-by: Andrei Vagin <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
q2ven authored and davem330 committed Sep 13, 2023
1 parent aa99e5f commit c48ef9c
Showing 1 changed file with 6 additions and 1 deletion.
7 changes: 6 additions & 1 deletion net/ipv4/inet_hashtables.c
Original file line number Diff line number Diff line change
Expand Up @@ -820,8 +820,13 @@ static bool inet_bind2_bucket_match(const struct inet_bind2_bucket *tb,
return false;

#if IS_ENABLED(CONFIG_IPV6)
if (sk->sk_family != tb->family)
if (sk->sk_family != tb->family) {
if (sk->sk_family == AF_INET)
return ipv6_addr_v4mapped(&tb->v6_rcv_saddr) &&
tb->v6_rcv_saddr.s6_addr32[3] == sk->sk_rcv_saddr;

return false;
}

if (sk->sk_family == AF_INET6)
return ipv6_addr_equal(&tb->v6_rcv_saddr, &sk->sk_v6_rcv_saddr);
Expand Down

0 comments on commit c48ef9c

Please sign in to comment.