summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorMickaël Salaün <mic@digikod.net>2026-09-18 20:50:27 +0200
committerMickaël Salaün <mic@digikod.net>2026-09-20 11:08:02 +0200
commit98b04ab00f0e738d69bd718228db55483a911b7a (patch)
tree0391a270db0a640ab8b9e46fc5ef402b0c31c3d4 /security
parent1a985d3890ed8caa428390a5682e957503f14060 (diff)
landlock: Fix network denial trace context
Network denial events report source and destination ports reconstructed from audit data. Their zero values are ambiguous, and neither identifies the complete endpoint that Landlock checked. Carry the checked sockaddr and its signed length in a private trace-only context. For an enabled event, validate the length and copy only the initialized prefix into zeroed local storage. This prevents a typed BPF program from reading uninitialized bytes while exposing the socket family, socket, address, and length. Replace the source and destination trace-record fields with one signed port derived from the checked address. A value of -1 means that no port was checked, zero is a valid port, and positive values use host endianness. Bind blockers select the bind address; connect and send blockers select the destination. Cc: Günther Noack <gnoack@google.com> Cc: Steven Rostedt <rostedt@goodmis.org> Fixes: 01ce260f5ccf ("landlock: Add landlock_deny_access_fs and landlock_deny_access_net") Link: https://patch.msgid.link/20260918185036.608651-5-mic@digikod.net Signed-off-by: Mickaël Salaün <mic@digikod.net>
Diffstat (limited to 'security')
-rw-r--r--security/landlock/log.h32
-rw-r--r--security/landlock/net.c37
-rw-r--r--security/landlock/trace.c20
3 files changed, 71 insertions, 18 deletions
diff --git a/security/landlock/log.h b/security/landlock/log.h
index 04f3e241e765..4587c2b1566d 100644
--- a/security/landlock/log.h
+++ b/security/landlock/log.h
@@ -15,6 +15,7 @@
struct landlock_cred_security;
struct landlock_hierarchy;
+struct sockaddr;
enum landlock_request_type {
LANDLOCK_REQUEST_PTRACE = 1,
@@ -30,6 +31,16 @@ struct landlock_blockers {
enum landlock_request_type type;
};
+#ifdef CONFIG_TRACEPOINTS
+
+struct landlock_net_trace {
+ const struct sockaddr *address;
+ int addrlen;
+ u16 socket_family;
+};
+
+#endif /* CONFIG_TRACEPOINTS */
+
/*
* We should be careful to only use a variable of this type for
* landlock_log_denial(). This way, the compiler can remove it entirely if
@@ -57,13 +68,20 @@ struct landlock_request {
deny_masks_t deny_masks;
optional_access_t quiet_optional_accesses;
- /*
- * Other-party domain ID for a relational (scope/ptrace) denial, or 0 if
- * that party is unsandboxed. An ID, not a pointer: the other task can
- * replace its credential and free the domain it referenced. Trace path
- * only; audit ignores it.
- */
- u64 other_domain_id;
+ union {
+ /*
+ * Other-party domain ID for a relational (scope/ptrace) denial,
+ * or 0 if that party is unsandboxed. Store an ID, not a
+ * pointer: the other task can replace its credential and free
+ * the domain it referenced. Trace-only; audit ignores it.
+ */
+ u64 other_domain_id;
+
+#ifdef CONFIG_TRACEPOINTS
+ /* Synchronous context for a network denial. */
+ const struct landlock_net_trace *trace_net;
+#endif /* CONFIG_TRACEPOINTS */
+ };
};
#ifdef CONFIG_SECURITY_LANDLOCK_LOG
diff --git a/security/landlock/net.c b/security/landlock/net.c
index 5552c60388f8..6fe0dbde3b78 100644
--- a/security/landlock/net.c
+++ b/security/landlock/net.c
@@ -93,7 +93,7 @@ static int current_check_access_socket(struct socket *const sock,
return 0;
/* Checks for minimal header length to safely read sa_family. */
- if (addrlen < offsetofend(typeof(*address), sa_family))
+ if (addrlen < (int)offsetofend(typeof(*address), sa_family))
return -EINVAL;
/*
@@ -145,6 +145,17 @@ static int current_check_access_socket(struct socket *const sock,
.audit.u.net = &audit_net,
.access = access_request,
.layer_masks = &layer_masks,
+#ifdef CONFIG_TRACEPOINTS
+ .trace_net =
+ &(struct landlock_net_trace){
+ .address =
+ address,
+ .addrlen =
+ addrlen,
+ .socket_family =
+ sock_family,
+ },
+#endif /* CONFIG_TRACEPOINTS */
});
return -EACCES;
}
@@ -276,14 +287,22 @@ static int current_check_access_socket(struct socket *const sock,
audit_net.family = address->sa_family;
audit_net.sk = sock->sk;
- 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,
- });
+ 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,
+#ifdef CONFIG_TRACEPOINTS
+ .trace_net =
+ &(struct landlock_net_trace){
+ .address = address,
+ .addrlen = addrlen,
+ .socket_family = sock_family,
+ },
+#endif /* CONFIG_TRACEPOINTS */
+ });
return -EACCES;
}
diff --git a/security/landlock/trace.c b/security/landlock/trace.c
index 58276cc32d3f..9be86638f905 100644
--- a/security/landlock/trace.c
+++ b/security/landlock/trace.c
@@ -12,6 +12,7 @@
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/lsm_audit.h>
+#include <linux/socket.h>
#include <net/sock.h>
#include "access.h"
@@ -157,16 +158,31 @@ void landlock_trace_denial(
break;
case LANDLOCK_REQUEST_NET_ACCESS:
if (trace_landlock_deny_access_net_enabled()) {
+ const struct landlock_net_trace *const trace_net =
+ request->trace_net;
const struct landlock_blockers blockers = {
.access = missing,
.type = request->type,
};
+ struct sockaddr_storage address = {};
+ if (WARN_ON_ONCE(!trace_net || !trace_net->address))
+ return;
+
+ if (WARN_ON_ONCE(
+ trace_net->addrlen <
+ (int)offsetofend(struct sockaddr,
+ sa_family) ||
+ trace_net->addrlen > (int)sizeof(address)))
+ return;
+
+ memcpy(&address, trace_net->address,
+ trace_net->addrlen);
trace_landlock_deny_access_net(
youngest_denied, same_exec, logged, &blockers,
request->audit.u.net->sk,
- ntohs(request->audit.u.net->sport),
- ntohs(request->audit.u.net->dport));
+ trace_net->socket_family, &address,
+ trace_net->addrlen);
}
break;
case LANDLOCK_REQUEST_PTRACE: