From: "Günther Noack" <gnoack3000@gmail.com>
To: "Mickaël Salaün" <mic@digikod.net>
Cc: "Matthieu Baerts" <matttbe@kernel.org>,
"Mat Martineau" <martineau@kernel.org>,
"Geliang Tang" <geliang@kernel.org>,
"Mikhail Ivanov" <ivanov.mikhail1@huawei-partners.com>,
mptcp@lists.linux.dev, netdev@vger.kernel.org,
linux-security-module@vger.kernel.org,
"Günther Noack" <gnoack3000@gmail.com>
Subject: [PATCH 4/6] selftests/landlock: Add MPTCP network access tests
Date: Sun, 30 Aug 2026 22:16:48 +0200 [thread overview]
Message-ID: <20260830201650.67050-5-gnoack3000@gmail.com> (raw)
In-Reply-To: <20260830201650.67050-1-gnoack3000@gmail.com>
Test LANDLOCK_ACCESS_NET_BIND_MPTCP and LANDLOCK_ACCESS_NET_CONNECT_MPTCP:
* Add the MPTCP_SANDBOX variant to the net_test fixtures.
* Introduce prot_*() helper functions for audit tests.
* Extend existing tests as needed for MPTCP, including the tcp_fastopen test.
Signed-off-by: Günther Noack <gnoack3000@gmail.com>
---
tools/testing/selftests/landlock/net_test.c | 256 ++++++++++++++++----
1 file changed, 210 insertions(+), 46 deletions(-)
diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index 3a0482beca5f..fbb3a99bc380 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -40,6 +40,7 @@ enum sandbox_type {
/* This may be used to test rules that allow *and* deny accesses. */
TCP_SANDBOX,
UDP_SANDBOX,
+ MPTCP_SANDBOX,
};
static int set_service(struct service_fixture *const srv,
@@ -105,6 +106,12 @@ static bool prot_is_udp(const struct protocol_variant *const prot)
(prot->protocol == IPPROTO_UDP || prot->protocol == IPPROTO_IP);
}
+static bool prot_is_mptcp(const struct protocol_variant *const prot)
+{
+ return (prot->domain == AF_INET || prot->domain == AF_INET6) &&
+ prot->type == SOCK_STREAM && prot->protocol == IPPROTO_MPTCP;
+}
+
static bool is_restricted(const struct protocol_variant *const prot,
const enum sandbox_type sandbox)
{
@@ -113,6 +120,8 @@ static bool is_restricted(const struct protocol_variant *const prot,
return prot_is_tcp(prot);
case UDP_SANDBOX:
return prot_is_udp(prot);
+ case MPTCP_SANDBOX:
+ return prot_is_mptcp(prot);
case NO_SANDBOX:
default:
return false;
@@ -126,6 +135,8 @@ static __u64 sandbox_bind_access(const enum sandbox_type sandbox)
return LANDLOCK_ACCESS_NET_BIND_TCP;
case UDP_SANDBOX:
return LANDLOCK_ACCESS_NET_BIND_UDP;
+ case MPTCP_SANDBOX:
+ return LANDLOCK_ACCESS_NET_BIND_MPTCP;
case NO_SANDBOX:
default:
return 0;
@@ -139,6 +150,8 @@ static __u64 sandbox_connect_access(const enum sandbox_type sandbox)
return LANDLOCK_ACCESS_NET_CONNECT_TCP;
case UDP_SANDBOX:
return LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP;
+ case MPTCP_SANDBOX:
+ return LANDLOCK_ACCESS_NET_CONNECT_MPTCP;
case NO_SANDBOX:
default:
return 0;
@@ -815,6 +828,114 @@ FIXTURE_VARIANT_ADD(protocol, udp_sandbox_with_unix_datagram) {
},
};
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv4_tcp1) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET,
+ .type = SOCK_STREAM,
+ /* IPPROTO_IP == 0 */
+ .protocol = IPPROTO_IP,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv4_tcp2) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET,
+ .type = SOCK_STREAM,
+ .protocol = IPPROTO_TCP,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv4_mptcp) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET,
+ .type = SOCK_STREAM,
+ .protocol = IPPROTO_MPTCP,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv6_tcp1) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET6,
+ .type = SOCK_STREAM,
+ /* IPPROTO_IP == 0 */
+ .protocol = IPPROTO_IP,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv6_tcp2) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET6,
+ .type = SOCK_STREAM,
+ .protocol = IPPROTO_TCP,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv6_mptcp) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET6,
+ .type = SOCK_STREAM,
+ .protocol = IPPROTO_MPTCP,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv4_udp) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET,
+ .type = SOCK_DGRAM,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_ipv6_udp) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_INET6,
+ .type = SOCK_DGRAM,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_unix_stream) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_UNIX,
+ .type = SOCK_STREAM,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(protocol, mptcp_sandbox_with_unix_datagram) {
+ /* clang-format on */
+ .sandbox = MPTCP_SANDBOX,
+ .prot = {
+ .domain = AF_UNIX,
+ .type = SOCK_DGRAM,
+ },
+};
+
static void test_bind_and_connect(struct __test_metadata *const _metadata,
const struct service_fixture *const srv,
const bool deny_bind, const bool deny_connect)
@@ -1294,14 +1415,12 @@ TEST_F(protocol, connect_unspec)
TEST_F(protocol, tcp_fastopen)
{
- const bool restricted = variant->sandbox == TCP_SANDBOX &&
- variant->prot.type == SOCK_STREAM &&
- (variant->prot.protocol == IPPROTO_TCP ||
- variant->prot.protocol == IPPROTO_IP) &&
- (variant->prot.domain == AF_INET ||
- variant->prot.domain == AF_INET6);
+ const bool stream_sandbox = variant->sandbox == TCP_SANDBOX ||
+ variant->sandbox == MPTCP_SANDBOX;
+ const bool restricted = stream_sandbox &&
+ is_restricted(&variant->prot, variant->sandbox);
const struct landlock_ruleset_attr ruleset_attr = {
- .handled_access_net = LANDLOCK_ACCESS_NET_CONNECT_TCP,
+ .handled_access_net = sandbox_connect_access(variant->sandbox),
};
int bind_fd, client_fd, status;
char buf;
@@ -1324,7 +1443,7 @@ TEST_F(protocol, tcp_fastopen)
connect_fd = socket_variant(&self->srv0);
ASSERT_LE(0, connect_fd);
- if (variant->sandbox == TCP_SANDBOX) {
+ if (stream_sandbox) {
const int ruleset_fd = landlock_create_ruleset(
&ruleset_attr, sizeof(ruleset_attr), 0);
ASSERT_LE(0, ruleset_fd);
@@ -2219,13 +2338,15 @@ FIXTURE_TEARDOWN(mini)
/* clang-format off */
-#define ACCESS_LAST LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP
+#define ACCESS_LAST LANDLOCK_ACCESS_NET_CONNECT_MPTCP
#define ACCESS_ALL ( \
LANDLOCK_ACCESS_NET_BIND_TCP | \
LANDLOCK_ACCESS_NET_CONNECT_TCP | \
LANDLOCK_ACCESS_NET_BIND_UDP | \
- LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP)
+ LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP | \
+ LANDLOCK_ACCESS_NET_BIND_MPTCP | \
+ LANDLOCK_ACCESS_NET_CONNECT_MPTCP)
/* clang-format on */
@@ -2949,6 +3070,28 @@ FIXTURE_VARIANT_ADD(audit, ipv6_udp) {
},
};
+/* clang-format off */
+FIXTURE_VARIANT_ADD(audit, ipv4_mptcp) {
+ /* clang-format on */
+ .addr = "127\\.0\\.0\\.1",
+ .prot = {
+ .domain = AF_INET,
+ .type = SOCK_STREAM,
+ .protocol = IPPROTO_MPTCP,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(audit, ipv6_mptcp) {
+ /* clang-format on */
+ .addr = "::1",
+ .prot = {
+ .domain = AF_INET6,
+ .type = SOCK_STREAM,
+ .protocol = IPPROTO_MPTCP,
+ },
+};
+
FIXTURE_SETUP(audit)
{
struct protocol_variant prot_unspec = variant->prot;
@@ -2975,17 +3118,56 @@ FIXTURE_TEARDOWN(audit)
clear_cap(_metadata, CAP_AUDIT_CONTROL);
}
+static __u64 prot_bind_access(const struct protocol_variant *const prot)
+{
+ if (prot_is_mptcp(prot))
+ return LANDLOCK_ACCESS_NET_BIND_MPTCP;
+
+ if (prot->type == SOCK_STREAM)
+ return LANDLOCK_ACCESS_NET_BIND_TCP;
+
+ return LANDLOCK_ACCESS_NET_BIND_UDP;
+}
+
+static __u64 prot_connect_access(const struct protocol_variant *const prot)
+{
+ if (prot_is_mptcp(prot))
+ return LANDLOCK_ACCESS_NET_CONNECT_MPTCP;
+
+ if (prot->type == SOCK_STREAM)
+ return LANDLOCK_ACCESS_NET_CONNECT_TCP;
+
+ return LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP;
+}
+
+static const char *prot_bind_blocker(const struct protocol_variant *const prot)
+{
+ if (prot_is_mptcp(prot))
+ return "net\\.bind_mptcp";
+
+ if (prot->type == SOCK_STREAM)
+ return "net\\.bind_tcp";
+
+ return "net\\.bind_udp";
+}
+
+static const char *
+prot_connect_blocker(const struct protocol_variant *const prot)
+{
+ if (prot_is_mptcp(prot))
+ return "net\\.connect_mptcp";
+
+ if (prot->type == SOCK_STREAM)
+ return "net\\.connect_tcp";
+
+ return "net\\.connect_send_udp";
+}
+
TEST_F(audit, bind)
{
- const char *audit_evt = (variant->prot.type == SOCK_STREAM ?
- "net\\.bind_tcp" :
- "net\\.bind_udp");
- const __u64 access_rights =
- (variant->prot.type == SOCK_STREAM ?
- LANDLOCK_ACCESS_NET_BIND_TCP |
- LANDLOCK_ACCESS_NET_CONNECT_TCP :
- LANDLOCK_ACCESS_NET_BIND_UDP |
- LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP);
+ const char *audit_evt = prot_bind_blocker(&variant->prot);
+ const __u64 access_rights = prot_bind_access(&variant->prot) |
+ prot_connect_access(&variant->prot);
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_net = access_rights,
.quiet_access_net = access_rights,
@@ -3031,15 +3213,9 @@ TEST_F(audit, bind)
TEST_F(audit, connect)
{
- const char *audit_evt = (variant->prot.type == SOCK_STREAM ?
- "net\\.connect_tcp" :
- "net\\.connect_send_udp");
- const __u64 bind_right = (variant->prot.type == SOCK_STREAM ?
- LANDLOCK_ACCESS_NET_BIND_TCP :
- LANDLOCK_ACCESS_NET_BIND_UDP);
- const __u64 conn_right = (variant->prot.type == SOCK_STREAM ?
- LANDLOCK_ACCESS_NET_CONNECT_TCP :
- LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP);
+ const char *audit_evt = prot_connect_blocker(&variant->prot);
+ const __u64 bind_right = prot_bind_access(&variant->prot);
+ const __u64 conn_right = prot_connect_access(&variant->prot);
const __u64 access_rights = bind_right | conn_right;
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_net = access_rights,
@@ -3104,15 +3280,9 @@ TEST_F(audit, connect)
/* Quieting bind access has no effect on connect. */
TEST_F(audit, connect_quiet_bind)
{
- const char *audit_evt = (variant->prot.type == SOCK_STREAM ?
- "net\\.connect_tcp" :
- "net\\.connect_send_udp");
- const int bind_right = (variant->prot.type == SOCK_STREAM ?
- LANDLOCK_ACCESS_NET_BIND_TCP :
- LANDLOCK_ACCESS_NET_BIND_UDP);
- const int conn_right = (variant->prot.type == SOCK_STREAM ?
- LANDLOCK_ACCESS_NET_CONNECT_TCP :
- LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP);
+ const char *audit_evt = prot_connect_blocker(&variant->prot);
+ const int bind_right = prot_bind_access(&variant->prot);
+ const int conn_right = prot_connect_access(&variant->prot);
const int access_rights = bind_right | conn_right;
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_net = access_rights,
@@ -3194,15 +3364,9 @@ static int matches_log_connect_bound(int audit_fd, const char *const blockers,
*/
TEST_F(audit, connect_bound)
{
- const __u64 bind_right = (variant->prot.type == SOCK_STREAM ?
- LANDLOCK_ACCESS_NET_BIND_TCP :
- LANDLOCK_ACCESS_NET_BIND_UDP);
- const __u64 conn_right = (variant->prot.type == SOCK_STREAM ?
- LANDLOCK_ACCESS_NET_CONNECT_TCP :
- LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP);
- const char *const audit_evt = (variant->prot.type == SOCK_STREAM ?
- "net\\.connect_tcp" :
- "net\\.connect_send_udp");
+ const __u64 bind_right = prot_bind_access(&variant->prot);
+ const __u64 conn_right = prot_connect_access(&variant->prot);
+ const char *const audit_evt = prot_connect_blocker(&variant->prot);
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_net = bind_right | conn_right,
};
--
2.55.0
next prev parent reply other threads:[~2026-08-30 20:17 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-30 20:16 [PATCH 0/6] landlock: Support MPTCP bind and connect restrictions Günther Noack
2026-08-30 20:16 ` [PATCH 1/6] samples/landlock: Implement best-effort fallback for network rules Günther Noack
2026-08-30 20:16 ` [PATCH 2/6] selftests/landlock: Generalize net test helpers for multiple socket types Günther Noack
2026-08-30 20:16 ` [PATCH 3/6] landlock: Add MPTCP bind and connect access rights Günther Noack
2026-08-31 4:09 ` Geliang Tang
2026-08-30 20:16 ` Günther Noack [this message]
2026-08-30 20:16 ` [PATCH 5/6] samples/landlock: Support MPTCP " Günther Noack
2026-08-30 20:16 ` [PATCH 6/6] landlock: Document " Günther Noack
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260830201650.67050-5-gnoack3000@gmail.com \
--to=gnoack3000@gmail.com \
--cc=geliang@kernel.org \
--cc=ivanov.mikhail1@huawei-partners.com \
--cc=linux-security-module@vger.kernel.org \
--cc=martineau@kernel.org \
--cc=matttbe@kernel.org \
--cc=mic@digikod.net \
--cc=mptcp@lists.linux.dev \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox