All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH] landlock08: add UDP bind/connect test variants
@ 2026-06-30 14:16 Andrea Cervesato
  2026-06-30 15:31 ` [LTP] " linuxtestproject.agent
  2026-06-30 16:53 ` [LTP] [PATCH] " Petr Vorel
  0 siblings, 2 replies; 3+ messages in thread
From: Andrea Cervesato @ 2026-06-30 14:16 UTC (permalink / raw)
  To: Linux Test Project

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>


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [LTP] landlock08: add UDP bind/connect test variants
  2026-06-30 14:16 [LTP] [PATCH] landlock08: add UDP bind/connect test variants Andrea Cervesato
@ 2026-06-30 15:31 ` linuxtestproject.agent
  2026-06-30 16:53 ` [LTP] [PATCH] " Petr Vorel
  1 sibling, 0 replies; 3+ messages in thread
From: linuxtestproject.agent @ 2026-06-30 15:31 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hi Andrea,

On Tue, 30 Jun 2026 16:16:08 +0200, Andrea Cervesato wrote:
> landlock08: add UDP bind/connect test variants

> static void setup(void)
> {
> 	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);

TST_GET_UNUSED_PORT is called with SOCK_STREAM, but addr_port is
also used for the UDP variants (tst_variant 2 and 3) where the
socket type is SOCK_DGRAM.

A port verified free for TCP is not guaranteed to be free for UDP.
Should the port acquisition be moved into run() and use the
variant's socket type instead?

> /*\
>  * Verify the landlock support for bind()/connect() syscalls in IPV4 and IPV6
>  * protocols, using both TCP and UDP. In particular, check that bind() is
>  ...
>  * [Algorithm]
>  *
>  * Repeat the following procedure for {TCP, UDP} x {IPV4, IPV6}:
>  *
>  ...
>  * - create a server listening on PORT1

The algorithm says "create a server listening on PORT1", but for
UDP variants the server only binds -- there is no listen() call.
The code handles this correctly (the SAFE_LISTEN is guarded by
SOCK_STREAM), but the description should probably say something
like "create a server bound on PORT1" or split the TCP/UDP steps.

Verdict - Needs revision

---
Note:

The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.

Regards,
LTP AI Reviewer

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [LTP] [PATCH] landlock08: add UDP bind/connect test variants
  2026-06-30 14:16 [LTP] [PATCH] landlock08: add UDP bind/connect test variants Andrea Cervesato
  2026-06-30 15:31 ` [LTP] " linuxtestproject.agent
@ 2026-06-30 16:53 ` Petr Vorel
  1 sibling, 0 replies; 3+ messages in thread
From: Petr Vorel @ 2026-06-30 16:53 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: Linux Test Project

> 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.

Implements: https://github.com/linux-test-project/ltp/issues/1333

Also why not to mention that it's from kernel 7.2? Saves test reviewers to
search for it.

...
> +++ 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.
Also here I'd add the versions.

>   *
>   * [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"
very nit: IPv4
> +	},
> +	{
> +		AF_INET6, SOCK_STREAM,
> +		LANDLOCK_ACCESS_NET_BIND_TCP,
> +		LANDLOCK_ACCESS_NET_CONNECT_TCP,
> +		4, "TCP/IPV6"
IPv6
(and below)

> +	},
> +	{
> +		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 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");
+1 (but again very nit IPv[46])

...
>  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);

Also agent complains about checking UDP port separately seems to be valid to me.

The rest LGTM.

Kind regards,
Petr

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-06-30 16:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-30 14:16 [LTP] [PATCH] landlock08: add UDP bind/connect test variants Andrea Cervesato
2026-06-30 15:31 ` [LTP] " linuxtestproject.agent
2026-06-30 16:53 ` [LTP] [PATCH] " Petr Vorel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.