diff options
Diffstat (limited to 'security/landlock/syscalls.c')
-rw-r--r-- | security/landlock/syscalls.c | 41 |
1 files changed, 35 insertions, 6 deletions
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 */ |