Skip to content

Commit ab6c4ec

Browse files
committed
Merge branch 'tcp-bind-fixes'
Kuniyuki Iwashima says: ==================== tcp: Fix bind() regression for v4-mapped-v6 address Since bhash2 was introduced, bind() is broken in two cases related to v4-mapped-v6 address. This series fixes the regression and adds test to cover the cases. Changes: v2: * Added patch 1 to factorise duplicated comparison (Eric Dumazet) v1: https://lore.kernel.org/netdev/20230911165106.39384-1-kuniyu@amazon.com/ ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 8cdd9f1 + 8637d8e commit ab6c4ec

File tree

3 files changed

+82
-27
lines changed

3 files changed

+82
-27
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: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -815,41 +815,45 @@ static bool inet_bind2_bucket_match(const struct inet_bind2_bucket *tb,
815815
const struct net *net, unsigned short port,
816816
int l3mdev, const struct sock *sk)
817817
{
818+
if (!net_eq(ib2_net(tb), net) || tb->port != port ||
819+
tb->l3mdev != l3mdev)
820+
return false;
821+
818822
#if IS_ENABLED(CONFIG_IPV6)
819-
if (sk->sk_family != tb->family)
823+
if (sk->sk_family != tb->family) {
824+
if (sk->sk_family == AF_INET)
825+
return ipv6_addr_v4mapped(&tb->v6_rcv_saddr) &&
826+
tb->v6_rcv_saddr.s6_addr32[3] == sk->sk_rcv_saddr;
827+
820828
return false;
829+
}
821830

822831
if (sk->sk_family == AF_INET6)
823-
return net_eq(ib2_net(tb), net) && tb->port == port &&
824-
tb->l3mdev == l3mdev &&
825-
ipv6_addr_equal(&tb->v6_rcv_saddr, &sk->sk_v6_rcv_saddr);
826-
else
832+
return ipv6_addr_equal(&tb->v6_rcv_saddr, &sk->sk_v6_rcv_saddr);
827833
#endif
828-
return net_eq(ib2_net(tb), net) && tb->port == port &&
829-
tb->l3mdev == l3mdev && tb->rcv_saddr == sk->sk_rcv_saddr;
834+
return tb->rcv_saddr == sk->sk_rcv_saddr;
830835
}
831836

832837
bool inet_bind2_bucket_match_addr_any(const struct inet_bind2_bucket *tb, const struct net *net,
833838
unsigned short port, int l3mdev, const struct sock *sk)
834839
{
840+
if (!net_eq(ib2_net(tb), net) || tb->port != port ||
841+
tb->l3mdev != l3mdev)
842+
return false;
843+
835844
#if IS_ENABLED(CONFIG_IPV6)
836845
if (sk->sk_family != tb->family) {
837846
if (sk->sk_family == AF_INET)
838-
return net_eq(ib2_net(tb), net) && tb->port == port &&
839-
tb->l3mdev == l3mdev &&
840-
ipv6_addr_any(&tb->v6_rcv_saddr);
847+
return ipv6_addr_any(&tb->v6_rcv_saddr) ||
848+
ipv6_addr_v4mapped_any(&tb->v6_rcv_saddr);
841849

842850
return false;
843851
}
844852

845853
if (sk->sk_family == AF_INET6)
846-
return net_eq(ib2_net(tb), net) && tb->port == port &&
847-
tb->l3mdev == l3mdev &&
848-
ipv6_addr_any(&tb->v6_rcv_saddr);
849-
else
854+
return ipv6_addr_any(&tb->v6_rcv_saddr);
850855
#endif
851-
return net_eq(ib2_net(tb), net) && tb->port == port &&
852-
tb->l3mdev == l3mdev && tb->rcv_saddr == 0;
856+
return tb->rcv_saddr == 0;
853857
}
854858

855859
/* The socket's bhash2 hashbucket spinlock must be held when this is called */

tools/testing/selftests/net/bind_wildcard.c

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,41 +6,91 @@
66

77
#include "../kselftest_harness.h"
88

9+
struct in6_addr in6addr_v4mapped_any = {
10+
.s6_addr = {
11+
0, 0, 0, 0,
12+
0, 0, 0, 0,
13+
0, 0, 255, 255,
14+
0, 0, 0, 0
15+
}
16+
};
17+
18+
struct in6_addr in6addr_v4mapped_loopback = {
19+
.s6_addr = {
20+
0, 0, 0, 0,
21+
0, 0, 0, 0,
22+
0, 0, 255, 255,
23+
127, 0, 0, 1
24+
}
25+
};
26+
927
FIXTURE(bind_wildcard)
1028
{
1129
struct sockaddr_in addr4;
1230
struct sockaddr_in6 addr6;
13-
int expected_errno;
1431
};
1532

