diff options
author | Mickaël Salaün <mic@digikod.net> | 2025-03-20 20:07:05 +0100 |
---|---|---|
committer | Mickaël Salaün <mic@digikod.net> | 2025-03-26 13:59:42 +0100 |
commit | 1176a15b5ec02925ea89bae05b5c860ddcce1e2e (patch) | |
tree | 5e291e10e1008628322c561a17f45feb5bf22a73 /security/landlock/task.c | |
parent | 9f74411a40cecc6faca2a3e3bbb7c1834276d4a2 (diff) |
landlock: Log scoped denials
Add audit support for unix_stream_connect, unix_may_send, task_kill, and
file_send_sigiotask hooks.
The related blockers are:
- scope.abstract_unix_socket
- scope.signal
Audit event sample for abstract unix socket:
type=LANDLOCK_DENY msg=audit(1729738800.268:30): domain=195ba459b blockers=scope.abstract_unix_socket path=00666F6F
Audit event sample for signal:
type=LANDLOCK_DENY msg=audit(1729738800.291:31): domain=195ba459b blockers=scope.signal opid=1 ocomm="systemd"
Refactor and simplify error handling in LSM hooks.
Extend struct landlock_file_security with fown_layer and use it to log
the blocking domain. The struct aligned size is still 16 bytes.
Cc: Günther Noack <gnoack@google.com>
Cc: Tahera Fahimi <fahimitahera@gmail.com>
Link: https://lore.kernel.org/r/20250320190717.2287696-17-mic@digikod.net
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Diffstat (limited to 'security/landlock/task.c')
-rw-r--r-- | security/landlock/task.c | 81 |
1 files changed, 65 insertions, 16 deletions
diff --git a/security/landlock/task.c b/security/landlock/task.c index 30ac4340c62e..2385017418ca 100644 --- a/security/landlock/task.c +++ b/security/landlock/task.c @@ -266,26 +266,41 @@ static int hook_unix_stream_connect(struct sock *const sock, struct sock *const other, struct sock *const newsk) { + size_t handle_layer; const struct landlock_cred_security *const subject = landlock_get_applicable_subject(current_cred(), unix_scope, - NULL); + &handle_layer); /* Quick return for non-landlocked tasks. */ if (!subject) return 0; - if (is_abstract_socket(other) && sock_is_scoped(other, subject->domain)) - return -EPERM; + if (!is_abstract_socket(other)) + return 0; + + if (!sock_is_scoped(other, subject->domain)) + return 0; - return 0; + landlock_log_denial(subject, &(struct landlock_request) { + .type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET, + .audit = { + .type = LSM_AUDIT_DATA_NET, + .u.net = &(struct lsm_network_audit) { + .sk = other, + }, + }, + .layer_plus_one = handle_layer + 1, + }); + return -EPERM; } static int hook_unix_may_send(struct socket *const sock, struct socket *const other) { + size_t handle_layer; const struct landlock_cred_security *const subject = landlock_get_applicable_subject(current_cred(), unix_scope, - NULL); + &handle_layer); if (!subject) return 0; @@ -297,11 +312,23 @@ static int hook_unix_may_send(struct socket *const sock, if (unix_peer(sock->sk) == other->sk) return 0; - if (is_abstract_socket(other->sk) && - sock_is_scoped(other->sk, subject->domain)) - return -EPERM; + if (!is_abstract_socket(other->sk)) + return 0; + + if (!sock_is_scoped(other->sk, subject->domain)) + return 0; - return 0; + landlock_log_denial(subject, &(struct landlock_request) { + .type = LANDLOCK_REQUEST_SCOPE_ABSTRACT_UNIX_SOCKET, + .audit = { + .type = LSM_AUDIT_DATA_NET, + .u.net = &(struct lsm_network_audit) { + .sk = other->sk, + }, + }, + .layer_plus_one = handle_layer + 1, + }); + return -EPERM; } static const struct access_masks signal_scope = { @@ -313,6 +340,7 @@ static int hook_task_kill(struct task_struct *const p, const struct cred *cred) { bool is_scoped; + size_t handle_layer; const struct landlock_cred_security *subject; if (!cred) { @@ -331,7 +359,8 @@ static int hook_task_kill(struct task_struct *const p, cred = current_cred(); } - subject = landlock_get_applicable_subject(cred, signal_scope, NULL); + subject = landlock_get_applicable_subject(cred, signal_scope, + &handle_layer); /* Quick return for non-landlocked tasks. */ if (!subject) @@ -343,10 +372,19 @@ static int hook_task_kill(struct task_struct *const p, landlock_get_task_domain(p), signal_scope.scope); } - if (is_scoped) - return -EPERM; - return 0; + if (!is_scoped) + return 0; + + landlock_log_denial(subject, &(struct landlock_request) { + .type = LANDLOCK_REQUEST_SCOPE_SIGNAL, + .audit = { + .type = LSM_AUDIT_DATA_TASK, + .u.tsk = p, + }, + .layer_plus_one = handle_layer + 1, + }); + return -EPERM; } static int hook_file_send_sigiotask(struct task_struct *tsk, @@ -375,10 +413,21 @@ static int hook_file_send_sigiotask(struct task_struct *tsk, landlock_get_task_domain(tsk), signal_scope.scope); } - if (is_scoped) - return -EPERM; - return 0; + if (!is_scoped) + return 0; + + landlock_log_denial(subject, &(struct landlock_request) { + .type = LANDLOCK_REQUEST_SCOPE_SIGNAL, + .audit = { + .type = LSM_AUDIT_DATA_TASK, + .u.tsk = tsk, + }, +#ifdef CONFIG_AUDIT + .layer_plus_one = landlock_file(fown->file)->fown_layer + 1, +#endif /* CONFIG_AUDIT */ + }); + return -EPERM; } static struct security_hook_list landlock_hooks[] __ro_after_init = { |