From: "Mickaël Salaün" <mic@digikod.net>
To: "Christian Brauner" <brauner@kernel.org>,
"Günther Noack" <gnoack@google.com>,
"Steven Rostedt" <rostedt@goodmis.org>
Cc: "Mickaël Salaün" <mic@digikod.net>,
"Jann Horn" <jannh@google.com>, "Jeff Xu" <jeffxu@google.com>,
"Justin Suess" <utilityemal77@gmail.com>,
"Kees Cook" <kees@kernel.org>,
"Masami Hiramatsu" <mhiramat@kernel.org>,
"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
"Matthieu Buffet" <matthieu@buffet.re>,
"Mikhail Ivanov" <ivanov.mikhail1@huawei-partners.com>,
"Tingmao Wang" <m@maowtm.org>,
kernel-team@cloudflare.com, linux-fsdevel@vger.kernel.org,
linux-security-module@vger.kernel.org,
linux-trace-kernel@vger.kernel.org
Subject: [PATCH v2 03/17] landlock: Split struct landlock_domain from struct landlock_ruleset
Date: Mon, 6 Apr 2026 16:37:01 +0200 [thread overview]
Message-ID: <20260406143717.1815792-4-mic@digikod.net> (raw)
In-Reply-To: <20260406143717.1815792-1-mic@digikod.net>
Switch all domain users to the new struct landlock_domain type
introduced by a previous commit. This eliminates the conflation between
mutable rulesets and immutable domains.
Change the credential domain field to struct landlock_domain *, and
update all consumer functions. Move the merge and inherit chain from
ruleset.c to domain.c; landlock_merge_ruleset() now returns struct
landlock_domain * and uses create_domain(). Lock assertions on the
destination are removed because domains have no lock.
Rename the per-layer FAM from access_masks to layers, and the single
ruleset field from access_masks to layer, to prepare for future
per-layer extensions beyond handled-access bitfields.
Clean up struct landlock_ruleset by removing domain-only fields
(hierarchy, work_free, num_layers) and replacing the layers[] FAM with a
single struct access_masks layer field.
Break the circular include between audit.h and cred.h by replacing the
cred.h include in audit.h with forward declarations.
Cc: Günther Noack <gnoack@google.com>
Cc: Tingmao Wang <m@maowtm.org>
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---
Changes since v1:
- New patch.
---
security/landlock/access.h | 4 +-
security/landlock/audit.c | 12 +-
security/landlock/audit.h | 4 +-
security/landlock/cred.c | 6 +-
security/landlock/cred.h | 21 ++-
security/landlock/domain.c | 252 ++++++++++++++++++++++++++-
security/landlock/domain.h | 43 ++++-
security/landlock/fs.c | 28 ++-
security/landlock/net.c | 3 +-
security/landlock/ruleset.c | 329 ++++-------------------------------
security/landlock/ruleset.h | 129 ++------------
security/landlock/syscalls.c | 10 +-
security/landlock/task.c | 20 +--
13 files changed, 386 insertions(+), 475 deletions(-)
diff --git a/security/landlock/access.h b/security/landlock/access.h
index c19d5bc13944..76ab447dfcf7 100644
--- a/security/landlock/access.h
+++ b/security/landlock/access.h
@@ -19,8 +19,8 @@
/*
* All access rights that are denied by default whether they are handled or not
- * by a ruleset/layer. This must be ORed with all ruleset->access_masks[]
- * entries when we need to get the absolute handled access masks, see
+ * by a ruleset/layer. This must be ORed with all domain->layers[] entries when
+ * we need to get the absolute handled access masks, see
* landlock_upgrade_handled_access_masks().
*/
/* clang-format off */
diff --git a/security/landlock/audit.c b/security/landlock/audit.c
index 8d0edf94037d..75438b3cc887 100644
--- a/security/landlock/audit.c
+++ b/security/landlock/audit.c
@@ -135,7 +135,7 @@ static void log_domain(struct landlock_hierarchy *const hierarchy)
}
static struct landlock_hierarchy *
-get_hierarchy(const struct landlock_ruleset *const domain, const size_t layer)
+get_hierarchy(const struct landlock_domain *const domain, const size_t layer)
{
struct landlock_hierarchy *hierarchy = domain->hierarchy;
ssize_t i;
@@ -168,7 +168,7 @@ static void test_get_hierarchy(struct kunit *const test)
.parent = &dom1_hierarchy,
.id = 30,
};
- struct landlock_ruleset dom2 = {
+ struct landlock_domain dom2 = {
.hierarchy = &dom2_hierarchy,
.num_layers = 3,
};
@@ -182,7 +182,7 @@ static void test_get_hierarchy(struct kunit *const test)
#endif /* CONFIG_SECURITY_LANDLOCK_KUNIT_TEST */
/* Get the youngest layer that denied the access_request. */
-static size_t get_denied_layer(const struct landlock_ruleset *const domain,
+static size_t get_denied_layer(const struct landlock_domain *const domain,
access_mask_t *const access_request,
const struct layer_access_masks *masks)
{
@@ -202,7 +202,7 @@ static size_t get_denied_layer(const struct landlock_ruleset *const domain,
static void test_get_denied_layer(struct kunit *const test)
{
- const struct landlock_ruleset dom = {
+ const struct landlock_domain dom = {
.num_layers = 5,
};
const struct layer_access_masks masks = {
@@ -440,8 +440,8 @@ void landlock_log_denial(const struct landlock_cred_security *const subject,
* Only domains which previously appeared in the audit logs are logged again.
* This is useful to know when a domain will never show again in the audit log.
*
- * Called in a work queue scheduled by landlock_put_ruleset_deferred() called
- * by hook_cred_free().
+ * Called in a work queue scheduled by landlock_put_domain_deferred() called by
+ * hook_cred_free().
*/
void landlock_log_drop_domain(const struct landlock_hierarchy *const hierarchy)
{
diff --git a/security/landlock/audit.h b/security/landlock/audit.h
index 56778331b58c..50452a791656 100644
--- a/security/landlock/audit.h
+++ b/security/landlock/audit.h
@@ -12,7 +12,9 @@
#include <linux/lsm_audit.h>
#include "access.h"
-#include "cred.h"
+
+struct landlock_cred_security;
+struct landlock_hierarchy;
enum landlock_request_type {
LANDLOCK_REQUEST_PTRACE = 1,
diff --git a/security/landlock/cred.c b/security/landlock/cred.c
index cc419de75cd6..58b544993db4 100644
--- a/security/landlock/cred.c
+++ b/security/landlock/cred.c
@@ -22,7 +22,7 @@ static void hook_cred_transfer(struct cred *const new,
const struct landlock_cred_security *const old_llcred =
landlock_cred(old);
- landlock_get_ruleset(old_llcred->domain);
+ landlock_get_domain(old_llcred->domain);
*landlock_cred(new) = *old_llcred;
}
@@ -35,10 +35,10 @@ static int hook_cred_prepare(struct cred *const new,
static void hook_cred_free(struct cred *const cred)
{
- struct landlock_ruleset *const dom = landlock_cred(cred)->domain;
+ struct landlock_domain *const dom = landlock_cred(cred)->domain;
if (dom)
- landlock_put_ruleset_deferred(dom);
+ landlock_put_domain_deferred(dom);
}
#ifdef CONFIG_AUDIT
diff --git a/security/landlock/cred.h b/security/landlock/cred.h
index f287c56b5fd4..c42b0d3ecec8 100644
--- a/security/landlock/cred.h
+++ b/security/landlock/cred.h
@@ -16,6 +16,7 @@
#include <linux/rcupdate.h>
#include "access.h"
+#include "domain.h"
#include "limits.h"
#include "ruleset.h"
#include "setup.h"
@@ -31,9 +32,9 @@
*/
struct landlock_cred_security {
/**
- * @domain: Immutable ruleset enforced on a task.
+ * @domain: Immutable domain enforced on a task.
*/
- struct landlock_ruleset *domain;
+ struct landlock_domain *domain;
#ifdef CONFIG_AUDIT
/**
@@ -70,22 +71,20 @@ landlock_cred(const struct cred *cred)
static inline void landlock_cred_copy(struct landlock_cred_security *dst,
const struct landlock_cred_security *src)
{
- landlock_put_ruleset(dst->domain);
+ landlock_put_domain(dst->domain);
*dst = *src;
- landlock_get_ruleset(src->domain);
+ landlock_get_domain(src->domain);
}
-static inline struct landlock_ruleset *landlock_get_current_domain(void)
+static inline struct landlock_domain *landlock_get_current_domain(void)
{
return landlock_cred(current_cred())->domain;
}
-/*
- * The call needs to come from an RCU read-side critical section.
- */
-static inline const struct landlock_ruleset *
+/* The call needs to come from an RCU read-side critical section. */
+static inline const struct landlock_domain *
landlock_get_task_domain(const struct task_struct *const task)
{
return landlock_cred(__task_cred(task))->domain;
@@ -126,7 +125,7 @@ landlock_get_applicable_subject(const struct cred *const cred,
const union access_masks_all masks_all = {
.masks = masks,
};
- const struct landlock_ruleset *domain;
+ const struct landlock_domain *domain;
ssize_t layer_level;
if (!cred)
@@ -139,7 +138,7 @@ landlock_get_applicable_subject(const struct cred *const cred,
for (layer_level = domain->num_layers - 1; layer_level >= 0;
layer_level--) {
union access_masks_all layer = {
- .masks = domain->access_masks[layer_level],
+ .masks = domain->layers[layer_level],
};
if (layer.all & masks_all.all) {
diff --git a/security/landlock/domain.c b/security/landlock/domain.c
index cb79edf5df02..317fd94d3ccd 100644
--- a/security/landlock/domain.c
+++ b/security/landlock/domain.c
@@ -36,6 +36,36 @@
#include "object.h"
#include "ruleset.h"
+static void build_check_domain(void)
+{
+ const struct landlock_domain domain = {
+ .num_layers = ~0,
+ };
+
+ BUILD_BUG_ON(domain.num_layers < LANDLOCK_MAX_NUM_LAYERS);
+}
+
+static struct landlock_domain *create_domain(const u32 num_layers)
+{
+ struct landlock_domain *new_domain;
+
+ build_check_domain();
+ new_domain = kzalloc_flex(*new_domain, layers, num_layers,
+ GFP_KERNEL_ACCOUNT);
+ if (!new_domain)
+ return ERR_PTR(-ENOMEM);
+
+ refcount_set(&new_domain->usage, 1);
+ new_domain->rules.root_inode = RB_ROOT;
+
+#if IS_ENABLED(CONFIG_INET)
+ new_domain->rules.root_net_port = RB_ROOT;
+#endif /* IS_ENABLED(CONFIG_INET) */
+
+ new_domain->num_layers = num_layers;
+ return new_domain;
+}
+
static void free_domain(struct landlock_domain *const domain)
{
might_sleep();
@@ -67,15 +97,15 @@ void landlock_put_domain_deferred(struct landlock_domain *const domain)
}
}
-/* The returned access has the same lifetime as @ruleset. */
+/* The returned access has the same lifetime as @domain. */
const struct landlock_rule *
-landlock_find_rule(const struct landlock_ruleset *const ruleset,
+landlock_find_rule(const struct landlock_domain *const domain,
const struct landlock_id id)
{
const struct rb_root *root;
const struct rb_node *node;
- root = landlock_get_rule_root((struct landlock_rules *)&ruleset->rules,
+ root = landlock_get_rule_root((struct landlock_rules *)&domain->rules,
id.type);
if (IS_ERR(root))
return NULL;
@@ -151,7 +181,7 @@ bool landlock_unmask_layers(const struct landlock_rule *const rule,
}
typedef access_mask_t
-get_access_mask_t(const struct landlock_ruleset *const ruleset,
+get_access_mask_t(const struct landlock_domain *const domain,
const u16 layer_level);
/**
@@ -169,7 +199,7 @@ get_access_mask_t(const struct landlock_ruleset *const ruleset,
* any of the active layers in @domain.
*/
access_mask_t
-landlock_init_layer_masks(const struct landlock_ruleset *const domain,
+landlock_init_layer_masks(const struct landlock_domain *const domain,
const access_mask_t access_request,
struct layer_access_masks *const masks,
const enum landlock_key_type key_type)
@@ -209,6 +239,218 @@ landlock_init_layer_masks(const struct landlock_ruleset *const domain,
return handled_accesses;
}
+static int merge_tree(struct landlock_domain *const dst,
+ struct landlock_ruleset *const src,
+ const enum landlock_key_type key_type)
+{
+ struct landlock_rule *walker_rule, *next_rule;
+ struct rb_root *src_root;
+ int err = 0;
+
+ might_sleep();
+ lockdep_assert_held(&src->lock);
+
+ src_root = landlock_get_rule_root(&src->rules, key_type);
+ if (IS_ERR(src_root))
+ return PTR_ERR(src_root);
+
+ /* Merges the @src tree. */
+ rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root,
+ node) {
+ struct landlock_layer layers[] = { {
+ .level = dst->num_layers,
+ } };
+ const struct landlock_id id = {
+ .key = walker_rule->key,
+ .type = key_type,
+ };
+
+ if (WARN_ON_ONCE(walker_rule->num_layers != 1))
+ return -EINVAL;
+
+ if (WARN_ON_ONCE(walker_rule->layers[0].level != 0))
+ return -EINVAL;
+
+ layers[0].access = walker_rule->layers[0].access;
+
+ err = landlock_rule_insert(&dst->rules, id, &layers,
+ ARRAY_SIZE(layers));
+ if (err)
+ return err;
+ }
+ return err;
+}
+
+static int merge_ruleset(struct landlock_domain *const dst,
+ struct landlock_ruleset *const src)
+{
+ int err = 0;
+
+ might_sleep();
+ /* Should already be checked by landlock_merge_ruleset() */
+ if (WARN_ON_ONCE(!src))
+ return 0;
+ /* Only merge into a domain. */
+ if (WARN_ON_ONCE(!dst || !dst->hierarchy))
+ return -EINVAL;
+
+ mutex_lock(&src->lock);
+
+ /* Stacks the new layer. */
+ if (WARN_ON_ONCE(dst->num_layers < 1)) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
+ dst->layers[dst->num_layers - 1] =
+ landlock_upgrade_handled_access_masks(src->layer);
+
+ /* Merges the @src inode tree. */
+ err = merge_tree(dst, src, LANDLOCK_KEY_INODE);
+ if (err)
+ goto out_unlock;
+
+#if IS_ENABLED(CONFIG_INET)
+ /* Merges the @src network port tree. */
+ err = merge_tree(dst, src, LANDLOCK_KEY_NET_PORT);
+ if (err)
+ goto out_unlock;
+#endif /* IS_ENABLED(CONFIG_INET) */
+
+out_unlock:
+ mutex_unlock(&src->lock);
+ return err;
+}
+
+static int inherit_tree(struct landlock_domain *const parent,
+ struct landlock_domain *const child,
+ const enum landlock_key_type key_type)
+{
+ struct landlock_rule *walker_rule, *next_rule;
+ struct rb_root *parent_root;
+ int err = 0;
+
+ might_sleep();
+
+ parent_root = landlock_get_rule_root(
+ (struct landlock_rules *)&parent->rules, key_type);
+ if (IS_ERR(parent_root))
+ return PTR_ERR(parent_root);
+
+ /* Copies the @parent inode or network tree. */
+ rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
+ parent_root, node) {
+ const struct landlock_id id = {
+ .key = walker_rule->key,
+ .type = key_type,
+ };
+
+ err = landlock_rule_insert(&child->rules, id,
+ &walker_rule->layers,
+ walker_rule->num_layers);
+ if (err)
+ return err;
+ }
+ return err;
+}
+
+static int inherit_ruleset(struct landlock_domain *const parent,
+ struct landlock_domain *const child)
+{
+ int err = 0;
+
+ might_sleep();
+ if (!parent)
+ return 0;
+
+ /* Copies the @parent inode tree. */
+ err = inherit_tree(parent, child, LANDLOCK_KEY_INODE);
+ if (err)
+ return err;
+
+#if IS_ENABLED(CONFIG_INET)
+ /* Copies the @parent network port tree. */
+ err = inherit_tree(parent, child, LANDLOCK_KEY_NET_PORT);
+ if (err)
+ return err;
+#endif /* IS_ENABLED(CONFIG_INET) */
+
+ if (WARN_ON_ONCE(child->num_layers <= parent->num_layers))
+ return -EINVAL;
+
+ /* Copies the parent layer stack and leaves a space for the new layer. */
+ memcpy(child->layers, parent->layers,
+ flex_array_size(parent, layers, parent->num_layers));
+
+ if (WARN_ON_ONCE(!parent->hierarchy))
+ return -EINVAL;
+
+ landlock_get_hierarchy(parent->hierarchy);
+ child->hierarchy->parent = parent->hierarchy;
+
+ return 0;
+}
+
+/**
+ * landlock_merge_ruleset - Merge a ruleset with a domain
+ *
+ * @parent: Parent domain.
+ * @ruleset: New ruleset to be merged.
+ *
+ * The current task is requesting to be restricted. The subjective credentials
+ * must not be in an overridden state. cf. landlock_init_hierarchy_log().
+ *
+ * Return: A new domain merging @parent and @ruleset on success, or ERR_PTR() on
+ * failure. If @parent is NULL, the new domain duplicates @ruleset.
+ */
+struct landlock_domain *
+landlock_merge_ruleset(struct landlock_domain *const parent,
+ struct landlock_ruleset *const ruleset)
+{
+ struct landlock_domain *new_dom __free(landlock_put_domain) = NULL;
+ u32 num_layers;
+ int err;
+
+ might_sleep();
+ if (WARN_ON_ONCE(!ruleset))
+ return ERR_PTR(-EINVAL);
+
+ if (parent) {
+ if (parent->num_layers >= LANDLOCK_MAX_NUM_LAYERS)
+ return ERR_PTR(-E2BIG);
+ num_layers = parent->num_layers + 1;
+ } else {
+ num_layers = 1;
+ }
+
+ /* Creates a new domain... */
+ new_dom = create_domain(num_layers);
+ if (IS_ERR(new_dom))
+ return new_dom;
+
+ new_dom->hierarchy =
+ kzalloc_obj(*new_dom->hierarchy, GFP_KERNEL_ACCOUNT);
+ if (!new_dom->hierarchy)
+ return ERR_PTR(-ENOMEM);
+
+ refcount_set(&new_dom->hierarchy->usage, 1);
+
+ /* ...as a child of @parent... */
+ err = inherit_ruleset(parent, new_dom);
+ if (err)
+ return ERR_PTR(err);
+
+ /* ...and including @ruleset. */
+ err = merge_ruleset(new_dom, ruleset);
+ if (err)
+ return ERR_PTR(err);
+
+ err = landlock_init_hierarchy_log(new_dom->hierarchy);
+ if (err)
+ return ERR_PTR(err);
+
+ return no_free_ptr(new_dom);
+}
+
#ifdef CONFIG_AUDIT
/**
diff --git a/security/landlock/domain.h b/security/landlock/domain.h
index afa97011ecd2..df11cb7d4f2b 100644
--- a/security/landlock/domain.h
+++ b/security/landlock/domain.h
@@ -196,7 +196,7 @@ struct landlock_domain {
* @work_free: Enables to free a domain within a lockless
* section. This is only used by landlock_put_domain_deferred()
* when @usage reaches zero. The fields @usage, @num_layers and
- * @access_masks are then unused.
+ * @layers are then unused.
*/
struct work_struct work_free;
struct {
@@ -212,7 +212,7 @@ struct landlock_domain {
*/
u32 num_layers;
/**
- * @access_masks: Contains the subset of filesystem and
+ * @layers: Contains the subset of filesystem and
* network actions that are restricted by a domain. A
* domain saves all layers of merged rulesets in a stack
* (FAM), starting from the first layer to the last one.
@@ -222,28 +222,51 @@ struct landlock_domain {
* overlapping access rights. These layers are set once
* and never changed for the lifetime of the domain.
*/
- struct access_masks access_masks[];
+ struct access_masks layers[];
};
};
};
+static inline access_mask_t
+landlock_get_fs_access_mask(const struct landlock_domain *const domain,
+ const u16 layer_level)
+{
+ /* Handles all initially denied by default access rights. */
+ return domain->layers[layer_level].fs |
+ _LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
+}
+
+static inline access_mask_t
+landlock_get_net_access_mask(const struct landlock_domain *const domain,
+ const u16 layer_level)
+{
+ return domain->layers[layer_level].net;
+}
+
+static inline access_mask_t
+landlock_get_scope_mask(const struct landlock_domain *const domain,
+ const u16 layer_level)
+{
+ return domain->layers[layer_level].scope;
+}
+
/**
* landlock_union_access_masks - Return all access rights handled in the
* domain
*
- * @domain: Landlock ruleset (used as a domain)
+ * @domain: Landlock domain
*
* Return: An access_masks result of the OR of all the domain's access masks.
*/
static inline struct access_masks
-landlock_union_access_masks(const struct landlock_ruleset *const domain)
+landlock_union_access_masks(const struct landlock_domain *const domain)
{
union access_masks_all matches = {};
size_t layer_level;
for (layer_level = 0; layer_level < domain->num_layers; layer_level++) {
union access_masks_all layer = {
- .masks = domain->access_masks[layer_level],
+ .masks = domain->layers[layer_level],
};
matches.all |= layer.all;
@@ -258,15 +281,19 @@ void landlock_put_domain_deferred(struct landlock_domain *const domain);
DEFINE_FREE(landlock_put_domain, struct landlock_domain *,
if (!IS_ERR_OR_NULL(_T)) landlock_put_domain(_T))
+struct landlock_domain *
+landlock_merge_ruleset(struct landlock_domain *const parent,
+ struct landlock_ruleset *const ruleset);
+
const struct landlock_rule *
-landlock_find_rule(const struct landlock_ruleset *const ruleset,
+landlock_find_rule(const struct landlock_domain *const domain,
const struct landlock_id id);
bool landlock_unmask_layers(const struct landlock_rule *const rule,
struct layer_access_masks *masks);
access_mask_t
-landlock_init_layer_masks(const struct landlock_ruleset *const domain,
+landlock_init_layer_masks(const struct landlock_domain *const domain,
const access_mask_t access_request,
struct layer_access_masks *masks,
const enum landlock_key_type key_type);
diff --git a/security/landlock/fs.c b/security/landlock/fs.c
index c1ecfe239032..3ef453fc14a6 100644
--- a/security/landlock/fs.c
+++ b/security/landlock/fs.c
@@ -336,12 +336,10 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
if (!d_is_dir(path->dentry) &&
!access_mask_subset(access_rights, ACCESS_FILE))
return -EINVAL;
- if (WARN_ON_ONCE(ruleset->num_layers != 1))
- return -EINVAL;
-
/* Transforms relative access rights to absolute ones. */
- access_rights |= LANDLOCK_MASK_ACCESS_FS &
- ~landlock_get_fs_access_mask(ruleset, 0);
+ access_rights |=
+ LANDLOCK_MASK_ACCESS_FS &
+ ~(ruleset->layer.fs | _LANDLOCK_ACCESS_FS_INITIALLY_DENIED);
id.key.object = get_inode_object(d_backing_inode(path->dentry));
if (IS_ERR(id.key.object))
return PTR_ERR(id.key.object);
@@ -364,7 +362,7 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset,
* Returns NULL if no rule is found or if @dentry is negative.
*/
static const struct landlock_rule *
-find_rule(const struct landlock_ruleset *const domain,
+find_rule(const struct landlock_domain *const domain,
const struct dentry *const dentry)
{
const struct landlock_rule *rule;
@@ -740,7 +738,7 @@ static void test_is_eacces_with_write(struct kunit *const test)
* Return: True if the access request is granted, false otherwise.
*/
static bool
-is_access_to_paths_allowed(const struct landlock_ruleset *const domain,
+is_access_to_paths_allowed(const struct landlock_domain *const domain,
const struct path *const path,
const access_mask_t access_request_parent1,
struct layer_access_masks *layer_masks_parent1,
@@ -1026,7 +1024,7 @@ static access_mask_t maybe_remove(const struct dentry *const dentry)
* Return: True if all the domain access rights are allowed for @dir, false if
* the walk reached @mnt_root.
*/
-static bool collect_domain_accesses(const struct landlock_ruleset *const domain,
+static bool collect_domain_accesses(const struct landlock_domain *const domain,
const struct dentry *const mnt_root,
struct dentry *dir,
struct layer_access_masks *layer_masks_dom)
@@ -1578,8 +1576,8 @@ static int hook_path_truncate(const struct path *const path)
* @masks: Layer access masks to unmask
* @access: Access bits that control scoping
*/
-static void unmask_scoped_access(const struct landlock_ruleset *const client,
- const struct landlock_ruleset *const server,
+static void unmask_scoped_access(const struct landlock_domain *const client,
+ const struct landlock_domain *const server,
struct layer_access_masks *const masks,
const access_mask_t access)
{
@@ -1633,7 +1631,7 @@ static void unmask_scoped_access(const struct landlock_ruleset *const client,
static int hook_unix_find(const struct path *const path, struct sock *other,
int flags)
{
- const struct landlock_ruleset *dom_other;
+ const struct landlock_domain *dom_other;
const struct landlock_cred_security *subject;
struct layer_access_masks layer_masks;
struct landlock_request request = {};
@@ -1914,7 +1912,7 @@ static bool control_current_fowner(struct fown_struct *const fown)
static void hook_file_set_fowner(struct file *file)
{
- struct landlock_ruleset *prev_dom;
+ struct landlock_domain *prev_dom;
struct landlock_cred_security fown_subject = {};
size_t fown_layer = 0;
@@ -1926,7 +1924,7 @@ static void hook_file_set_fowner(struct file *file)
landlock_get_applicable_subject(
current_cred(), signal_scope, &fown_layer);
if (new_subject) {
- landlock_get_ruleset(new_subject->domain);
+ landlock_get_domain(new_subject->domain);
fown_subject = *new_subject;
}
}
@@ -1938,12 +1936,12 @@ static void hook_file_set_fowner(struct file *file)
#endif /* CONFIG_AUDIT*/
/* May be called in an RCU read-side critical section. */
- landlock_put_ruleset_deferred(prev_dom);
+ landlock_put_domain_deferred(prev_dom);
}
static void hook_file_free_security(struct file *file)
{
- landlock_put_ruleset_deferred(landlock_file(file)->fown_subject.domain);
+ landlock_put_domain_deferred(landlock_file(file)->fown_subject.domain);
}
static struct security_hook_list landlock_hooks[] __ro_after_init = {
diff --git a/security/landlock/net.c b/security/landlock/net.c
index 34a72a4f833d..de108b3277bc 100644
--- a/security/landlock/net.c
+++ b/security/landlock/net.c
@@ -32,8 +32,7 @@ int landlock_append_net_rule(struct landlock_ruleset *const ruleset,
BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data));
/* Transforms relative access rights to absolute ones. */
- access_rights |= LANDLOCK_MASK_ACCESS_NET &
- ~landlock_get_net_access_mask(ruleset, 0);
+ access_rights |= LANDLOCK_MASK_ACCESS_NET & ~ruleset->layer.net;
mutex_lock(&ruleset->lock);
err = landlock_insert_rule(ruleset, id, access_rights);
diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c
index 0cf31a7e4c7b..c220e0f9cf5f 100644
--- a/security/landlock/ruleset.c
+++ b/security/landlock/ruleset.c
@@ -20,22 +20,27 @@
#include <linux/refcount.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/workqueue.h>
#include "access.h"
-#include "domain.h"
#include "limits.h"
#include "object.h"
#include "ruleset.h"
-static struct landlock_ruleset *create_ruleset(const u32 num_layers)
+struct landlock_ruleset *
+landlock_create_ruleset(const access_mask_t fs_access_mask,
+ const access_mask_t net_access_mask,
+ const access_mask_t scope_mask)
{
struct landlock_ruleset *new_ruleset;
- new_ruleset = kzalloc_flex(*new_ruleset, access_masks, num_layers,
- GFP_KERNEL_ACCOUNT);
+ /* Informs about useless ruleset. */
+ if (!fs_access_mask && !net_access_mask && !scope_mask)
+ return ERR_PTR(-ENOMSG);
+
+ new_ruleset = kzalloc(sizeof(*new_ruleset), GFP_KERNEL_ACCOUNT);
if (!new_ruleset)
return ERR_PTR(-ENOMEM);
+
refcount_set(&new_ruleset->usage, 1);
mutex_init(&new_ruleset->lock);
new_ruleset->rules.root_inode = RB_ROOT;
@@ -44,34 +49,21 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers)
new_ruleset->rules.root_net_port = RB_ROOT;
#endif /* IS_ENABLED(CONFIG_INET) */
- new_ruleset->num_layers = num_layers;
- /*
- * hierarchy = NULL
- * rules.num_rules = 0
- * access_masks[] = 0
- */
- return new_ruleset;
-}
-
-struct landlock_ruleset *
-landlock_create_ruleset(const access_mask_t fs_access_mask,
- const access_mask_t net_access_mask,
- const access_mask_t scope_mask)
-{
- struct landlock_ruleset *new_ruleset;
-
- /* Informs about useless ruleset. */
- if (!fs_access_mask && !net_access_mask && !scope_mask)
- return ERR_PTR(-ENOMSG);
- new_ruleset = create_ruleset(1);
- if (IS_ERR(new_ruleset))
- return new_ruleset;
- if (fs_access_mask)
- landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0);
- if (net_access_mask)
- landlock_add_net_access_mask(new_ruleset, net_access_mask, 0);
- if (scope_mask)
- landlock_add_scope_mask(new_ruleset, scope_mask, 0);
+ /* Should already be checked in sys_landlock_create_ruleset(). */
+ if (fs_access_mask) {
+ WARN_ON_ONCE(fs_access_mask !=
+ (fs_access_mask & LANDLOCK_MASK_ACCESS_FS));
+ new_ruleset->layer.fs |= fs_access_mask;
+ }
+ if (net_access_mask) {
+ WARN_ON_ONCE(net_access_mask !=
+ (net_access_mask & LANDLOCK_MASK_ACCESS_NET));
+ new_ruleset->layer.net |= net_access_mask;
+ }
+ if (scope_mask) {
+ WARN_ON_ONCE(scope_mask != (scope_mask & LANDLOCK_MASK_SCOPE));
+ new_ruleset->layer.scope |= scope_mask;
+ }
return new_ruleset;
}
@@ -128,7 +120,7 @@ create_rule(const struct landlock_id id,
return ERR_PTR(-ENOMEM);
RB_CLEAR_NODE(&new_rule->node);
if (is_object_pointer(id.type)) {
- /* This should have been caught by insert_rule(). */
+ /* This should have been caught by landlock_rule_insert(). */
WARN_ON_ONCE(!id.key.object);
landlock_get_object(id.key.object);
}
@@ -144,12 +136,6 @@ create_rule(const struct landlock_id id,
return new_rule;
}
-static struct rb_root *get_root(struct landlock_ruleset *const ruleset,
- const enum landlock_key_type key_type)
-{
- return landlock_get_rule_root(&ruleset->rules, key_type);
-}
-
static void free_rule(struct landlock_rule *const rule,
const enum landlock_key_type key_type)
{
@@ -166,16 +152,12 @@ static void build_check_ruleset(void)
const struct landlock_rules rules = {
.num_rules = ~0,
};
- const struct landlock_ruleset ruleset = {
- .num_layers = ~0,
- };
BUILD_BUG_ON(rules.num_rules < LANDLOCK_MAX_NUM_RULES);
- BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS);
}
/**
- * insert_rule - Create and insert a rule in a rule set
+ * landlock_rule_insert - Create and insert a rule in a rule set
*
* @rules: The rule storage to be updated. The caller is responsible for
* any required locking. For rulesets, this means holding
@@ -197,10 +179,10 @@ static void build_check_ruleset(void)
*
* Return: 0 on success, -errno on failure.
*/
-static int insert_rule(struct landlock_rules *const rules,
- const struct landlock_id id,
- const struct landlock_layer (*layers)[],
- const size_t num_layers)
+int landlock_rule_insert(struct landlock_rules *const rules,
+ const struct landlock_id id,
+ const struct landlock_layer (*layers)[],
+ const size_t num_layers)
{
struct rb_node **walker_node;
struct rb_node *parent_node = NULL;
@@ -240,7 +222,7 @@ static int insert_rule(struct landlock_rules *const rules,
if ((*layers)[0].level == 0) {
/*
* Extends access rights when the request comes from
- * landlock_add_rule(2), i.e. contained by a ruleset.
+ * landlock_add_rule(2), i.e. @rules is not a domain.
*/
if (WARN_ON_ONCE(this->num_layers != 1))
return -EINVAL;
@@ -301,176 +283,14 @@ int landlock_insert_rule(struct landlock_ruleset *const ruleset,
{
struct landlock_layer layers[] = { {
.access = access,
- /* When @level is zero, insert_rule() extends @ruleset. */
+ /* When @level is zero, landlock_rule_insert() extends @ruleset. */
.level = 0,
} };
build_check_layer();
lockdep_assert_held(&ruleset->lock);
- return insert_rule(&ruleset->rules, id, &layers, ARRAY_SIZE(layers));
-}
-
-static int merge_tree(struct landlock_ruleset *const dst,
- struct landlock_ruleset *const src,
- const enum landlock_key_type key_type)
-{
- struct landlock_rule *walker_rule, *next_rule;
- struct rb_root *src_root;
- int err = 0;
-
- might_sleep();
- lockdep_assert_held(&dst->lock);
- lockdep_assert_held(&src->lock);
-
- src_root = get_root(src, key_type);
- if (IS_ERR(src_root))
- return PTR_ERR(src_root);
-
- /* Merges the @src tree. */
- rbtree_postorder_for_each_entry_safe(walker_rule, next_rule, src_root,
- node) {
- struct landlock_layer layers[] = { {
- .level = dst->num_layers,
- } };
- const struct landlock_id id = {
- .key = walker_rule->key,
- .type = key_type,
- };
-
- if (WARN_ON_ONCE(walker_rule->num_layers != 1))
- return -EINVAL;
-
- if (WARN_ON_ONCE(walker_rule->layers[0].level != 0))
- return -EINVAL;
-
- layers[0].access = walker_rule->layers[0].access;
-
- err = insert_rule(&dst->rules, id, &layers, ARRAY_SIZE(layers));
- if (err)
- return err;
- }
- return err;
-}
-
-static int merge_ruleset(struct landlock_ruleset *const dst,
- struct landlock_ruleset *const src)
-{
- int err = 0;
-
- might_sleep();
- /* Should already be checked by landlock_merge_ruleset() */
- if (WARN_ON_ONCE(!src))
- return 0;
- /* Only merge into a domain. */
- if (WARN_ON_ONCE(!dst || !dst->hierarchy))
- return -EINVAL;
-
- /* Locks @dst first because we are its only owner. */
- mutex_lock(&dst->lock);
- mutex_lock_nested(&src->lock, SINGLE_DEPTH_NESTING);
-
- /* Stacks the new layer. */
- if (WARN_ON_ONCE(src->num_layers != 1 || dst->num_layers < 1)) {
- err = -EINVAL;
- goto out_unlock;
- }
- dst->access_masks[dst->num_layers - 1] =
- landlock_upgrade_handled_access_masks(src->access_masks[0]);
-
- /* Merges the @src inode tree. */
- err = merge_tree(dst, src, LANDLOCK_KEY_INODE);
- if (err)
- goto out_unlock;
-
-#if IS_ENABLED(CONFIG_INET)
- /* Merges the @src network port tree. */
- err = merge_tree(dst, src, LANDLOCK_KEY_NET_PORT);
- if (err)
- goto out_unlock;
-#endif /* IS_ENABLED(CONFIG_INET) */
-
-out_unlock:
- mutex_unlock(&src->lock);
- mutex_unlock(&dst->lock);
- return err;
-}
-
-static int inherit_tree(struct landlock_ruleset *const parent,
- struct landlock_ruleset *const child,
- const enum landlock_key_type key_type)
-{
- struct landlock_rule *walker_rule, *next_rule;
- struct rb_root *parent_root;
- int err = 0;
-
- might_sleep();
- lockdep_assert_held(&parent->lock);
- lockdep_assert_held(&child->lock);
-
- parent_root = get_root(parent, key_type);
- if (IS_ERR(parent_root))
- return PTR_ERR(parent_root);
-
- /* Copies the @parent inode or network tree. */
- rbtree_postorder_for_each_entry_safe(walker_rule, next_rule,
- parent_root, node) {
- const struct landlock_id id = {
- .key = walker_rule->key,
- .type = key_type,
- };
-
- err = insert_rule(&child->rules, id, &walker_rule->layers,
- walker_rule->num_layers);
- if (err)
- return err;
- }
- return err;
-}
-
-static int inherit_ruleset(struct landlock_ruleset *const parent,
- struct landlock_ruleset *const child)
-{
- int err = 0;
-
- might_sleep();
- if (!parent)
- return 0;
-
- /* Locks @child first because we are its only owner. */
- mutex_lock(&child->lock);
- mutex_lock_nested(&parent->lock, SINGLE_DEPTH_NESTING);
-
- /* Copies the @parent inode tree. */
- err = inherit_tree(parent, child, LANDLOCK_KEY_INODE);
- if (err)
- goto out_unlock;
-
-#if IS_ENABLED(CONFIG_INET)
- /* Copies the @parent network port tree. */
- err = inherit_tree(parent, child, LANDLOCK_KEY_NET_PORT);
- if (err)
- goto out_unlock;
-#endif /* IS_ENABLED(CONFIG_INET) */
-
- if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) {
- err = -EINVAL;
- goto out_unlock;
- }
- /* Copies the parent layer stack and leaves a space for the new layer. */
- memcpy(child->access_masks, parent->access_masks,
- flex_array_size(parent, access_masks, parent->num_layers));
-
- if (WARN_ON_ONCE(!parent->hierarchy)) {
- err = -EINVAL;
- goto out_unlock;
- }
- landlock_get_hierarchy(parent->hierarchy);
- child->hierarchy->parent = parent->hierarchy;
-
-out_unlock:
- mutex_unlock(&parent->lock);
- mutex_unlock(&child->lock);
- return err;
+ return landlock_rule_insert(&ruleset->rules, id, &layers,
+ ARRAY_SIZE(layers));
}
void landlock_free_rules(struct landlock_rules *const rules)
@@ -493,7 +313,6 @@ static void free_ruleset(struct landlock_ruleset *const ruleset)
{
might_sleep();
landlock_free_rules(&ruleset->rules);
- landlock_put_hierarchy(ruleset->hierarchy);
kfree(ruleset);
}
@@ -503,81 +322,3 @@ void landlock_put_ruleset(struct landlock_ruleset *const ruleset)
if (ruleset && refcount_dec_and_test(&ruleset->usage))
free_ruleset(ruleset);
}
-
-static void free_ruleset_work(struct work_struct *const work)
-{
- struct landlock_ruleset *ruleset;
-
- ruleset = container_of(work, struct landlock_ruleset, work_free);
- free_ruleset(ruleset);
-}
-
-/* Only called by hook_cred_free(). */
-void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset)
-{
- if (ruleset && refcount_dec_and_test(&ruleset->usage)) {
- INIT_WORK(&ruleset->work_free, free_ruleset_work);
- schedule_work(&ruleset->work_free);
- }
-}
-
-/**
- * landlock_merge_ruleset - Merge a ruleset with a domain
- *
- * @parent: Parent domain.
- * @ruleset: New ruleset to be merged.
- *
- * The current task is requesting to be restricted. The subjective credentials
- * must not be in an overridden state. cf. landlock_init_hierarchy_log().
- *
- * Return: A new domain merging @parent and @ruleset on success, or ERR_PTR()
- * on failure. If @parent is NULL, the new domain duplicates @ruleset.
- */
-struct landlock_ruleset *
-landlock_merge_ruleset(struct landlock_ruleset *const parent,
- struct landlock_ruleset *const ruleset)
-{
- struct landlock_ruleset *new_dom __free(landlock_put_ruleset) = NULL;
- u32 num_layers;
- int err;
-
- might_sleep();
- if (WARN_ON_ONCE(!ruleset || parent == ruleset))
- return ERR_PTR(-EINVAL);
-
- if (parent) {
- if (parent->num_layers >= LANDLOCK_MAX_NUM_LAYERS)
- return ERR_PTR(-E2BIG);
- num_layers = parent->num_layers + 1;
- } else {
- num_layers = 1;
- }
-
- /* Creates a new domain... */
- new_dom = create_ruleset(num_layers);
- if (IS_ERR(new_dom))
- return new_dom;
-
- new_dom->hierarchy =
- kzalloc_obj(*new_dom->hierarchy, GFP_KERNEL_ACCOUNT);
- if (!new_dom->hierarchy)
- return ERR_PTR(-ENOMEM);
-
- refcount_set(&new_dom->hierarchy->usage, 1);
-
- /* ...as a child of @parent... */
- err = inherit_ruleset(parent, new_dom);
- if (err)
- return ERR_PTR(err);
-
- /* ...and including @ruleset. */
- err = merge_ruleset(new_dom, ruleset);
- if (err)
- return ERR_PTR(err);
-
- err = landlock_init_hierarchy_log(new_dom->hierarchy);
- if (err)
- return ERR_PTR(err);
-
- return no_free_ptr(new_dom);
-}
diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h
index 1d3a9c36eb74..bf127ff7496e 100644
--- a/security/landlock/ruleset.h
+++ b/security/landlock/ruleset.h
@@ -14,14 +14,11 @@
#include <linux/mutex.h>
#include <linux/rbtree.h>
#include <linux/refcount.h>
-#include <linux/workqueue.h>
#include "access.h"
#include "limits.h"
#include "object.h"
-struct landlock_hierarchy;
-
/**
* struct landlock_layer - Access rights for a given layer
*/
@@ -147,54 +144,20 @@ struct landlock_ruleset {
* @rules: Red-black tree storage for rules.
*/
struct landlock_rules rules;
-
/**
- * @hierarchy: Enables hierarchy identification even when a parent
- * domain vanishes. This is needed for the ptrace protection.
+ * @lock: Protects against concurrent modifications of @rules, if @usage
+ * is greater than zero.
+ */
+ struct mutex lock;
+ /**
+ * @usage: Number of file descriptors referencing this ruleset.
*/
- struct landlock_hierarchy *hierarchy;
- union {
- /**
- * @work_free: Enables to free a ruleset within a lockless
- * section. This is only used by
- * landlock_put_ruleset_deferred() when @usage reaches zero. The
- * fields @lock, @usage, @num_layers and @access_masks are then
- * unused.
- */
- struct work_struct work_free;
- struct {
- /**
- * @lock: Protects against concurrent modifications of
- * @root, if @usage is greater than zero.
- */
- struct mutex lock;
- /**
- * @usage: Number of processes (i.e. domains) or file
- * descriptors referencing this ruleset.
- */
- refcount_t usage;
- /**
- * @num_layers: Number of layers that are used in this
- * ruleset. This enables to check that all the layers
- * allow an access request. A value of 0 identifies a
- * non-merged ruleset (i.e. not a domain).
- */
- u32 num_layers;
- /**
- * @access_masks: Contains the subset of filesystem and
- * network actions that are restricted by a ruleset.
- * A domain saves all layers of merged rulesets in a
- * stack (FAM), starting from the first layer to the
- * last one. These layers are used when merging
- * rulesets, for user space backward compatibility
- * (i.e. future-proof), and to properly handle merged
- * rulesets without overlapping access rights. These
- * layers are set once and never changed for the
- * lifetime of the ruleset.
- */
- struct access_masks access_masks[];
- };
- };
+ refcount_t usage;
+ /**
+ * @layer: Contains the subset of filesystem and network actions that
+ * are handled by this ruleset.
+ */
+ struct access_masks layer;
};
struct landlock_ruleset *
@@ -203,7 +166,6 @@ landlock_create_ruleset(const access_mask_t access_mask_fs,
const access_mask_t scope_mask);
void landlock_put_ruleset(struct landlock_ruleset *const ruleset);
-void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset);
DEFINE_FREE(landlock_put_ruleset, struct landlock_ruleset *,
if (!IS_ERR_OR_NULL(_T)) landlock_put_ruleset(_T))
@@ -212,11 +174,12 @@ int landlock_insert_rule(struct landlock_ruleset *const ruleset,
const struct landlock_id id,
const access_mask_t access);
-void landlock_free_rules(struct landlock_rules *const rules);
+int landlock_rule_insert(struct landlock_rules *const rules,
+ const struct landlock_id id,
+ const struct landlock_layer (*layers)[],
+ const size_t num_layers);
-struct landlock_ruleset *
-landlock_merge_ruleset(struct landlock_ruleset *const parent,
- struct landlock_ruleset *const ruleset);
+void landlock_free_rules(struct landlock_rules *const rules);
/**
* landlock_get_rule_root - Get the root of a rule tree by key type
@@ -251,62 +214,4 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset)
refcount_inc(&ruleset->usage);
}
-static inline void
-landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset,
- const access_mask_t fs_access_mask,
- const u16 layer_level)
-{
- access_mask_t fs_mask = fs_access_mask & LANDLOCK_MASK_ACCESS_FS;
-
- /* Should already be checked in sys_landlock_create_ruleset(). */
- WARN_ON_ONCE(fs_access_mask != fs_mask);
- ruleset->access_masks[layer_level].fs |= fs_mask;
-}
-
-static inline void
-landlock_add_net_access_mask(struct landlock_ruleset *const ruleset,
- const access_mask_t net_access_mask,
- const u16 layer_level)
-{
- access_mask_t net_mask = net_access_mask & LANDLOCK_MASK_ACCESS_NET;
-
- /* Should already be checked in sys_landlock_create_ruleset(). */
- WARN_ON_ONCE(net_access_mask != net_mask);
- ruleset->access_masks[layer_level].net |= net_mask;
-}
-
-static inline void
-landlock_add_scope_mask(struct landlock_ruleset *const ruleset,
- const access_mask_t scope_mask, const u16 layer_level)
-{
- access_mask_t mask = scope_mask & LANDLOCK_MASK_SCOPE;
-
- /* Should already be checked in sys_landlock_create_ruleset(). */
- WARN_ON_ONCE(scope_mask != mask);
- ruleset->access_masks[layer_level].scope |= mask;
-}
-
-static inline access_mask_t
-landlock_get_fs_access_mask(const struct landlock_ruleset *const ruleset,
- const u16 layer_level)
-{
- /* Handles all initially denied by default access rights. */
- return ruleset->access_masks[layer_level].fs |
- _LANDLOCK_ACCESS_FS_INITIALLY_DENIED;
-}
-
-static inline access_mask_t
-landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset,
- const u16 layer_level)
-{
- return ruleset->access_masks[layer_level].net;
-}
-
-static inline access_mask_t
-landlock_get_scope_mask(const struct landlock_ruleset *const ruleset,
- const u16 layer_level)
-{
- return ruleset->access_masks[layer_level].scope;
-}
-
#endif /* _SECURITY_LANDLOCK_RULESET_H */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index accfd2e5a0cd..73ccc32d0afd 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -283,8 +283,6 @@ static struct landlock_ruleset *get_ruleset_from_fd(const int fd,
if (!(fd_file(ruleset_f)->f_mode & mode))
return ERR_PTR(-EPERM);
ruleset = fd_file(ruleset_f)->private_data;
- if (WARN_ON_ONCE(ruleset->num_layers != 1))
- return ERR_PTR(-EINVAL);
landlock_get_ruleset(ruleset);
return ruleset;
}
@@ -341,7 +339,7 @@ static int add_rule_path_beneath(struct landlock_ruleset *const ruleset,
return -ENOMSG;
/* Checks that allowed_access matches the @ruleset constraints. */
- mask = ruleset->access_masks[0].fs;
+ mask = ruleset->layer.fs;
if ((path_beneath_attr.allowed_access | mask) != mask)
return -EINVAL;
@@ -377,7 +375,7 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset,
return -ENOMSG;
/* Checks that allowed_access matches the @ruleset constraints. */
- mask = landlock_get_net_access_mask(ruleset, 0);
+ mask = ruleset->layer.net;
if ((net_port_attr.allowed_access | mask) != mask)
return -EINVAL;
@@ -556,7 +554,7 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
* manipulating the current credentials because they are
* dedicated per thread.
*/
- struct landlock_ruleset *const new_dom =
+ struct landlock_domain *const new_dom =
landlock_merge_ruleset(new_llcred->domain, ruleset);
if (IS_ERR(new_dom)) {
abort_creds(new_cred);
@@ -571,7 +569,7 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
#endif /* CONFIG_AUDIT */
/* Replaces the old (prepared) domain. */
- landlock_put_ruleset(new_llcred->domain);
+ landlock_put_domain(new_llcred->domain);
new_llcred->domain = new_dom;
#ifdef CONFIG_AUDIT
diff --git a/security/landlock/task.c b/security/landlock/task.c
index 6d46042132ce..2e7ee62958b2 100644
--- a/security/landlock/task.c
+++ b/security/landlock/task.c
@@ -41,8 +41,8 @@
* Return: True if @parent is an ancestor of or equal to @child, false
* otherwise.
*/
-static bool domain_scope_le(const struct landlock_ruleset *const parent,
- const struct landlock_ruleset *const child)
+static bool domain_scope_le(const struct landlock_domain *const parent,
+ const struct landlock_domain *const child)
{
const struct landlock_hierarchy *walker;
@@ -63,8 +63,8 @@ static bool domain_scope_le(const struct landlock_ruleset *const parent,
return false;
}
-static int domain_ptrace(const struct landlock_ruleset *const parent,
- const struct landlock_ruleset *const child)
+static int domain_ptrace(const struct landlock_domain *const parent,
+ const struct landlock_domain *const child)
{
if (domain_scope_le(parent, child))
return 0;
@@ -97,7 +97,7 @@ static int hook_ptrace_access_check(struct task_struct *const child,
scoped_guard(rcu)
{
- const struct landlock_ruleset *const child_dom =
+ const struct landlock_domain *const child_dom =
landlock_get_task_domain(child);
err = domain_ptrace(parent_subject->domain, child_dom);
}
@@ -136,7 +136,7 @@ static int hook_ptrace_access_check(struct task_struct *const child,
static int hook_ptrace_traceme(struct task_struct *const parent)
{
const struct landlock_cred_security *parent_subject;
- const struct landlock_ruleset *child_dom;
+ const struct landlock_domain *child_dom;
int err;
child_dom = landlock_get_current_domain();
@@ -177,8 +177,8 @@ static int hook_ptrace_traceme(struct task_struct *const parent)
* Return: True if @server is in a different domain from @client and @client
* is scoped to access @server (i.e. access should be denied), false otherwise.
*/
-static bool domain_is_scoped(const struct landlock_ruleset *const client,
- const struct landlock_ruleset *const server,
+static bool domain_is_scoped(const struct landlock_domain *const client,
+ const struct landlock_domain *const server,
access_mask_t scope)
{
int client_layer, server_layer;
@@ -237,9 +237,9 @@ static bool domain_is_scoped(const struct landlock_ruleset *const client,
}
static bool sock_is_scoped(struct sock *const other,
- const struct landlock_ruleset *const domain)
+ const struct landlock_domain *const domain)
{
- const struct landlock_ruleset *dom_other;
+ const struct landlock_domain *dom_other;
/* The credentials will not change. */
lockdep_assert_held(&unix_sk(other)->lock);
--
2.53.0
next prev parent reply other threads:[~2026-04-06 14:37 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-06 14:36 [PATCH v2 00/17] Landlock tracepoints Mickaël Salaün
2026-04-06 14:36 ` [PATCH v2 01/17] landlock: Prepare ruleset and domain type split Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 02/17] landlock: Move domain query functions to domain.c Mickaël Salaün
2026-04-06 14:37 ` Mickaël Salaün [this message]
2026-04-06 14:37 ` [PATCH v2 04/17] landlock: Split denial logging from audit into common framework Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 05/17] tracing: Add __print_untrusted_str() Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 06/17] landlock: Add create_ruleset and free_ruleset tracepoints Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 07/17] landlock: Add landlock_add_rule_fs and landlock_add_rule_net tracepoints Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 08/17] landlock: Add restrict_self and free_domain tracepoints Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 09/17] landlock: Add tracepoints for rule checking Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 10/17] landlock: Set audit_net.sk for socket access checks Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 11/17] landlock: Add landlock_deny_access_fs and landlock_deny_access_net Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 12/17] landlock: Add tracepoints for ptrace and scope denials Mickaël Salaün
2026-04-06 15:01 ` Steven Rostedt
2026-04-07 13:00 ` Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 13/17] selftests/landlock: Add trace event test infrastructure and tests Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 14/17] selftests/landlock: Add filesystem tracepoint tests Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 15/17] selftests/landlock: Add network " Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 16/17] selftests/landlock: Add scope and ptrace " Mickaël Salaün
2026-04-06 14:37 ` [PATCH v2 17/17] landlock: Document tracepoints Mickaël Salaün
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260406143717.1815792-4-mic@digikod.net \
--to=mic@digikod.net \
--cc=brauner@kernel.org \
--cc=gnoack@google.com \
--cc=ivanov.mikhail1@huawei-partners.com \
--cc=jannh@google.com \
--cc=jeffxu@google.com \
--cc=kees@kernel.org \
--cc=kernel-team@cloudflare.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=m@maowtm.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=matthieu@buffet.re \
--cc=mhiramat@kernel.org \
--cc=rostedt@goodmis.org \
--cc=utilityemal77@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox