@@ -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);
}
@@ -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;
};
/**
@@ -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;
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@maowtm.org> --- security/landlock/ruleset.c | 26 +++++++++++++++++++++++--- security/landlock/ruleset.h | 7 +++++++ security/landlock/supervise.h | 6 ++++++ 3 files changed, 36 insertions(+), 3 deletions(-)