1633
FIXTURE_VARIANT(bind_wildcard)
1734
{
1835
const __u32 addr4_const;
1936
const struct in6_addr *addr6_const;
37+
int expected_errno;
2038
};
2139

2240
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_any)
2341
{
2442
.addr4_const = INADDR_ANY,
2543
.addr6_const = &in6addr_any,
44+
.expected_errno = EADDRINUSE,
2645
};
2746

2847
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_local)
2948
{
3049
.addr4_const = INADDR_ANY,
3150
.addr6_const = &in6addr_loopback,
51+
.expected_errno = 0,
52+
};
53+
54+
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_v4mapped_any)
55+
{
56+
.addr4_const = INADDR_ANY,
57+
.addr6_const = &in6addr_v4mapped_any,
58+
.expected_errno = EADDRINUSE,
59+
};
60+
61+
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_v4mapped_local)
62+
{
63+
.addr4_const = INADDR_ANY,
64+
.addr6_const = &in6addr_v4mapped_loopback,
65+
.expected_errno = EADDRINUSE,
3266
};
3367

3468
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_any)
3569
{
3670
.addr4_const = INADDR_LOOPBACK,
3771
.addr6_const = &in6addr_any,
72+
.expected_errno = EADDRINUSE,
3873
};
3974

4075
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_local)
4176
{
4277
.addr4_const = INADDR_LOOPBACK,
4378
.addr6_const = &in6addr_loopback,
79+
.expected_errno = 0,
80+
};
81+
82+
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_v4mapped_any)
83+
{
84+
.addr4_const = INADDR_LOOPBACK,
85+
.addr6_const = &in6addr_v4mapped_any,
86+
.expected_errno = EADDRINUSE,
87+
};
88+
89+
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_v4mapped_local)
90+
{
91+
.addr4_const = INADDR_LOOPBACK,
92+
.addr6_const = &in6addr_v4mapped_loopback,
93+
.expected_errno = EADDRINUSE,
4494
};
4595

4696
FIXTURE_SETUP(bind_wildcard)
@@ -52,11 +102,6 @@ FIXTURE_SETUP(bind_wildcard)
52102
self->addr6.sin6_family = AF_INET6;
53103
self->addr6.sin6_port = htons(0);
54104
self->addr6.sin6_addr = *variant->addr6_const;
55-
56-
if (variant->addr6_const == &in6addr_any)
57-
self->expected_errno = EADDRINUSE;
58-
else
59-
self->expected_errno = 0;
60105
}
61106

62107
FIXTURE_TEARDOWN(bind_wildcard)
@@ -65,6 +110,7 @@ FIXTURE_TEARDOWN(bind_wildcard)
65110

66111
void bind_sockets(struct __test_metadata *_metadata,
67112
FIXTURE_DATA(bind_wildcard) *self,
113+
int expected_errno,
68114
struct sockaddr *addr1, socklen_t addrlen1,
69115
struct sockaddr *addr2, socklen_t addrlen2)
70116
{
@@ -86,9 +132,9 @@ void bind_sockets(struct __test_metadata *_metadata,
86132
ASSERT_GT(fd[1], 0);
87133

88134
ret = bind(fd[1], addr2, addrlen2);
89-
if (self->expected_errno) {
135+
if (expected_errno) {
90136
ASSERT_EQ(ret, -1);
91-
ASSERT_EQ(errno, self->expected_errno);
137+
ASSERT_EQ(errno, expected_errno);
92138
} else {
93139
ASSERT_EQ(ret, 0);
94140
}
@@ -99,14 +145,14 @@ void bind_sockets(struct __test_metadata *_metadata,
99145

100146
TEST_F(bind_wildcard, v4_v6)
101147
{
102-
bind_sockets(_metadata, self,
103-
(struct sockaddr *)&self->addr4, sizeof(self->addr6),
148+
bind_sockets(_metadata, self, variant->expected_errno,
149+
(struct sockaddr *)&self->addr4, sizeof(self->addr4),
104150
(struct sockaddr *)&self->addr6, sizeof(self->addr6));
105151
}
106152

107153
TEST_F(bind_wildcard, v6_v4)
108154
{
109-
bind_sockets(_metadata, self,
155+
bind_sockets(_metadata, self, variant->expected_errno,
110156
(struct sockaddr *)&self->addr6, sizeof(self->addr6),
111157
(struct sockaddr *)&self->addr4, sizeof(self->addr4));
112158
}

0 commit comments

Comments
 (0)