diff mbox series

[RFC,v2,10/12] selftests/landlock: Add mini.socket_overflow to socket tests

Message ID 20240524093015.2402952-11-ivanov.mikhail1@huawei-partners.com
State RFC
Headers show
Series Socket type control for Landlock | expand

Commit Message

Mikhail Ivanov May 24, 2024, 9:30 a.m. UTC
* Add test validating that adding a rule for sockets that do not match
  the ranges (0 <= domain < AF_MAX), (0 <= type < SOCK_MAX)
  is prohibited. This test also checks that Landlock supports maximum
  possible domain, type values.

* Add CONFIG_MCTP to selftests config to check the socket with maximum
  family (AF_MCTP).

* Add CAP_NET_RAW capability to landlock selftests, which is required
  to create PACKET sockets (maximum type value).

Signed-off-by: Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com>
---
 tools/testing/selftests/landlock/common.h     |  1 +
 tools/testing/selftests/landlock/config       |  1 +
 .../testing/selftests/landlock/socket_test.c  | 93 +++++++++++++++++++
 3 files changed, 95 insertions(+)
diff mbox series

Patch

diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h
index 7e2b431b9f90..28df49fa22d5 100644
--- a/tools/testing/selftests/landlock/common.h
+++ b/tools/testing/selftests/landlock/common.h
@@ -66,6 +66,7 @@  static void _init_caps(struct __test_metadata *const _metadata, bool drop_all)
 		CAP_NET_BIND_SERVICE,
 		CAP_SYS_ADMIN,
 		CAP_SYS_CHROOT,
+		CAP_NET_RAW,
 		/* clang-format on */
 	};
 	const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED;
diff --git a/tools/testing/selftests/landlock/config b/tools/testing/selftests/landlock/config
index 0086efaa7b68..2820c481aefe 100644
--- a/tools/testing/selftests/landlock/config
+++ b/tools/testing/selftests/landlock/config
@@ -12,3 +12,4 @@  CONFIG_SHMEM=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_XATTR=y
+CONFIG_MCTP=y
\ No newline at end of file
diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c
index c81f02ffef6c..80c904380075 100644
--- a/tools/testing/selftests/landlock/socket_test.c
+++ b/tools/testing/selftests/landlock/socket_test.c
@@ -9,6 +9,7 @@ 
 #define _GNU_SOURCE
 
 #include <errno.h>
+#include <linux/net.h>
 #include <linux/landlock.h>
 #include <sched.h>
 #include <string.h>
@@ -439,4 +440,96 @@  TEST_F(mini, ruleset_with_unknown_access)
 	}
 }
 
+TEST_F(mini, socket_overflow)
+{
+	const struct landlock_ruleset_attr ruleset_attr = {
+		.handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE,
+	};
+	/*
+	 * Assuming that AF_MCTP == AF_MAX - 1 uses MCTP as protocol
+	 * with maximum family value. Appropriate сheck for this is given below.
+	 */
+	const struct landlock_socket_attr create_socket_max_family = {
+		.allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE,
+		.family = AF_MCTP,
+		.type = SOCK_DGRAM,
+	};
+	/*
+	 * Assuming that SOCK_PACKET == SOCK_MAX - 1 uses PACKET socket as
+	 * socket with maximum type value. Since SOCK_MAX cannot be accessed
+	 * from selftests, this assumption is not verified.
+	 */
+	const struct landlock_socket_attr create_socket_max_type = {
+		.allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE,
+		.family = AF_PACKET,
+		.type = SOCK_PACKET,
+	};
+	struct landlock_socket_attr create_socket_overflow = {
+		.allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE,
+	};
+	const struct protocol_variant protocol_max_family = {
+		.family = create_socket_max_family.family,
+		.type = create_socket_max_family.type,
+	};
+	const struct protocol_variant protocol_max_type = {
+		.family = create_socket_max_type.family,
+		.type = create_socket_max_type.type,
+	};
+	const struct protocol_variant ipv4_tcp = {
+		.family = AF_INET,
+		.type = SOCK_STREAM,
+	};
+	struct service_fixture srv_max_allowed_family, srv_max_allowed_type,
+		srv_denied;
+	int ruleset_fd;
+
+	/* Checks protocol_max_family correctness. */
+	ASSERT_EQ(AF_MCTP + 1, AF_MAX);
+
+	srv_max_allowed_family.protocol = protocol_max_family;
+	srv_max_allowed_type.protocol = protocol_max_type;
+	srv_denied.protocol = ipv4_tcp;
+
+	ruleset_fd =
+		landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+	ASSERT_LE(0, ruleset_fd);
+
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET,
+				       &create_socket_max_family, 0));
+	ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET,
+				       &create_socket_max_type, 0));
+
+	/* Checks the overflow variants for family, type values. */
+#define CHECK_RULE_OVERFLOW(family_val, type_val)                             \
+	do {                                                                  \
+		create_socket_overflow.family = family_val;                   \
+		create_socket_overflow.type = type_val;                       \
+		EXPECT_EQ(-1,                                                 \
+			  landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, \
+					    &create_socket_overflow, 0));     \
+		EXPECT_EQ(EINVAL, errno);                                     \
+	} while (0)
+
+	CHECK_RULE_OVERFLOW(AF_MAX, SOCK_STREAM);
+	CHECK_RULE_OVERFLOW(AF_INET, (SOCK_PACKET + 1));
+	CHECK_RULE_OVERFLOW(AF_MAX, (SOCK_PACKET + 1));
+	CHECK_RULE_OVERFLOW(-1, SOCK_STREAM);
+	CHECK_RULE_OVERFLOW(AF_INET, -1);
+	CHECK_RULE_OVERFLOW(-1, -1);
+	CHECK_RULE_OVERFLOW(INT16_MAX + 1, INT16_MAX + 1);
+
+#undef CHECK_RULE_OVERFLOW
+
+	enforce_ruleset(_metadata, ruleset_fd);
+
+	EXPECT_EQ(0, test_socket(&srv_max_allowed_family));
+
+	/* PACKET sockets can be used only with CAP_NET_RAW. */
+	set_cap(_metadata, CAP_NET_RAW);
+	EXPECT_EQ(0, test_socket(&srv_max_allowed_type));
+	clear_cap(_metadata, CAP_NET_RAW);
+
+	EXPECT_EQ(EACCES, test_socket(&srv_denied));
+}
+
 TEST_HARNESS_MAIN