]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
landlock: Set audit_net.sk for socket access checks
authorMickaël Salaün <mic@digikod.net>
Fri, 12 Jun 2026 17:27:55 +0000 (19:27 +0200)
committerMickaël Salaün <mic@digikod.net>
Sat, 13 Jun 2026 21:14:56 +0000 (23:14 +0200)
Set audit_net.sk in current_check_access_socket() to provide the socket
object to audit_log_lsm_data().  This makes Landlock consistent with
AppArmor, which always sets .sk for socket operations, and with
SELinux's generic socket permission checks.

The socket's local and foreign address information (laddr, lport, faddr,
fport) is logged by the shared lsm_audit.c infrastructure when the
socket has bound or connected state.  Fields with zero values are
suppressed by print_ipv4_addr()/print_ipv6_addr(), so the audit output
is unchanged for the common case of bind denials on unbound sockets.
For connect denials after a prior bind, the bound local address (laddr,
lport) appears before the existing sockaddr fields (daddr, dest).

No existing fields are removed or reordered, and the new field names
(laddr, lport, faddr, fport) are standard audit fields already emitted
by other LSMs through the same lsm_audit.c code path.

Add a connect_tcp_bound audit test that binds to an allowed port and
then connects to a denied one, verifying that the denial record reports
laddr/lport from the bound socket in addition to the connect
destination.

Cc: Günther Noack <gnoack@google.com>
Cc: Tingmao Wang <m@maowtm.org>
Cc: stable@vger.kernel.org
Fixes: 9f74411a40ce ("landlock: Log TCP bind and connect denials")
Link: https://patch.msgid.link/20260612172757.1003481-1-mic@digikod.net
Signed-off-by: Mickaël Salaün <mic@digikod.net>
security/landlock/net.c
tools/testing/selftests/landlock/net_test.c

index c368649985c53c067f9148e11d5a344b9ca4d410..a38bdfcffc22a31b23b89e07f2f214b4afa3d455 100644 (file)
@@ -198,6 +198,7 @@ static int current_check_access_socket(struct socket *const sock,
                return 0;
 
        audit_net.family = address->sa_family;
+       audit_net.sk = sock->sk;
        landlock_log_denial(subject,
                            &(struct landlock_request){
                                    .type = LANDLOCK_REQUEST_NET_ACCESS,
index 4c528154ea92bbf2e9e2d39def0e39c2a13ae844..0c256e7c86752e7f6e5196a16a39a8f88ea9d52f 100644 (file)
@@ -2026,4 +2026,66 @@ TEST_F(audit, connect)
        EXPECT_EQ(0, close(sock_fd));
 }
 
+static int matches_log_tcp_bound(int audit_fd, const char *const addr,
+                                __u16 lport, __u16 dport)
+{
+       static const char log_template[] = REGEX_LANDLOCK_PREFIX
+               " blockers=net\\.connect_tcp laddr=%s lport=%u daddr=%s dest=%u$";
+       /* Slack for two addresses and two port numbers. */
+       char log_match[sizeof(log_template) + 40];
+       int log_match_len;
+
+       log_match_len = snprintf(log_match, sizeof(log_match), log_template,
+                                addr, lport, addr, dport);
+       if (log_match_len > sizeof(log_match))
+               return -E2BIG;
+
+       return audit_match_record(audit_fd, AUDIT_LANDLOCK_ACCESS, log_match,
+                                 NULL);
+}
+
+/*
+ * After a bind() to an allowed port, a denied connect must report laddr/lport
+ * from the bound socket (made available through audit_net.sk) in addition to
+ * the connect sockaddr's daddr/dest.
+ */
+TEST_F(audit, connect_tcp_bound)
+{
+       const struct landlock_ruleset_attr ruleset_attr = {
+               .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP |
+                                     LANDLOCK_ACCESS_NET_CONNECT_TCP,
+       };
+       const struct landlock_net_port_attr rule_bind = {
+               .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
+               .port = self->srv0.port,
+       };
+       struct service_fixture srv_remote;
+       struct audit_records records;
+       int ruleset_fd, sock_fd;
+
+       /* Uses a second port as the denied connect target. */
+       ASSERT_EQ(0, set_service(&srv_remote, variant->prot, 1));
+
+       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_NET_PORT,
+                                      &rule_bind, 0));
+       enforce_ruleset(_metadata, ruleset_fd);
+       EXPECT_EQ(0, close(ruleset_fd));
+
+       sock_fd = socket_variant(&self->srv0);
+       ASSERT_LE(0, sock_fd);
+       EXPECT_EQ(0, bind_variant(sock_fd, &self->srv0));
+       EXPECT_EQ(-EACCES, connect_variant(sock_fd, &srv_remote));
+       EXPECT_EQ(0, matches_log_tcp_bound(self->audit_fd, variant->addr,
+                                          self->srv0.port, srv_remote.port));
+
+       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