summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/landlock/net_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/landlock/net_test.c')
-rw-r--r--tools/testing/selftests/landlock/net_test.c164
1 files changed, 161 insertions, 3 deletions
diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c
index d9de0ee49ebc..4c528154ea92 100644
--- a/tools/testing/selftests/landlock/net_test.c
+++ b/tools/testing/selftests/landlock/net_test.c
@@ -20,6 +20,7 @@
#include <sys/syscall.h>
#include <sys/un.h>
+#include "audit.h"
#include "common.h"
const short sock_port_start = (1 << 10);
@@ -120,6 +121,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 +762,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 +775,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 +803,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 +814,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)
@@ -891,7 +906,19 @@ TEST_F(protocol, connect_unspec)
EXPECT_EQ(0, close(ruleset_fd));
}
- ret = connect_variant(connect_fd, &self->unspec_any0);
+ /* Try to re-disconnect with a truncated address struct. */
+ EXPECT_EQ(-EINVAL,
+ connect_variant_addrlen(
+ connect_fd, &self->unspec_any0,
+ get_addrlen(&self->unspec_any0, true) - 1));
+
+ /*
+ * Re-disconnect, with a minimal sockaddr struct (just a
+ * bare af_family=AF_UNSPEC field).
+ */
+ ret = connect_variant_addrlen(connect_fd, &self->unspec_any0,
+ get_addrlen(&self->unspec_any0,
+ true));
if (self->srv0.protocol.domain == AF_UNIX &&
self->srv0.protocol.type == SOCK_STREAM) {
EXPECT_EQ(-EINVAL, ret);
@@ -1329,7 +1356,7 @@ TEST_F(mini, network_access_rights)
&net_port, 0))
{
TH_LOG("Failed to add rule with access 0x%llx: %s",
- access, strerror(errno));
+ (unsigned long long)access, strerror(errno));
}
}
EXPECT_EQ(0, close(ruleset_fd));
@@ -1868,4 +1895,135 @@ TEST_F(port_specific, bind_connect_1023)
EXPECT_EQ(0, close(bind_fd));
}
+static int matches_log_tcp(const int audit_fd, const char *const blockers,
+ const char *const dir_addr, const char *const addr,
+ const char *const dir_port)
+{
+ static const char log_template[] = REGEX_LANDLOCK_PREFIX
+ " blockers=%s %s=%s %s=1024$";
+ /*
+ * Max strlen(blockers): 16
+ * Max strlen(dir_addr): 5
+ * Max strlen(addr): 12
+ * Max strlen(dir_port): 4
+ */
+ char log_match[sizeof(log_template) + 37];
+ int log_match_len;
+
+ log_match_len = snprintf(log_match, sizeof(log_match), log_template,
+ blockers, dir_addr, addr, dir_port);
+ if (log_match_len > sizeof(log_match))
+ return -E2BIG;
+
+ return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
+ NULL);
+}
+
+FIXTURE(audit)
+{
+ struct service_fixture srv0;
+ struct audit_filter audit_filter;
+ int audit_fd;
+};
+
+FIXTURE_VARIANT(audit)
+{
+ const char *const addr;
+ const struct protocol_variant prot;
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(audit, ipv4) {
+ /* clang-format on */
+ .addr = "127\\.0\\.0\\.1",
+ .prot = {
+ .domain = AF_INET,
+ .type = SOCK_STREAM,
+ },
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(audit, ipv6) {
+ /* clang-format on */
+ .addr = "::1",
+ .prot = {
+ .domain = AF_INET6,
+ .type = SOCK_STREAM,
+ },
+};
+
+FIXTURE_SETUP(audit)
+{
+ ASSERT_EQ(0, set_service(&self->srv0, variant->prot, 0));
+ setup_loopback(_metadata);
+
+ set_cap(_metadata, CAP_AUDIT_CONTROL);
+ self->audit_fd = audit_init_with_exe_filter(&self->audit_filter);
+ EXPECT_LE(0, self->audit_fd);
+ disable_caps(_metadata);
+};
+
+FIXTURE_TEARDOWN(audit)
+{
+ set_cap(_metadata, CAP_AUDIT_CONTROL);
+ EXPECT_EQ(0, audit_cleanup(self->audit_fd, &self->audit_filter));
+ clear_cap(_metadata, CAP_AUDIT_CONTROL);
+}
+
+TEST_F(audit, bind)
+{
+ const struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+ LANDLOCK_ACCESS_NET_CONNECT_TCP,
+ };
+ struct audit_records records;
+ int ruleset_fd, sock_fd;
+
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ EXPECT_EQ(0, close(ruleset_fd));
+
+ sock_fd = socket_variant(&self->srv0);
+ ASSERT_LE(0, sock_fd);
+ EXPECT_EQ(-EACCES, bind_variant(sock_fd, &self->srv0));
+ EXPECT_EQ(0, matches_log_tcp(self->audit_fd, "net\\.bind_tcp", "saddr",
+ variant->addr, "src"));
+
+ EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
+ EXPECT_EQ(0, records.access);
+ EXPECT_EQ(1, records.domain);
+
+ EXPECT_EQ(0, close(sock_fd));
+}
+
+TEST_F(audit, connect)
+{
+ const struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+ LANDLOCK_ACCESS_NET_CONNECT_TCP,
+ };
+ struct audit_records records;
+ int ruleset_fd, sock_fd;
+
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+ enforce_ruleset(_metadata, ruleset_fd);
+ EXPECT_EQ(0, close(ruleset_fd));
+
+ sock_fd = socket_variant(&self->srv0);
+ ASSERT_LE(0, sock_fd);
+ EXPECT_EQ(-EACCES, connect_variant(sock_fd, &self->srv0));
+ EXPECT_EQ(0, matches_log_tcp(self->audit_fd, "net\\.connect_tcp",
+ "daddr", variant->addr, "dest"));
+
+ EXPECT_EQ(0, audit_count_records(self->audit_fd, &records));
+ EXPECT_EQ(0, records.access);
+ EXPECT_EQ(1, records.domain);
+
+ EXPECT_EQ(0, close(sock_fd));
+}
+
TEST_HARNESS_MAIN