diff options
-rw-r--r-- | include/uapi/linux/landlock.h | 12 | ||||
-rw-r--r-- | security/landlock/cred.h | 7 | ||||
-rw-r--r-- | security/landlock/limits.h | 2 | ||||
-rw-r--r-- | security/landlock/syscalls.c | 41 |
4 files changed, 55 insertions, 7 deletions
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index 56b0094ef792..d9d0cb827117 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -79,10 +79,22 @@ struct landlock_ruleset_attr { * 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). + * - %LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF: Do not create any log related + * to the enforced restrictions coming from future nested domains created by + * the caller or its descendants. This should only be set according to a + * runtime configuration (i.e. not hardcoded) by programs launching other + * unknown or untrusted programs that may create their own Landlock domains + * and spam logs. The main use case is for container runtimes to enable users + * to mute buggy sandboxed programs for a specific container image. Other use + * cases include sandboxer tools and init systems. Unlike + * %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF, + * %LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF does not impact the requested + * restriction (if any) but only the future nested domains. */ /* clang-format off */ #define LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF (1U << 0) #define LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON (1U << 1) +#define LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF (1U << 2) /* clang-format on */ /** diff --git a/security/landlock/cred.h b/security/landlock/cred.h index 3bf18551d7b8..c82fe63ec598 100644 --- a/security/landlock/cred.h +++ b/security/landlock/cred.h @@ -40,6 +40,13 @@ struct landlock_cred_security { * landlock_restrict_self(2)). */ u16 domain_exec; + /** + * @log_subdomains_off: Set if the domain descendants's log_status should be + * set to %LANDLOCK_LOG_DISABLED. This is not a landlock_hierarchy + * configuration because it applies to future descendant domains and it does + * not require a current domain. + */ + u8 log_subdomains_off : 1; #endif /* CONFIG_AUDIT */ } __packed; diff --git a/security/landlock/limits.h b/security/landlock/limits.h index 404e880cccf9..65b5ff051674 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -31,7 +31,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_LOG_NEW_EXEC_ON +#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF #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 75bc9fcd0a8f..54a9f29e6ebb 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -454,12 +454,16 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, * * - %LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF * - %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON + * - %LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF * * 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 * namespace or is running with no_new_privs. This avoids scenarios where * unprivileged tasks can affect the behavior of privileged children. * + * It is allowed to only pass the %LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF + * flag with a @ruleset_fd value of -1. + * * Possible returned errors are: * * - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time; @@ -479,7 +483,8 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, *ruleset __free(landlock_put_ruleset) = NULL; struct cred *new_cred; struct landlock_cred_security *new_llcred; - bool __maybe_unused log_same_exec, log_new_exec; + bool __maybe_unused log_same_exec, log_new_exec, log_subdomains, + prev_log_subdomains; if (!is_initialized()) return -EOPNOTSUPP; @@ -500,11 +505,20 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, log_same_exec = !(flags & LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF); /* Translates "on" flag to boolean. */ log_new_exec = !!(flags & LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON); + /* Translates "off" flag to boolean. */ + log_subdomains = !(flags & LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF); - /* Gets and checks the ruleset. */ - ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ); - if (IS_ERR(ruleset)) - return PTR_ERR(ruleset); + /* + * It is allowed to set LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF with + * -1 as ruleset_fd, but no other flag must be set. + */ + if (!(ruleset_fd == -1 && + flags == LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF)) { + /* Gets and checks the ruleset. */ + ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ); + if (IS_ERR(ruleset)) + return PTR_ERR(ruleset); + } /* Prepares new credentials. */ new_cred = prepare_creds(); @@ -513,6 +527,21 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, new_llcred = landlock_cred(new_cred); +#ifdef CONFIG_AUDIT + prev_log_subdomains = !new_llcred->log_subdomains_off; + new_llcred->log_subdomains_off = !prev_log_subdomains || + !log_subdomains; +#endif /* CONFIG_AUDIT */ + + /* + * The only case when a ruleset may not be set is if + * LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF is set and ruleset_fd is -1. + * We could optimize this case by not calling commit_creds() if this flag + * was already set, but it is not worth the complexity. + */ + if (!ruleset) + return commit_creds(new_cred); + /* * There is no possible race condition while copying and manipulating * the current credentials because they are dedicated per thread. @@ -526,7 +555,7 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, #ifdef CONFIG_AUDIT new_dom->hierarchy->log_same_exec = log_same_exec; new_dom->hierarchy->log_new_exec = log_new_exec; - if (!log_same_exec && !log_new_exec) + if ((!log_same_exec && !log_new_exec) || !prev_log_subdomains) new_dom->hierarchy->log_status = LANDLOCK_LOG_DISABLED; #endif /* CONFIG_AUDIT */ |