mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-19 17:14:40 +08:00
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>
This commit is contained in:
commit
ab6c4ec874
@ -784,6 +784,11 @@ static inline bool ipv6_addr_v4mapped(const struct in6_addr *a)
|
||||
cpu_to_be32(0x0000ffff))) == 0UL;
|
||||
}
|
||||
|
||||
static inline bool ipv6_addr_v4mapped_any(const struct in6_addr *a)
|
||||
{
|
||||
return ipv6_addr_v4mapped(a) && ipv4_is_zeronet(a->s6_addr32[3]);
|
||||
}
|
||||
|
||||
static inline bool ipv6_addr_v4mapped_loopback(const struct in6_addr *a)
|
||||
{
|
||||
return ipv6_addr_v4mapped(a) && ipv4_is_loopback(a->s6_addr32[3]);
|
||||
|
@ -815,41 +815,45 @@ static bool inet_bind2_bucket_match(const struct inet_bind2_bucket *tb,
|
||||
const struct net *net, unsigned short port,
|
||||
int l3mdev, const struct sock *sk)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (sk->sk_family != tb->family)
|
||||
if (!net_eq(ib2_net(tb), net) || tb->port != port ||
|
||||
tb->l3mdev != l3mdev)
|
||||
return false;
|
||||
|
||||
if (sk->sk_family == AF_INET6)
|
||||
return net_eq(ib2_net(tb), net) && tb->port == port &&
|
||||
tb->l3mdev == l3mdev &&
|
||||
ipv6_addr_equal(&tb->v6_rcv_saddr, &sk->sk_v6_rcv_saddr);
|
||||
else
|
||||
#endif
|
||||
return net_eq(ib2_net(tb), net) && tb->port == port &&
|
||||
tb->l3mdev == l3mdev && tb->rcv_saddr == sk->sk_rcv_saddr;
|
||||
}
|
||||
|
||||
bool inet_bind2_bucket_match_addr_any(const struct inet_bind2_bucket *tb, const struct net *net,
|
||||
unsigned short port, int l3mdev, const struct sock *sk)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (sk->sk_family != tb->family) {
|
||||
if (sk->sk_family == AF_INET)
|
||||
return net_eq(ib2_net(tb), net) && tb->port == port &&
|
||||
tb->l3mdev == l3mdev &&
|
||||
ipv6_addr_any(&tb->v6_rcv_saddr);
|
||||
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 net_eq(ib2_net(tb), net) && tb->port == port &&
|
||||
tb->l3mdev == l3mdev &&
|
||||
ipv6_addr_any(&tb->v6_rcv_saddr);
|
||||
else
|
||||
return ipv6_addr_equal(&tb->v6_rcv_saddr, &sk->sk_v6_rcv_saddr);
|
||||
#endif
|
||||
return net_eq(ib2_net(tb), net) && tb->port == port &&
|
||||
tb->l3mdev == l3mdev && tb->rcv_saddr == 0;
|
||||
return tb->rcv_saddr == sk->sk_rcv_saddr;
|
||||
}
|
||||
|
||||
bool inet_bind2_bucket_match_addr_any(const struct inet_bind2_bucket *tb, const struct net *net,
|
||||
unsigned short port, int l3mdev, const struct sock *sk)
|
||||
{
|
||||
if (!net_eq(ib2_net(tb), net) || tb->port != port ||
|
||||
tb->l3mdev != l3mdev)
|
||||
return false;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (sk->sk_family != tb->family) {
|
||||
if (sk->sk_family == AF_INET)
|
||||
return ipv6_addr_any(&tb->v6_rcv_saddr) ||
|
||||
ipv6_addr_v4mapped_any(&tb->v6_rcv_saddr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sk->sk_family == AF_INET6)
|
||||
return ipv6_addr_any(&tb->v6_rcv_saddr);
|
||||
#endif
|
||||
return tb->rcv_saddr == 0;
|
||||
}
|
||||
|
||||
/* The socket's bhash2 hashbucket spinlock must be held when this is called */
|
||||
|
@ -6,41 +6,91 @@
|
||||
|
||||
#include "../kselftest_harness.h"
|
||||
|
||||
struct in6_addr in6addr_v4mapped_any = {
|
||||
.s6_addr = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 255, 255,
|
||||
0, 0, 0, 0
|
||||
}
|
||||
};
|
||||
|
||||
struct in6_addr in6addr_v4mapped_loopback = {
|
||||
.s6_addr = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 255, 255,
|
||||
127, 0, 0, 1
|
||||
}
|
||||
};
|
||||
|
||||
FIXTURE(bind_wildcard)
|
||||
{
|
||||
struct sockaddr_in addr4;
|
||||
struct sockaddr_in6 addr6;
|
||||
int expected_errno;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT(bind_wildcard)
|
||||
{
|
||||
const __u32 addr4_const;
|
||||
const struct in6_addr *addr6_const;
|
||||
int expected_errno;
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_any)
|
||||
{
|
||||
.addr4_const = INADDR_ANY,
|
||||
.addr6_const = &in6addr_any,
|
||||
.expected_errno = EADDRINUSE,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_local)
|
||||
{
|
||||
.addr4_const = INADDR_ANY,
|
||||
.addr6_const = &in6addr_loopback,
|
||||
.expected_errno = 0,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_v4mapped_any)
|
||||
{
|
||||
.addr4_const = INADDR_ANY,
|
||||
.addr6_const = &in6addr_v4mapped_any,
|
||||
.expected_errno = EADDRINUSE,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_any_v6_v4mapped_local)
|
||||
{
|
||||
.addr4_const = INADDR_ANY,
|
||||
.addr6_const = &in6addr_v4mapped_loopback,
|
||||
.expected_errno = EADDRINUSE,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_any)
|
||||
{
|
||||
.addr4_const = INADDR_LOOPBACK,
|
||||
.addr6_const = &in6addr_any,
|
||||
.expected_errno = EADDRINUSE,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_local)
|
||||
{
|
||||
.addr4_const = INADDR_LOOPBACK,
|
||||
.addr6_const = &in6addr_loopback,
|
||||
.expected_errno = 0,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_v4mapped_any)
|
||||
{
|
||||
.addr4_const = INADDR_LOOPBACK,
|
||||
.addr6_const = &in6addr_v4mapped_any,
|
||||
.expected_errno = EADDRINUSE,
|
||||
};
|
||||
|
||||
FIXTURE_VARIANT_ADD(bind_wildcard, v4_local_v6_v4mapped_local)
|
||||
{
|
||||
.addr4_const = INADDR_LOOPBACK,
|
||||
.addr6_const = &in6addr_v4mapped_loopback,
|
||||
.expected_errno = EADDRINUSE,
|
||||
};
|
||||
|
||||
FIXTURE_SETUP(bind_wildcard)
|
||||
@ -52,11 +102,6 @@ FIXTURE_SETUP(bind_wildcard)
|
||||
self->addr6.sin6_family = AF_INET6;
|
||||
self->addr6.sin6_port = htons(0);
|
||||
self->addr6.sin6_addr = *variant->addr6_const;
|
||||
|
||||
if (variant->addr6_const == &in6addr_any)
|
||||
self->expected_errno = EADDRINUSE;
|
||||
else
|
||||
self->expected_errno = 0;
|
||||
}
|
||||
|
||||
FIXTURE_TEARDOWN(bind_wildcard)
|
||||
@ -65,6 +110,7 @@ FIXTURE_TEARDOWN(bind_wildcard)
|
||||
|
||||
void bind_sockets(struct __test_metadata *_metadata,
|
||||
FIXTURE_DATA(bind_wildcard) *self,
|
||||
int expected_errno,
|
||||
struct sockaddr *addr1, socklen_t addrlen1,
|
||||
struct sockaddr *addr2, socklen_t addrlen2)
|
||||
{
|
||||
@ -86,9 +132,9 @@ void bind_sockets(struct __test_metadata *_metadata,
|
||||
ASSERT_GT(fd[1], 0);
|
||||
|
||||
ret = bind(fd[1], addr2, addrlen2);
|
||||
if (self->expected_errno) {
|
||||
if (expected_errno) {
|
||||
ASSERT_EQ(ret, -1);
|
||||
ASSERT_EQ(errno, self->expected_errno);
|
||||
ASSERT_EQ(errno, expected_errno);
|
||||
} else {
|
||||
ASSERT_EQ(ret, 0);
|
||||
}
|
||||
@ -99,14 +145,14 @@ void bind_sockets(struct __test_metadata *_metadata,
|
||||
|
||||
TEST_F(bind_wildcard, v4_v6)
|
||||
{
|
||||
bind_sockets(_metadata, self,
|
||||
(struct sockaddr *)&self->addr4, sizeof(self->addr6),
|
||||
bind_sockets(_metadata, self, variant->expected_errno,
|
||||
(struct sockaddr *)&self->addr4, sizeof(self->addr4),
|
||||
(struct sockaddr *)&self->addr6, sizeof(self->addr6));
|
||||
}
|
||||
|
||||
TEST_F(bind_wildcard, v6_v4)
|
||||
{
|
||||
bind_sockets(_metadata, self,
|
||||
bind_sockets(_metadata, self, variant->expected_errno,
|
||||
(struct sockaddr *)&self->addr6, sizeof(self->addr6),
|
||||
(struct sockaddr *)&self->addr4, sizeof(self->addr4));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user