summaryrefslogtreecommitdiff
path: root/security/landlock/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/landlock/net.c')
-rw-r--r--security/landlock/net.c78
1 files changed, 59 insertions, 19 deletions
diff --git a/security/landlock/net.c b/security/landlock/net.c
index 104b6c01fe50..1f3915a90a80 100644
--- a/security/landlock/net.c
+++ b/security/landlock/net.c
@@ -1,16 +1,18 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Landlock LSM - Network management and hooks
+ * Landlock - Network management and hooks
*
* Copyright © 2022-2023 Huawei Tech. Co., Ltd.
- * Copyright © 2022-2023 Microsoft Corporation
+ * Copyright © 2022-2025 Microsoft Corporation
*/
#include <linux/in.h>
+#include <linux/lsm_audit.h>
#include <linux/net.h>
#include <linux/socket.h>
#include <net/ipv6.h>
+#include "audit.h"
#include "common.h"
#include "cred.h"
#include "limits.h"
@@ -39,10 +41,6 @@ int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
return err;
}
-static const struct access_masks any_net = {
- .net = ~0,
-};
-
static int current_check_access_socket(struct socket *const sock,
struct sockaddr *const address,
const int addrlen,
@@ -54,14 +52,15 @@ static int current_check_access_socket(struct socket *const sock,
struct landlock_id id = {
.type = LANDLOCK_KEY_NET_PORT,
};
- const struct landlock_ruleset *const dom =
- landlock_get_applicable_domain(landlock_get_current_domain(),
- any_net);
+ const struct access_masks masks = {
+ .net = access_request,
+ };
+ const struct landlock_cred_security *const subject =
+ landlock_get_applicable_subject(current_cred(), masks, NULL);
+ struct lsm_network_audit audit_net = {};
- if (!dom)
+ if (!subject)
return 0;
- if (WARN_ON_ONCE(dom->num_layers < 1))
- return -EACCES;
if (!sk_is_tcp(sock->sk))
return 0;
@@ -72,18 +71,48 @@ static int current_check_access_socket(struct socket *const sock,
switch (address->sa_family) {
case AF_UNSPEC:
- case AF_INET:
+ case AF_INET: {
+ const struct sockaddr_in *addr4;
+
if (addrlen < sizeof(struct sockaddr_in))
return -EINVAL;
- port = ((struct sockaddr_in *)address)->sin_port;
+
+ addr4 = (struct sockaddr_in *)address;
+ port = addr4->sin_port;
+
+ if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
+ audit_net.dport = port;
+ audit_net.v4info.daddr = addr4->sin_addr.s_addr;
+ } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) {
+ audit_net.sport = port;
+ audit_net.v4info.saddr = addr4->sin_addr.s_addr;
+ } else {
+ WARN_ON_ONCE(1);
+ }
break;
+ }
#if IS_ENABLED(CONFIG_IPV6)
- case AF_INET6:
+ case AF_INET6: {
+ const struct sockaddr_in6 *addr6;
+
if (addrlen < SIN6_LEN_RFC2133)
return -EINVAL;
- port = ((struct sockaddr_in6 *)address)->sin6_port;
+
+ addr6 = (struct sockaddr_in6 *)address;
+ port = addr6->sin6_port;
+
+ if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
+ audit_net.dport = port;
+ audit_net.v6info.daddr = addr6->sin6_addr;
+ } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) {
+ audit_net.sport = port;
+ audit_net.v6info.saddr = addr6->sin6_addr;
+ } else {
+ WARN_ON_ONCE(1);
+ }
break;
+ }
#endif /* IS_ENABLED(CONFIG_IPV6) */
default:
@@ -145,13 +174,24 @@ static int current_check_access_socket(struct socket *const sock,
id.key.data = (__force uintptr_t)port;
BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data));
- rule = landlock_find_rule(dom, id);
- access_request = landlock_init_layer_masks(
- dom, access_request, &layer_masks, LANDLOCK_KEY_NET_PORT);
+ rule = landlock_find_rule(subject->domain, id);
+ access_request = landlock_init_layer_masks(subject->domain,
+ access_request, &layer_masks,
+ LANDLOCK_KEY_NET_PORT);
if (landlock_unmask_layers(rule, access_request, &layer_masks,
ARRAY_SIZE(layer_masks)))
return 0;
+ audit_net.family = address->sa_family;
+ landlock_log_denial(subject,
+ &(struct landlock_request){
+ .type = LANDLOCK_REQUEST_NET_ACCESS,
+ .audit.type = LSM_AUDIT_DATA_NET,
+ .audit.u.net = &audit_net,
+ .access = access_request,
+ .layer_masks = &layer_masks,
+ .layer_masks_size = ARRAY_SIZE(layer_masks),
+ });
return -EACCES;
}