Log denied access for processes resulting from an execve(2), which is not the case by default.
The rationale is that a program should know its own behavior, but not necessarily the behavior of other programs. Signed-off-by: Mickaël Salaün <m...@digikod.net> Link: https://lore.kernel.org/r/20250131163059.1139617-19-...@digikod.net --- Changes since v4: - New patch to replace the now-removed Landlock-specific audit rule types. --- include/uapi/linux/landlock.h | 6 ++++++ security/landlock/audit.c | 3 ++- security/landlock/domain.c | 1 + security/landlock/domain.h | 8 +++++++- security/landlock/limits.h | 2 +- security/landlock/syscalls.c | 10 +++++++++- 6 files changed, 26 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index d810fd9e17c6..65a9340b9c0e 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -81,10 +81,16 @@ struct landlock_ruleset_attr { * init systems. Unlike %LANDLOCK_RESTRICT_SELF_QUIET, * %LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS does not impact the requested * restriction but only the potential descendant domains. + * - %LANDLOCK_RESTRICT_SELF_LOG_CROSS_EXEC: Explicitly ask to continue logging + * denied access requests even after an :manpage:`execve(2)` call. This flag + * should only be set if all the programs than can legitimately be executed + * will not try to request a denied access (which could spam audit logs). + * This flag is incompatible with %LANDLOCK_RESTRICT_SELF_QUIET. */ /* clang-format off */ #define LANDLOCK_RESTRICT_SELF_QUIET (1U << 0) #define LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS (1U << 1) +#define LANDLOCK_RESTRICT_SELF_LOG_CROSS_EXEC (1U << 2) /* clang-format on */ /** diff --git a/security/landlock/audit.c b/security/landlock/audit.c index beebe45a47e6..6e1de850a5b4 100644 --- a/security/landlock/audit.c +++ b/security/landlock/audit.c @@ -434,7 +434,8 @@ void landlock_log_denial(const struct landlock_cred_security *const subject, atomic64_inc(&youngest_denied->num_denials); /* Ignores denials after an execution. */ - if (!(subject->domain_exec & (1 << youngest_layer))) + if (!(subject->domain_exec & (1 << youngest_layer)) && + !youngest_denied->log_cross_exec) return; if (!unlikely(audit_context() && audit_enabled)) diff --git a/security/landlock/domain.c b/security/landlock/domain.c index eff7c774bf06..49ccb0f72e53 100644 --- a/security/landlock/domain.c +++ b/security/landlock/domain.c @@ -128,6 +128,7 @@ int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy) hierarchy->id = landlock_get_id_range(1); hierarchy->log_status = LANDLOCK_LOG_PENDING; hierarchy->quiet_subdomains = false; + hierarchy->log_cross_exec = false; atomic64_set(&hierarchy->num_denials, 0); return 0; } diff --git a/security/landlock/domain.h b/security/landlock/domain.h index 8979cf00f8be..06b213aa7579 100644 --- a/security/landlock/domain.h +++ b/security/landlock/domain.h @@ -108,7 +108,13 @@ struct landlock_hierarchy { * @quiet_subdomains: Set if the domain descendants's log_status * should be set to %LANDLOCK_LOG_DISABLED. */ - u32 quiet_subdomains : 1; + u32 quiet_subdomains : 1, + /** + * @log_cross_exec: Set if the domain is configured with + * %LANDLOCK_RESTRICT_SELF_LOG_CROSS_EXEC to log denials across + * child executions. + */ + log_cross_exec : 1; #endif /* CONFIG_AUDIT */ }; diff --git a/security/landlock/limits.h b/security/landlock/limits.h index 48aa75c98665..d9b70d9259c0 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -30,7 +30,7 @@ #define LANDLOCK_MASK_SCOPE ((LANDLOCK_LAST_SCOPE << 1) - 1) #define LANDLOCK_NUM_SCOPE __const_hweight64(LANDLOCK_MASK_SCOPE) -#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS +#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_LOG_CROSS_EXEC #define LANDLOCK_MASK_RESTRICT_SELF ((LANDLOCK_LAST_RESTRICT_SELF << 1) - 1) /* clang-format on */ diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index f44f4f884499..5709a53c4a09 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -441,6 +441,7 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, * * - %LANDLOCK_RESTRICT_SELF_QUIET * - %LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS + * - %LANDLOCK_RESTRICT_SELF_LOG_CROSS_EXEC * * This system call enables to enforce a Landlock ruleset on the current * thread. Enforcing a ruleset requires that the task has %CAP_SYS_ADMIN in its @@ -451,6 +452,8 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, * * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; * - %EINVAL: @flags contains an unknown bit. + * - %EINVAL: @flags contains %LANDLOCK_RESTRICT_SELF_QUIET and + * %LANDLOCK_RESTRICT_SELF_LOG_CROSS_EXEC, which are incompatible. * - %EBADF: @ruleset_fd is not a file descriptor for the current thread; * - %EBADFD: @ruleset_fd is not a ruleset file descriptor; * - %EPERM: @ruleset_fd has no read access to the underlying ruleset, or the @@ -467,7 +470,7 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, struct cred *new_cred; struct landlock_cred_security *new_llcred; bool is_quiet, is_quiet_subdomains, - __maybe_unused inherits_quiet_subdomains; + __maybe_unused inherits_quiet_subdomains, is_log_cross_exec; if (!is_initialized()) return -EOPNOTSUPP; @@ -487,6 +490,9 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, is_quiet = !!(flags & LANDLOCK_RESTRICT_SELF_QUIET); is_quiet_subdomains = !!(flags & LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS); + is_log_cross_exec = !!(flags & LANDLOCK_RESTRICT_SELF_LOG_CROSS_EXEC); + if (is_quiet && is_log_cross_exec) + return -EINVAL; /* Gets and checks the ruleset. */ ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ); @@ -518,6 +524,8 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, inherits_quiet_subdomains; if (is_quiet || inherits_quiet_subdomains) new_dom->hierarchy->log_status = LANDLOCK_LOG_DISABLED; + + new_dom->hierarchy->log_cross_exec = is_log_cross_exec; #endif /* CONFIG_AUDIT */ /* Replaces the old (prepared) domain. */ -- 2.48.1