[PATCH v5 17/24] landlock: Add LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS

Mickaël Salaün
2025-01-31T16:31:55Z

Add LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS for the case of sandboxer
tools, init systems, or runtime containers launching programs sandboxing
themselves in an inconsistent way. Setting this flag should only
depends on runtime configuration (i.e. not hardcoded).

We don't create a new ruleset's option because this should not be part
of the security policy: only the task that enforces the policy (not the
one that create it) knows if itself or its children may request denied
actions.

Cc: Günther Noack <gnoack@google.com>
Cc: Paul Moore <paul@paul-moore.com>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Link: https://lore.kernel.org/r/20250131163059.1139617-18-mic@digikod.net
---

Using "mute" instead of "quiet" might be more appropriate.

Changes since v4:
- New patch.
---
include/uapi/linux/landlock.h | 11 +++++++++++
security/landlock/domain.c | 1 +
security/landlock/domain.h | 5 +++++
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 14 +++++++++++---
5 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index b7f78abd6ddd..d810fd9e17c6 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -71,9 +71,20 @@ struct landlock_ruleset_attr {
* service manager). Because programs sandboxing themselves should fix any
* denied access, they should not set this flag to be aware of potential
* issues reported by system's logs (i.e. audit).
+ * - %LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS: Do not create any log related
+ * to the enforced restrictions coming from descendant domains. 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_QUIET,
+ * %LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS does not impact the requested
+ * restriction but only the potential descendant domains.
*/
/* clang-format off */
#define LANDLOCK_RESTRICT_SELF_QUIET (1U << 0)
+#define LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS (1U << 1)
/* clang-format on */

/**
diff --git a/security/landlock/domain.c b/security/landlock/domain.c
index 6704e9283206..eff7c774bf06 100644
--- a/security/landlock/domain.c
+++ b/security/landlock/domain.c
@@ -127,6 +127,7 @@ int landlock_init_hierarchy_log(struct landlock_hierarchy *const hierarchy)
hierarchy->details = details;
hierarchy->id = landlock_get_id_range(1);
hierarchy->log_status = LANDLOCK_LOG_PENDING;
+ hierarchy->quiet_subdomains = false;
atomic64_set(&hierarchy->num_denials, 0);
return 0;
}
diff --git a/security/landlock/domain.h b/security/landlock/domain.h
index 25be0a18da1f..8979cf00f8be 100644
--- a/security/landlock/domain.h
+++ b/security/landlock/domain.h
@@ -104,6 +104,11 @@ struct landlock_hierarchy {
* @details: Information about the related domain.
*/
const struct landlock_details *details;
+ /**
+ * @quiet_subdomains: Set if the domain descendants's log_status
+ * should be set to %LANDLOCK_LOG_DISABLED.
+ */
+ u32 quiet_subdomains : 1;
#endif /* CONFIG_AUDIT */
};

diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 2a5e9f3ee750..48aa75c98665 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
+#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS
#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 5c6abcd6d604..f44f4f884499 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -440,6 +440,7 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
* @flags: Supported values:
*
* - %LANDLOCK_RESTRICT_SELF_QUIET
+ * - %LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS
*
* 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
@@ -465,7 +466,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 is_quiet;
+ bool is_quiet, is_quiet_subdomains,
+ __maybe_unused inherits_quiet_subdomains;

if (!is_initialized())
return -EOPNOTSUPP;
@@ -483,6 +485,8 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
return -EINVAL;

is_quiet = !!(flags & LANDLOCK_RESTRICT_SELF_QUIET);
+ is_quiet_subdomains =
+ !!(flags & LANDLOCK_RESTRICT_SELF_QUIET_SUBDOMAINS);

/* Gets and checks the ruleset. */
ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ);
@@ -506,11 +510,15 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
return PTR_ERR(new_dom);
}

- if (is_quiet) {
#ifdef CONFIG_AUDIT
+ inherits_quiet_subdomains =
+ new_llcred->domain &&
+ new_llcred->domain->hierarchy->quiet_subdomains;
+ new_dom->hierarchy->quiet_subdomains = is_quiet_subdomains ||
+ inherits_quiet_subdomains;
+ if (is_quiet || inherits_quiet_subdomains)
new_dom->hierarchy->log_status = LANDLOCK_LOG_DISABLED;
#endif /* CONFIG_AUDIT */
- }

/* Replaces the old (prepared) domain. */
landlock_put_ruleset(new_llcred->domain);
--
2.48.1