[RFC PATCH 1/9] Define the supervisor and event structure

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

 



In the current design (mostly not implemented yet), a "supervisor" is a
program that creates (but probably not enforce on itself) a Landlock
ruleset which it specifically marks as operating in "supervise" mode. For
such a layer (but not other layers below or above it), access not granted
by the ruleset, which would normally result in a denial, instead triggers
a supervise event, and the thread which caused the event is paused until
either the supervisor responds to the event, the event is cancelled due to
supervisor termination, or the requesting thread being killed.

We define a refcounted structure that represents a supervisor, and will
later be exposed to the user-space via a file descriptor.  Each supervisor
has an event queue and a separate list of events which have been read by
the supervisor and is now awaiting response.  This allows the future read
codepath to not have to iterate over already notified events, but still
allow the response codepath to find the event.

The event struct is also refcounted, so that it is not tied to the
lifetime of the supervisor (e.g. if it dies, the task doing the access
that is currently stuck in kernel syscall still holds the event refcount,
and can read its status safely).

The details of the event structure will be populated in a future patch.

The struct is called landlock_supervise_event_kernel so that the uapi
header can use the shorter name.

Signed-off-by: Tingmao Wang <m@xxxxxxxxxx>
---
 security/landlock/Makefile    |  2 +-
 security/landlock/supervise.c | 72 +++++++++++++++++++++++++++++++++++
 security/landlock/supervise.h | 63 ++++++++++++++++++++++++++++++
 3 files changed, 136 insertions(+), 1 deletion(-)
 create mode 100644 security/landlock/supervise.c
 create mode 100644 security/landlock/supervise.h

diff --git a/security/landlock/Makefile b/security/landlock/Makefile
index b4538b7cf7d2..c9bab22ab0f5 100644
--- a/security/landlock/Makefile
+++ b/security/landlock/Makefile
@@ -1,6 +1,6 @@
 obj-$(CONFIG_SECURITY_LANDLOCK) := landlock.o
 
 landlock-y := setup.o syscalls.o object.o ruleset.o \
-	cred.o task.o fs.o
+	cred.o task.o fs.o supervise.o
 
 landlock-$(CONFIG_INET) += net.o
diff --git a/security/landlock/supervise.c b/security/landlock/supervise.c
new file mode 100644
index 000000000000..a3bb6928f453
--- /dev/null
+++ b/security/landlock/supervise.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Landlock LSM - Implementation specific to landlock-supervise
+ *
+ * Copyright © 2025 Tingmao Wang <m@xxxxxxxxxx>
+ */
+
+#include <linux/path.h>
+#include <linux/pid.h>
+#include <linux/slab.h>
+#include <linux/wait_bit.h>
+
+#include "supervise.h"
+
+struct landlock_supervisor *landlock_create_supervisor(void)
+{
+	struct landlock_supervisor *supervisor;
+
+	supervisor = kzalloc(sizeof(*supervisor), GFP_KERNEL_ACCOUNT);
+	if (!supervisor)
+		return ERR_PTR(-ENOMEM);
+	refcount_set(&supervisor->usage, 1);
+	supervisor->next_event_id = 1;
+	spin_lock_init(&supervisor->lock);
+	INIT_LIST_HEAD(&supervisor->event_queue);
+	INIT_LIST_HEAD(&supervisor->notified_events);
+	init_waitqueue_head(&supervisor->poll_event_wq);
+	return supervisor;
+}
+
+void landlock_get_supervisor(struct landlock_supervisor *const supervisor)
+{
+	refcount_inc(&supervisor->usage);
+}
+
+static void
+deny_and_put_event(struct landlock_supervise_event_kernel *const event)
+{
+	cmpxchg(&event->state, LANDLOCK_SUPERVISE_EVENT_NEW,
+		LANDLOCK_SUPERVISE_EVENT_DENIED);
+	cmpxchg(&event->state, LANDLOCK_SUPERVISE_EVENT_NOTIFIED,
+		LANDLOCK_SUPERVISE_EVENT_DENIED);
+	wake_up_var(event);
+	landlock_put_supervise_event(event);
+}
+
+void landlock_put_supervisor(struct landlock_supervisor *const supervisor)
+{
+	if (refcount_dec_and_test(&supervisor->usage)) {
+		struct landlock_supervise_event_kernel *freeme, *next;
+
+		might_sleep();
+		/* we are the only reference, hence no locking */
+
+		/* deny all pending events */
+		list_for_each_entry_safe(freeme, next, &supervisor->event_queue,
+					 node) {
+			list_del(&freeme->node);
+			deny_and_put_event(freeme);
+		}
+		/*
+		 * user reply no longer possible without any reference to
+		 * supervisor, deny all notified events
+		 */
+		list_for_each_entry_safe(freeme, next,
+					 &supervisor->notified_events, node) {
+			list_del(&freeme->node);
+			deny_and_put_event(freeme);
+		}
+		kfree(supervisor);
+	}
+}
diff --git a/security/landlock/supervise.h b/security/landlock/supervise.h
new file mode 100644
index 000000000000..1fc3460335af
--- /dev/null
+++ b/security/landlock/supervise.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Landlock LSM - Implementation specific to landlock-supervise
+ *
+ * Copyright © 2025 Tingmao Wang <m@xxxxxxxxxx>
+ */
+
+#ifndef _SECURITY_LANDLOCK_SUPERVISE_H
+#define _SECURITY_LANDLOCK_SUPERVISE_H
+
+#include <linux/refcount.h>
+#include <linux/wait.h>
+#include <linux/path.h>
+#include <linux/pid.h>
+
+#include "access.h"
+#include "ruleset.h"
+
+struct landlock_supervisor {
+	refcount_t usage;
+	spinlock_t lock;
+	/* protected by @lock, contains landlock_supervise_event_kernel */
+	struct list_head event_queue;
+	/* protected by @lock, contains landlock_supervise_event_kernel */
+	struct list_head notified_events;
+	struct wait_queue_head poll_event_wq;
+	/* protected by @lock */
+	u32 next_event_id;
+};
+
+enum landlock_supervise_event_state {
+	LANDLOCK_SUPERVISE_EVENT_NEW,
+	LANDLOCK_SUPERVISE_EVENT_NOTIFIED,
+	LANDLOCK_SUPERVISE_EVENT_ALLOWED,
+	LANDLOCK_SUPERVISE_EVENT_DENIED,
+};
+
+struct landlock_supervise_event_kernel {
+	struct list_head node;
+	refcount_t usage;
+	enum landlock_supervise_event_state state;
+
+	/* more fields to come */
+};
+
+struct landlock_supervisor *landlock_create_supervisor(void);
+void landlock_get_supervisor(struct landlock_supervisor *const supervisor);
+void landlock_put_supervisor(struct landlock_supervisor *const supervisor);
+
+static inline void landlock_get_supervise_event(
+	struct landlock_supervise_event_kernel *const event)
+{
+	refcount_inc(&event->usage);
+}
+
+static inline void landlock_put_supervise_event(
+	struct landlock_supervise_event_kernel *const event)
+{
+	if (refcount_dec_and_test(&event->usage))
+		kfree(event);
+}
+
+#endif /* _SECURITY_LANDLOCK_SUPERVISE_H */
-- 
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