[LTP] [PATCH] landlock08: add UDP bind/connect test variants

Andrea Cervesato andrea.cervesato@suse.de
Tue Jun 30 16:16:08 CEST 2026


From: Andrea Cervesato <andrea.cervesato@suse.com>

Extend the network test to cover the LANDLOCK_ACCESS_NET_BIND_UDP and
LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP access rights introduced with
Landlock ABI v10, alongside the existing TCP rights.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 include/lapi/landlock.h                            |   8 ++
 testcases/kernel/syscalls/landlock/landlock08.c    | 128 ++++++++++++++-------
 .../kernel/syscalls/landlock/landlock_common.h     |   4 +-
 3 files changed, 95 insertions(+), 45 deletions(-)

diff --git a/include/lapi/landlock.h b/include/lapi/landlock.h
index e579500ec26cdc0a568620bc35386f3d2b68952e..54039b3404dd9d717630f0f560e055064acfbe91 100644
--- a/include/lapi/landlock.h
+++ b/include/lapi/landlock.h
@@ -129,6 +129,14 @@ struct landlock_net_port_attr {
 # define LANDLOCK_ACCESS_NET_CONNECT_TCP	(1ULL << 1)
 #endif
 
+#ifndef LANDLOCK_ACCESS_NET_BIND_UDP
+# define LANDLOCK_ACCESS_NET_BIND_UDP		(1ULL << 2)
+#endif
+
+#ifndef LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP
+# define LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP	(1ULL << 3)
+#endif
+
 #ifndef LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
 # define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET		(1ULL << 0)
 #endif
diff --git a/testcases/kernel/syscalls/landlock/landlock08.c b/testcases/kernel/syscalls/landlock/landlock08.c
index 7e7d8470bf49662416f7c83a444876575b29fb16..2012937133658b1315924150db661bf6efb861a4 100644
--- a/testcases/kernel/syscalls/landlock/landlock08.c
+++ b/testcases/kernel/syscalls/landlock/landlock08.c
@@ -5,67 +5,103 @@
 
 /*\
  * Verify the landlock support for bind()/connect() syscalls in IPV4 and IPV6
- * protocols. In particular, check that bind() is assigning the address only on
- * the TCP port enforced by LANDLOCK_ACCESS_NET_BIND_TCP and check that
- * connect() is connecting only to a specific TCP port enforced by
- * LANDLOCK_ACCESS_NET_CONNECT_TCP.
+ * protocols, using both TCP and UDP. In particular, check that bind() is
+ * assigning the address only on the port enforced by
+ * LANDLOCK_ACCESS_NET_BIND_TCP / LANDLOCK_ACCESS_NET_BIND_UDP and check that
+ * connect() is connecting only to a specific port enforced by
+ * LANDLOCK_ACCESS_NET_CONNECT_TCP / LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP.
+ *
+ * TCP rules are available since Landlock ABI v4, while UDP rules are available
+ * since Landlock ABI v10.
  *
  * [Algorithm]
  *
- * Repeat the following procedure for IPV4 and IPV6:
+ * Repeat the following procedure for {TCP, UDP} x {IPV4, IPV6}:
  *
  * - create a socket on PORT1, bind() it and check if it passes
- * - enforce the current sandbox with LANDLOCK_ACCESS_NET_BIND_TCP on PORT1
+ * - enforce the current sandbox with the BIND access right on PORT1
  * - create a socket on PORT1, bind() it and check if it passes
  * - create a socket on PORT2, bind() it and check if it fails
  *
  * - create a server listening on PORT1
  * - create a socket on PORT1, connect() to it and check if it passes
- * - enforce the current sandbox with LANDLOCK_ACCESS_NET_CONNECT_TCP on PORT1
+ * - enforce the current sandbox with the CONNECT access right on PORT1
  * - create a socket on PORT1, connect() to it and check if it passes
  * - create a socket on PORT2, connect() to it and check if it fails
  */
 
 #include "landlock_common.h"
 
-static int variants[] = {
-	AF_INET,
-	AF_INET6,
+static struct tcase {
+	int family;
+	int type;
+	uint64_t bind_access;
+	uint64_t connect_access;
+	int min_abi;
+	const char *desc;
+} variants[] = {
+	{
+		AF_INET, SOCK_STREAM,
+		LANDLOCK_ACCESS_NET_BIND_TCP,
+		LANDLOCK_ACCESS_NET_CONNECT_TCP,
+		4, "TCP/IPV4"
+	},
+	{
+		AF_INET6, SOCK_STREAM,
+		LANDLOCK_ACCESS_NET_BIND_TCP,
+		LANDLOCK_ACCESS_NET_CONNECT_TCP,
+		4, "TCP/IPV6"
+	},
+	{
+		AF_INET, SOCK_DGRAM,
+		LANDLOCK_ACCESS_NET_BIND_UDP,
+		LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP,
+		10, "UDP/IPV4"
+	},
+	{
+		AF_INET6, SOCK_DGRAM,
+		LANDLOCK_ACCESS_NET_BIND_UDP,
+		LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP,
+		10, "UDP/IPV6"
+	},
 };
 
 static struct tst_landlock_ruleset_attr_abi4 *ruleset_attr;
 static struct landlock_net_port_attr *net_port_attr;
 static in_port_t *server_port;
 static int addr_port;
+static int landlock_abi;
 
-static void create_server(const int addr_family)
+static void create_server(const struct tcase *tc)
 {
 	struct socket_data socket;
 	struct sockaddr *addr = NULL;
 
-	create_socket(&socket, addr_family, 0);
-	getsocket_addr(&socket, addr_family, &addr);
+	create_socket(&socket, tc->family, 0, tc->type);
+	getsocket_addr(&socket, tc->family, &addr);
 
 	SAFE_BIND(socket.fd, addr, socket.address_size);
-	SAFE_LISTEN(socket.fd, 1);
 
-	*server_port = getsocket_port(&socket, addr_family);
+	if (tc->type == SOCK_STREAM)
+		SAFE_LISTEN(socket.fd, 1);
 
-	tst_res(TDEBUG, "Server listening on port %u", *server_port);
+	*server_port = getsocket_port(&socket, tc->family);
+
+	tst_res(TDEBUG, "Server bound on port %u", *server_port);
 
 	TST_CHECKPOINT_WAKE_AND_WAIT(0);
 
 	SAFE_CLOSE(socket.fd);
 }
 
-static void test_bind(const int addr_family, const in_port_t port,
+static void test_bind(const struct tcase *tc, const in_port_t port,
 	const int exp_err)
 {
 	struct socket_data socket;
 	struct sockaddr *addr = NULL;
 
-	create_socket(&socket, addr_family, port);
-	getsocket_addr(&socket, addr_family, &addr);
+	create_socket(&socket, tc->family, port, tc->type);
+	getsocket_addr(&socket, tc->family, &addr);
 
 	if (exp_err) {
 		TST_EXP_FAIL(
@@ -80,14 +116,14 @@ static void test_bind(const int addr_family, const in_port_t port,
 	SAFE_CLOSE(socket.fd);
 }
 
-static void test_connect(const int addr_family, const in_port_t port,
+static void test_connect(const struct tcase *tc, const in_port_t port,
 	const int exp_err)
 {
 	struct socket_data socket;
 	struct sockaddr *addr = NULL;
 
-	create_socket(&socket, addr_family, port);
-	getsocket_addr(&socket, addr_family, &addr);
+	create_socket(&socket, tc->family, port, tc->type);
+	getsocket_addr(&socket, tc->family, &addr);
 
 	if (exp_err) {
 		TST_EXP_FAIL(
@@ -102,13 +138,14 @@ static void test_connect(const int addr_family, const in_port_t port,
 	SAFE_CLOSE(socket.fd);
 }
 
-static int check_ipv6_support(void)
+static int check_family_support(const struct tcase *tc)
 {
 	int fd;
 
-	fd = socket(AF_INET6, SOCK_STREAM, 0);
+	fd = socket(tc->family, tc->type, 0);
 	if (fd == -1 && errno == EAFNOSUPPORT) {
-		tst_res(TCONF, "IPv6 not supported in kernel");
+		tst_res(TCONF, "%s address family not supported in kernel",
+			tc->family == AF_INET ? "IPV4" : "IPV6");
 		return 0;
 	}
 	if (fd != -1)
@@ -118,15 +155,21 @@ static int check_ipv6_support(void)
 
 static void run(void)
 {
-	int addr_family = variants[tst_variant];
+	struct tcase *tc = &variants[tst_variant];
+
+	tst_res(TINFO, "Using %s protocol", tc->desc);
+
+	if (landlock_abi < tc->min_abi) {
+		tst_res(TCONF, "%s rules require Landlock ABI v%d",
+			tc->desc, tc->min_abi);
+		return;
+	}
 
-	tst_res(TINFO, "Using %s protocol",
-		addr_family == AF_INET ? "IPV4" : "IPV6");
-	if (addr_family == AF_INET6 && !check_ipv6_support())
+	if (!check_family_support(tc))
 		return;
 
 	if (!SAFE_FORK()) {
-		create_server(addr_family);
+		create_server(tc);
 		exit(0);
 	}
 
@@ -134,10 +177,9 @@ static void run(void)
 
 	/* verify bind() syscall accessibility */
 	if (!SAFE_FORK()) {
-		ruleset_attr->handled_access_net =
-			LANDLOCK_ACCESS_NET_BIND_TCP;
+		ruleset_attr->handled_access_net = tc->bind_access;
 
-		test_bind(addr_family, addr_port, 0);
+		test_bind(tc, addr_port, 0);
 
 		tst_res(TINFO, "Enable bind() access only for port %u",
 			addr_port);
@@ -147,20 +189,19 @@ static void run(void)
 			sizeof(struct tst_landlock_ruleset_attr_abi4),
 			net_port_attr,
 			addr_port,
-			LANDLOCK_ACCESS_NET_BIND_TCP);
+			tc->bind_access);
 
-		test_bind(addr_family, addr_port, 0);
-		test_bind(addr_family, addr_port + 0x80, EACCES);
+		test_bind(tc, addr_port, 0);
+		test_bind(tc, addr_port + 0x80, EACCES);
 
 		exit(0);
 	}
 
 	/* verify connect() syscall accessibility */
 	if (!SAFE_FORK()) {
-		ruleset_attr->handled_access_net =
-			LANDLOCK_ACCESS_NET_CONNECT_TCP;
+		ruleset_attr->handled_access_net = tc->connect_access;
 
-		test_connect(addr_family, *server_port, 0);
+		test_connect(tc, *server_port, 0);
 
 		tst_res(TINFO, "Enable connect() access only on port %u",
 			*server_port);
@@ -170,10 +211,10 @@ static void run(void)
 			sizeof(struct tst_landlock_ruleset_attr_abi4),
 			net_port_attr,
 			*server_port,
-			LANDLOCK_ACCESS_NET_CONNECT_TCP);
+			tc->connect_access);
 
-		test_connect(addr_family, *server_port, 0);
-		test_connect(addr_family, *server_port + 0x80, EACCES);
+		test_connect(tc, *server_port, 0);
+		test_connect(tc, *server_port + 0x80, EACCES);
 
 		TST_CHECKPOINT_WAKE(0);
 
@@ -183,7 +224,8 @@ static void run(void)
 
 static void setup(void)
 {
-	if (verify_landlock_is_enabled() < 4)
+	landlock_abi = verify_landlock_is_enabled();
+	if (landlock_abi < 4)
 		tst_brk(TCONF, "Landlock network is not supported");
 
 	addr_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_STREAM);
diff --git a/testcases/kernel/syscalls/landlock/landlock_common.h b/testcases/kernel/syscalls/landlock/landlock_common.h
index 8857745d6f1c1c30fc914924b8d0da381b36059f..51e57477049003b7e65c13e64303479bfae41224 100644
--- a/testcases/kernel/syscalls/landlock/landlock_common.h
+++ b/testcases/kernel/syscalls/landlock/landlock_common.h
@@ -158,7 +158,7 @@ static inline in_port_t getsocket_port(struct socket_data *socket,
 }
 
 static inline void create_socket(struct socket_data *socket,
-	const int addr_family, const in_port_t port)
+	const int addr_family, const in_port_t port, const int sock_type)
 {
 	memset(socket, 0, sizeof(struct socket_data));
 
@@ -190,7 +190,7 @@ static inline void create_socket(struct socket_data *socket,
 		return;
 	};
 
-	socket->fd = SAFE_SOCKET(addr_family, SOCK_STREAM | SOCK_CLOEXEC, 0);
+	socket->fd = SAFE_SOCKET(addr_family, sock_type | SOCK_CLOEXEC, 0);
 }
 
 static inline void getsocket_addr(struct socket_data *socket,

---
base-commit: 01d0eecd694cab3b95db1394e327bdd40974493e
change-id: 20260630-landlock_udp-2db35b4d43c2

Best regards,
-- 
Andrea Cervesato <andrea.cervesato@suse.com>



More information about the ltp mailing list