Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

landlock: Log TCP bind and connect denials

Add audit support to socket_bind and socket_connect hooks.

The related blockers are:
- net.bind_tcp
- net.connect_tcp

Audit event sample:

type=LANDLOCK_DENY msg=audit(1729738800.349:44): domain=195ba459b blockers=net.connect_tcp daddr=127.0.0.1 dest=80

Cc: Günther Noack <gnoack@google.com>
Cc: Konstantin Meskhidze <konstantin.meskhidze@huawei.com>
Cc: Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com>
Link: https://lore.kernel.org/r/20250320190717.2287696-16-mic@digikod.net
Signed-off-by: Mickaël Salaün <mic@digikod.net>

+60 -4
+12
security/landlock/audit.c
··· 41 41 42 42 static_assert(ARRAY_SIZE(fs_access_strings) == LANDLOCK_NUM_ACCESS_FS); 43 43 44 + static const char *const net_access_strings[] = { 45 + [BIT_INDEX(LANDLOCK_ACCESS_NET_BIND_TCP)] = "net.bind_tcp", 46 + [BIT_INDEX(LANDLOCK_ACCESS_NET_CONNECT_TCP)] = "net.connect_tcp", 47 + }; 48 + 49 + static_assert(ARRAY_SIZE(net_access_strings) == LANDLOCK_NUM_ACCESS_NET); 50 + 44 51 static __attribute_const__ const char * 45 52 get_blocker(const enum landlock_request_type type, 46 53 const unsigned long access_bit) ··· 65 58 if (WARN_ON_ONCE(access_bit >= ARRAY_SIZE(fs_access_strings))) 66 59 return "unknown"; 67 60 return fs_access_strings[access_bit]; 61 + 62 + case LANDLOCK_REQUEST_NET_ACCESS: 63 + if (WARN_ON_ONCE(access_bit >= ARRAY_SIZE(net_access_strings))) 64 + return "unknown"; 65 + return net_access_strings[access_bit]; 68 66 } 69 67 70 68 WARN_ON_ONCE(1);
+1
security/landlock/audit.h
··· 18 18 LANDLOCK_REQUEST_PTRACE = 1, 19 19 LANDLOCK_REQUEST_FS_CHANGE_TOPOLOGY, 20 20 LANDLOCK_REQUEST_FS_ACCESS, 21 + LANDLOCK_REQUEST_NET_ACCESS, 21 22 }; 22 23 23 24 /*
+47 -4
security/landlock/net.c
··· 7 7 */ 8 8 9 9 #include <linux/in.h> 10 + #include <linux/lsm_audit.h> 10 11 #include <linux/net.h> 11 12 #include <linux/socket.h> 12 13 #include <net/ipv6.h> 13 14 15 + #include "audit.h" 14 16 #include "common.h" 15 17 #include "cred.h" 16 18 #include "limits.h" ··· 57 55 }; 58 56 const struct landlock_cred_security *const subject = 59 57 landlock_get_applicable_subject(current_cred(), masks, NULL); 58 + struct lsm_network_audit audit_net = {}; 60 59 61 60 if (!subject) 62 61 return 0; ··· 71 68 72 69 switch (address->sa_family) { 73 70 case AF_UNSPEC: 74 - case AF_INET: 71 + case AF_INET: { 72 + const struct sockaddr_in *addr4; 73 + 75 74 if (addrlen < sizeof(struct sockaddr_in)) 76 75 return -EINVAL; 77 - port = ((struct sockaddr_in *)address)->sin_port; 76 + 77 + addr4 = (struct sockaddr_in *)address; 78 + port = addr4->sin_port; 79 + 80 + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) { 81 + audit_net.dport = port; 82 + audit_net.v4info.daddr = addr4->sin_addr.s_addr; 83 + } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) { 84 + audit_net.sport = port; 85 + audit_net.v4info.saddr = addr4->sin_addr.s_addr; 86 + } else { 87 + WARN_ON_ONCE(1); 88 + } 78 89 break; 90 + } 79 91 80 92 #if IS_ENABLED(CONFIG_IPV6) 81 - case AF_INET6: 93 + case AF_INET6: { 94 + const struct sockaddr_in6 *addr6; 95 + 82 96 if (addrlen < SIN6_LEN_RFC2133) 83 97 return -EINVAL; 84 - port = ((struct sockaddr_in6 *)address)->sin6_port; 98 + 99 + addr6 = (struct sockaddr_in6 *)address; 100 + port = addr6->sin6_port; 101 + 102 + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) { 103 + audit_net.dport = port; 104 + audit_net.v6info.daddr = addr6->sin6_addr; 105 + } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) { 106 + audit_net.sport = port; 107 + audit_net.v6info.saddr = addr6->sin6_addr; 108 + } else { 109 + WARN_ON_ONCE(1); 110 + } 85 111 break; 112 + } 86 113 #endif /* IS_ENABLED(CONFIG_IPV6) */ 87 114 88 115 default: ··· 182 149 ARRAY_SIZE(layer_masks))) 183 150 return 0; 184 151 152 + audit_net.family = address->sa_family; 153 + landlock_log_denial(subject, 154 + &(struct landlock_request){ 155 + .type = LANDLOCK_REQUEST_NET_ACCESS, 156 + .audit.type = LSM_AUDIT_DATA_NET, 157 + .audit.u.net = &audit_net, 158 + .access = access_request, 159 + .layer_masks = &layer_masks, 160 + .layer_masks_size = ARRAY_SIZE(layer_masks), 161 + }); 185 162 return -EACCES; 186 163 } 187 164