[PATCH v6 2/6] landlock: Implement LANDLOCK_ADD_RULE_NO_INHERIT userspace api
Justin Suess
utilityemal77 at gmail.com
Sun Dec 21 19:42:57 UTC 2025
Implements the syscall side flag handling and kernel api headers for the
LANDLOCK_ADD_RULE_NO_INHERIT flag.
Signed-off-by: Justin Suess <utilityemal77 at gmail.com>
---
Notes:
v5..v6 changes:
* None
v4..v5 changes:
* Moved syscall handling to this patch and moved out flag definition
to allow independent build.
v3..v4 changes:
* Changed documentation to reflect protections now apply to VFS root
instead of the mountpoint.
v2..v3 changes:
* Extended documentation for flag inheritance suppression on
LANDLOCK_ADD_RULE_NO_INHERIT.
* Extended the flag validation rules in the syscall.
* Added mention of no inherit in empty rules in add_rule_path_beneath
as per Tingmao Wang's suggestion.
* Added check for useless no-inherit flag in networking rules.
security/landlock/ruleset.c | 19 ++++++++++++++++++-
security/landlock/syscalls.c | 16 ++++++++++++----
2 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index a58af26db201..adc965de8e4e 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -254,8 +254,13 @@ static int insert_rule(struct landlock_ruleset *const ruleset,
return -EINVAL;
if (WARN_ON_ONCE(this->layers[0].level != 0))
return -EINVAL;
+ /* Merge the flags into the rules */
this->layers[0].access |= (*layers)[0].access;
this->layers[0].flags.quiet |= (*layers)[0].flags.quiet;
+ this->layers[0].flags.no_inherit |=
+ (*layers)[0].flags.no_inherit;
+ this->layers[0].flags.has_no_inherit_descendant |=
+ (*layers)[0].flags.has_no_inherit_descendant;
return 0;
}
@@ -314,7 +319,10 @@ int landlock_insert_rule(struct landlock_ruleset *const ruleset,
.level = 0,
.flags = {
.quiet = !!(flags & LANDLOCK_ADD_RULE_QUIET),
- },
+ .no_inherit = !!(flags & LANDLOCK_ADD_RULE_NO_INHERIT),
+ .has_no_inherit_descendant =
+ !!(flags & LANDLOCK_ADD_RULE_NO_INHERIT),
+ }
} };
build_check_layer();
@@ -661,9 +669,18 @@ bool landlock_unmask_layers(const struct landlock_rule *const rule,
unsigned long access_bit;
bool is_empty;
+ /* Skip layers that already have no inherit flags. */
+ if (rule_flags &&
+ (rule_flags->no_inherit_masks & layer_bit))
+ continue;
+
/* Collect rule flags for each layer. */
if (rule_flags && layer->flags.quiet)
rule_flags->quiet_masks |= layer_bit;
+ if (rule_flags && layer->flags.no_inherit)
+ rule_flags->no_inherit_masks |= layer_bit;
+ if (rule_flags && layer->flags.has_no_inherit_descendant)
+ rule_flags->no_inherit_desc_masks |= layer_bit;
/*
* Records in @layer_masks which layer grants access to each requested
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 5cf1183bb596..cffe7d944ae5 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -352,7 +352,7 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
/*
* Informs about useless rule: empty allowed_access (i.e. deny rules)
* are ignored in path walks. However, the rule is not useless if it
- * is there to hold a quiet flag
+ * is there to hold a quiet or no inherit flag.
*/
if (!flags && !path_beneath_attr.allowed_access)
return -ENOMSG;
@@ -407,6 +407,10 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
if (flags & LANDLOCK_ADD_RULE_QUIET && !ruleset->quiet_masks.net)
return -EINVAL;
+ /* No inherit is always useless for this scope */
+ if (flags & LANDLOCK_ADD_RULE_NO_INHERIT)
+ return -EINVAL;
+
/* Denies inserting a rule with port greater than 65535. */
if (net_port_attr.port > U16_MAX)
return -EINVAL;
@@ -424,7 +428,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
* @rule_type: Identify the structure type pointed to by @rule_attr:
* %LANDLOCK_RULE_PATH_BENEATH or %LANDLOCK_RULE_NET_PORT.
* @rule_attr: Pointer to a rule (matching the @rule_type).
- * @flags: Must be 0 or %LANDLOCK_ADD_RULE_QUIET.
+ * @flags: Must be 0 or %LANDLOCK_ADD_RULE_QUIET and/or %LANDLOCK_ADD_RULE_NO_INHERIT.
*
* This system call enables to define a new rule and add it to an existing
* ruleset.
@@ -462,8 +466,12 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
if (!is_initialized())
return -EOPNOTSUPP;
-
- if (flags && flags != LANDLOCK_ADD_RULE_QUIET)
+ /* Checks flag existence */
+ if (flags & ~(LANDLOCK_ADD_RULE_QUIET | LANDLOCK_ADD_RULE_NO_INHERIT))
+ return -EINVAL;
+ /* No inherit may only apply on path_beneath rules. */
+ if ((flags & LANDLOCK_ADD_RULE_NO_INHERIT) &&
+ rule_type != LANDLOCK_RULE_PATH_BENEATH)
return -EINVAL;
/* Gets and checks the ruleset. */
--
2.51.0
More information about the Linux-security-module-archive
mailing list