Following from the previous patch, we now use the new per-layer struct to store a reference to any supervisor attached to a layer (merged in a domain or unmerged). The supervisor is refcounted, and so we need to correctly get/put it when inheriting a domain or when merging a layer. This means looping through all the layers and getting each supervisor that exists, as the domain effectively stores a copy of all the inherited layers. TODO: because we are now referencing the supervisor in the layer, the event deny and cleanup code in landlock_put_supervisor won't work as intended. I didn't realize this until after finishing this set of patches, so this will be addressed in a future series. Signed-off-by: Tingmao Wang <m@xxxxxxxxxx> --- security/landlock/ruleset.c | 26 +++++++++++++++++++++++--- security/landlock/ruleset.h | 7 +++++++ security/landlock/supervise.h | 6 ++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c index 2cc6f7c5eb1b..2e93b8105cc9 100644 --- a/security/landlock/ruleset.c +++ b/security/landlock/ruleset.c @@ -26,6 +26,7 @@ #include "limits.h" #include "object.h" #include "ruleset.h" +#include "supervise.h" static struct landlock_ruleset *create_ruleset(const u32 num_layers) { @@ -389,9 +390,14 @@ static int merge_ruleset(struct landlock_ruleset *const dst, err = -EINVAL; goto out_unlock; } - dst->layer_stack[dst->num_layers - 1].access_masks = - landlock_upgrade_handled_access_masks( - src->layer_stack[0].access_masks); + dst->layer_stack[dst->num_layers - 1] = (struct landlock_ruleset_layer){ + .access_masks = landlock_upgrade_handled_access_masks( + src->layer_stack[0].access_masks), + .supervisor = src->layer_stack[0].supervisor, + }; + if (dst->layer_stack[dst->num_layers - 1].supervisor) + landlock_get_supervisor( + dst->layer_stack[dst->num_layers - 1].supervisor); /* Merges the @src inode tree. */ err = merge_tree(dst, src, LANDLOCK_KEY_INODE); @@ -447,6 +453,7 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, struct landlock_ruleset *const child) { int err = 0; + int layer; might_sleep(); if (!parent) @@ -475,6 +482,12 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, /* Copies the parent layer stack and leaves a space for the new layer. */ memcpy(child->layer_stack, parent->layer_stack, flex_array_size(parent, layer_stack, parent->num_layers)); + /* Get the refcount of any supervisor copied over */ + for (layer = 0; layer < child->num_layers; layer++) { + if (child->layer_stack[layer].supervisor) + landlock_get_supervisor( + child->layer_stack[layer].supervisor); + } if (WARN_ON_ONCE(!parent->hierarchy)) { err = -EINVAL; @@ -492,6 +505,7 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, static void free_ruleset(struct landlock_ruleset *const ruleset) { struct landlock_rule *freeme, *next; + int layer; might_sleep(); rbtree_postorder_for_each_entry_safe(freeme, next, &ruleset->root_inode, @@ -505,6 +519,12 @@ static void free_ruleset(struct landlock_ruleset *const ruleset) #endif /* IS_ENABLED(CONFIG_INET) */ put_hierarchy(ruleset->hierarchy); + for (layer = 0; layer < ruleset->num_layers; layer++) { + struct landlock_supervisor *const supervisor = + ruleset->layer_stack[layer].supervisor; + if (supervisor) + landlock_put_supervisor(supervisor); + } kfree(ruleset); } diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h index a2605959f733..ed530643ea68 100644 --- a/security/landlock/ruleset.h +++ b/security/landlock/ruleset.h @@ -136,6 +136,13 @@ struct landlock_ruleset_layer { * network actions that are restricted by a layer. */ struct access_masks access_masks; + /** + * @supervisor: If not null, this layer is operating in + * supervisor mode. Access denied by only supervised layers + * are forwarded to the supervisor(s), who can then make a + * decision whether to actually deny the access, or allow it. + */ + struct landlock_supervisor *supervisor; }; /** diff --git a/security/landlock/supervise.h b/security/landlock/supervise.h index 1fc3460335af..febe26a11578 100644 --- a/security/landlock/supervise.h +++ b/security/landlock/supervise.h @@ -16,6 +16,12 @@ #include "access.h" #include "ruleset.h" +/** + * Each supervisor is associated with one active layer in a + * domain (or associated with a not-yet-active layer in a struct + * landlock_ruleset). User-space interact with the event queue + * through a landlock_supervise_fd. + */ struct landlock_supervisor { refcount_t usage; spinlock_t lock; -- 2.39.5