@@ -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 */
/**
@@ -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))
@@ -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;
}
@@ -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 */
};
@@ -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 */
@@ -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. */
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 <mic@digikod.net> Link: https://lore.kernel.org/r/20250131163059.1139617-19-mic@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(-)