Skip to content

Commit aa99e5f

Browse files
q2vendavem330
authored andcommitted
tcp: Fix bind() regression for v4-mapped-v6 wildcard address.
Andrei Vagin reported bind() regression with strace logs. If we bind() a TCPv6 socket to ::FFFF:0.0.0.0 and then bind() a TCPv4 socket to 127.0.0.1, the 2nd bind() should fail but now succeeds. from socket import * s1 = socket(AF_INET6, SOCK_STREAM) s1.bind(('::ffff:0.0.0.0', 0)) s2 = socket(AF_INET, SOCK_STREAM) s2.bind(('127.0.0.1', s1.getsockname()[1])) During the 2nd bind(), if tb->family is AF_INET6 and sk->sk_family is AF_INET in inet_bind2_bucket_match_addr_any(), we still need to check if tb has the v4-mapped-v6 wildcard address. The example above does not work after commit 5456262 ("net: Fix incorrect address comparison when searching for a bind2 bucket"), but the blamed change is not the commit. Before the commit, the leading zeros of ::FFFF:0.0.0.0 were treated as 0.0.0.0, and the sequence above worked by chance. Technically, this case has been broken since bhash2 was introduced. Note that if we bind() two sockets to 127.0.0.1 and then ::FFFF:0.0.0.0, the 2nd bind() fails properly because we fall back to using bhash to detect conflicts for the v4-mapped-v6 address. Fixes: 28044fc ("net: Add a bhash2 table hashed by port and address") Reported-by: Andrei Vagin <avagin@google.com> Closes: https://lore.kernel.org/netdev/ZPuYBOFC8zsK6r9T@google.com/ Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent c6d2770 commit aa99e5f

File tree

2 files changed

+7
-1
lines changed

2 files changed

+7
-1
lines changed

include/net/ipv6.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,11 @@ static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
784784
cpu_to_be32(0x0000ffff))) == 0UL;
785785
}
786786

787+
static inline bool ipv6_addr_v4mapped_any(const struct in6_addr *a)
788+
{
789+
return ipv6_addr_v4mapped(a) && ipv4_is_zeronet(a->s6_addr32[3]);
790+
}
791+
787792
static inline bool ipv6_addr_v4mapped_loopback(const struct in6_addr *a)
788793
{
789794
return ipv6_addr_v4mapped(a) && ipv4_is_loopback(a->s6_addr32[3]);

net/ipv4/inet_hashtables.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,8 @@ bool inet_bind2_bucket_match_addr_any(const struct inet_bind2_bucket *tb, const
839839
#if IS_ENABLED(CONFIG_IPV6)
840840
if (sk->sk_family != tb->family) {
841841
if (sk->sk_family == AF_INET)
842-
return ipv6_addr_any(&tb->v6_rcv_saddr);
842+
return ipv6_addr_any(&tb->v6_rcv_saddr) ||
843+
ipv6_addr_v4mapped_any(&tb->v6_rcv_saddr);
843844

844845
return false;
845846
}

0 commit comments

Comments
 (0)