[RFC PATCH 3/9] Adds a supervisor reference in the per-layer information

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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





[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux