]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
selftests/landlock: Fix TCP bind(AF_UNSPEC) test case
authorMatthieu Buffet <matthieu@buffet.re>
Mon, 27 Oct 2025 19:07:24 +0000 (20:07 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 23 Jan 2026 10:18:41 +0000 (11:18 +0100)
[ Upstream commit bd09d9a05cf04028f639e209b416bacaeffd4909 ]

The nominal error code for bind(AF_UNSPEC) on an IPv6 socket
is -EAFNOSUPPORT, not -EINVAL. -EINVAL is only returned when
the supplied address struct is too short, which happens to be
the case in current selftests because they treat AF_UNSPEC
like IPv4 sockets do: as an alias for AF_INET (which is a
16-byte struct instead of the 24 bytes required by IPv6
sockets).

Make the union large enough for any address (by adding struct
sockaddr_storage to the union), and make AF_UNSPEC addresses
large enough for any family.

Test for -EAFNOSUPPORT instead, and add a dedicated test case
for truncated inputs with -EINVAL.

Fixes: a549d055a22e ("selftests/landlock: Add network tests")
Signed-off-by: Matthieu Buffet <matthieu@buffet.re>
Link: https://lore.kernel.org/r/20251027190726.626244-2-matthieu@buffet.re
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
tools/testing/selftests/landlock/common.h
tools/testing/selftests/landlock/net_test.c

index 60afc1ce11bcd7c790b3265367a82150b45b15dc..8be801c45f9b9927ed82d70e1daeedbdab86a6a4 100644 (file)
@@ -249,6 +249,7 @@ struct service_fixture {
                        struct sockaddr_un unix_addr;
                        socklen_t unix_addr_len;
                };
+               struct sockaddr_storage _largest;
        };
 };
 
index 376079d70d3fc0bedad4eca4e947cbfd3ddb38bc..c3642c17b251d12340a9381a8ccf6ca777e731c0 100644 (file)
@@ -120,6 +120,10 @@ static socklen_t get_addrlen(const struct service_fixture *const srv,
 {
        switch (srv->protocol.domain) {
        case AF_UNSPEC:
+               if (minimal)
+                       return sizeof(sa_family_t);
+               return sizeof(struct sockaddr_storage);
+
        case AF_INET:
                return sizeof(srv->ipv4_addr);
 
@@ -757,6 +761,11 @@ TEST_F(protocol, bind_unspec)
        bind_fd = socket_variant(&self->srv0);
        ASSERT_LE(0, bind_fd);
 
+       /* Tries to bind with too small addrlen. */
+       EXPECT_EQ(-EINVAL, bind_variant_addrlen(
+                                  bind_fd, &self->unspec_any0,
+                                  get_addrlen(&self->unspec_any0, true) - 1));
+
        /* Allowed bind on AF_UNSPEC/INADDR_ANY. */
        ret = bind_variant(bind_fd, &self->unspec_any0);
        if (variant->prot.domain == AF_INET) {
@@ -765,6 +774,8 @@ TEST_F(protocol, bind_unspec)
                        TH_LOG("Failed to bind to unspec/any socket: %s",
                               strerror(errno));
                }
+       } else if (variant->prot.domain == AF_INET6) {
+               EXPECT_EQ(-EAFNOSUPPORT, ret);
        } else {
                EXPECT_EQ(-EINVAL, ret);
        }
@@ -791,6 +802,8 @@ TEST_F(protocol, bind_unspec)
                } else {
                        EXPECT_EQ(0, ret);
                }
+       } else if (variant->prot.domain == AF_INET6) {
+               EXPECT_EQ(-EAFNOSUPPORT, ret);
        } else {
                EXPECT_EQ(-EINVAL, ret);
        }
@@ -800,7 +813,8 @@ TEST_F(protocol, bind_unspec)
        bind_fd = socket_variant(&self->srv0);
        ASSERT_LE(0, bind_fd);
        ret = bind_variant(bind_fd, &self->unspec_srv0);
-       if (variant->prot.domain == AF_INET) {
+       if (variant->prot.domain == AF_INET ||
+           variant->prot.domain == AF_INET6) {
                EXPECT_EQ(-EAFNOSUPPORT, ret);
        } else {
                EXPECT_EQ(-EINVAL, ret)