diff options
| author | Mickaël Salaün <mic@digikod.net> | 2026-09-18 20:50:27 +0200 |
|---|---|---|
| committer | Mickaël Salaün <mic@digikod.net> | 2026-09-20 11:08:02 +0200 |
| commit | 98b04ab00f0e738d69bd718228db55483a911b7a (patch) | |
| tree | 0391a270db0a640ab8b9e46fc5ef402b0c31c3d4 /security | |
| parent | 1a985d3890ed8caa428390a5682e957503f14060 (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.h | 32 | ||||
| -rw-r--r-- | security/landlock/net.c | 37 | ||||
| -rw-r--r-- | security/landlock/trace.c | 20 |
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: |
