@@ -464,4 +464,93 @@ TEST_F(socket, connect_afunspec_with_restictions)
ASSERT_EQ(1, WIFEXITED(status));
ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
}
+
+TEST_F(socket, ruleset_overlap)
+{
+ int sockfd;
+ int one = 1;
+
+ struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+ LANDLOCK_ACCESS_NET_CONNECT_TCP,
+ };
+ struct landlock_net_service_attr net_service_1 = {
+ .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+
+ .port = self->port[0],
+ };
+
+ struct landlock_net_service_attr net_service_2 = {
+ .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP |
+ LANDLOCK_ACCESS_NET_CONNECT_TCP,
+
+ .port = self->port[0],
+ };
+
+ int ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ /* Allows bind operations to the port[0] socket. */
+ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+ &net_service_1, 0));
+ /* Allows connect and bind operations to the port[0] socket. */
+ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+ &net_service_2, 0));
+
+ /* Enforces the ruleset. */
+ enforce_ruleset(_metadata, ruleset_fd);
+
+ /* Creates a server socket. */
+ sockfd = create_socket_variant(variant, SOCK_STREAM);
+ ASSERT_LE(0, sockfd);
+ /* Allows to reuse of local address. */
+ ASSERT_EQ(0, setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one,
+ sizeof(one)));
+
+ /* Binds the socket to address with port[0]. */
+ ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+ /* Makes connection to socket with port[0]. */
+ ASSERT_EQ(0, connect_variant(variant, sockfd, self, 0));
+
+ /* Closes socket. */
+ ASSERT_EQ(0, close(sockfd));
+
+ /* Creates another ruleset layer. */
+ ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ /*
+ * Allows bind operations to the port[0] socket in
+ * the new ruleset layer.
+ */
+ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_SERVICE,
+ &net_service_1, 0));
+
+ /* Enforces the new ruleset. */
+ enforce_ruleset(_metadata, ruleset_fd);
+
+ /* Creates a server socket. */
+ sockfd = create_socket_variant(variant, SOCK_STREAM);
+ ASSERT_LE(0, sockfd);
+ /* Allows to reuse of local address. */
+ ASSERT_EQ(0, setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &one,
+ sizeof(one)));
+
+ /* Binds the socket to address with port[0]. */
+ ASSERT_EQ(0, bind_variant(variant, sockfd, self, 0));
+
+ /*
+ * Forbids to connect the socket to address with port[0],
+ * cause just one ruleset layer has connect() access rule.
+ */
+ ASSERT_EQ(-1, connect_variant(variant, sockfd, self, 0));
+ ASSERT_EQ(EACCES, errno);
+
+ /* Closes socket. */
+ ASSERT_EQ(0, close(sockfd));
+}
+
TEST_HARNESS_MAIN
This patch adds overlapping rules for one port. First rule adds just bind() access right for a port. The second one adds both bind() and connect() access rights for the same port. Signed-off-by: Konstantin Meskhidze <konstantin.meskhidze@huawei.com> --- Changes since v5: * Formats code with clang-format-14. Changes since v4: * Refactors code with self->port, self->addr4 variables. Changes since v3: * Adds ruleset_overlap test. --- tools/testing/selftests/landlock/net_test.c | 89 +++++++++++++++++++++ 1 file changed, 89 insertions(+) -- 2.25.1