[RFC PATCH 5/9] Define user structure for events and responses.
Tingmao Wang
m at maowtm.org
Tue Mar 4 01:13:01 UTC 2025
The two structures are designed to be passed via read and write
to the supervisor-fd. Compile time check for no holes are added
to build_check_abi.
The event structure will be a dynamically sized structure with
possibly a NULL-terminating filename at the end. This is so that
we can pass a raw filename to the supervisor for file creation
requests, without having the trouble of not being able to open a
fd to a file that has not been created.
NOTE: despite this patch having a new uapi, I'm still very open to e.g.
re-using fanotify stuff instead (if that makes sense in the end). This is
just a PoC.
Signed-off-by: Tingmao Wang <m at maowtm.org>
---
include/uapi/linux/landlock.h | 107 ++++++++++++++++++++++++++++++++++
security/landlock/syscalls.c | 28 +++++++++
2 files changed, 135 insertions(+)
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 7bc1eb4859fb..b5645fdd998d 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -318,4 +318,111 @@ struct landlock_net_port_attr {
#define LANDLOCK_SCOPE_SIGNAL (1ULL << 1)
/* clang-format on*/
+/**
+ * DOC: supervisor
+ *
+ * Supervise mode
+ * ~~~~~~~~~~~~~~
+ *
+ * TODO
+ */
+
+typedef __u16 landlock_supervise_event_type_t;
+/* clang-format off */
+#define LANDLOCK_SUPERVISE_EVENT_TYPE_FS_ACCESS 1
+#define LANDLOCK_SUPERVISE_EVENT_TYPE_NET_ACCESS 2
+/* clang-format on */
+
+struct landlock_supervise_event_hdr {
+ /**
+ * @type: Type of the event.
+ */
+ landlock_supervise_event_type_t type;
+ /**
+ * @length: Length of the entire struct
+ * landlock_supervise_event including this header.
+ */
+ __u16 length;
+ /**
+ * @cookie: Opaque identifier to be included in the response.
+ */
+ __u32 cookie;
+};
+
+struct landlock_supervise_event {
+ struct landlock_supervise_event_hdr hdr;
+ __u64 access_request;
+ __kernel_pid_t accessor;
+ union {
+ struct {
+ /**
+ * @fd1: An open file descriptor for the file (open,
+ * delete, execute, link, readdir, rename, truncate),
+ * or the parent directory (for create operations
+ * targeting its child) being accessed. Must be
+ * closed by the reader.
+ *
+ * If this points to a parent directory, @destname
+ * will contain the target filename. If @destname is
+ * empty, this points to the target file.
+ */
+ int fd1;
+ /**
+ * @fd2: For link or rename requests, a second file
+ * descriptor for the target parent directory. Must
+ * be closed by the reader. @destname contains the
+ * destination filename. This field is -1 if not
+ * used.
+ */
+ int fd2;
+ /**
+ * @destname: A filename for a file creation target.
+ *
+ * If either of fd1 or fd2 points to a parent
+ * directory rather than the target file, this is the
+ * NULL-terminated name of the file that will be
+ * newly created.
+ *
+ * Counting the NULL terminator, this field will
+ * contain one or more NULL padding at the end so
+ * that the length of the whole struct
+ * landlock_supervise_event is a multiple of 8 bytes.
+ *
+ * This is a variable length member, and the length
+ * including the terminating NULL(s) can be derived
+ * from hdr.length - offsetof(struct
+ * landlock_supervise_event, destname).
+ */
+ char destname[];
+ };
+ struct {
+ __u16 port;
+ };
+ };
+};
+
+/* clang-format off */
+#define LANDLOCK_SUPERVISE_DECISION_DENY 0
+#define LANDLOCK_SUPERVISE_DECISION_ALLOW 1
+/* clang-format on */
+
+struct landlock_supervise_response {
+ /**
+ * @length: Size of this structure.
+ */
+ __u16 length;
+ /**
+ * @decision: Whether to allow the request.
+ */
+ __u8 decision;
+ /**
+ * @pad: Reserved, must be zero.
+ */
+ __u8 _reserved;
+ /**
+ * @cookie: Cookie previously received in the request.
+ */
+ __u32 cookie;
+};
+
#endif /* _UAPI_LINUX_LANDLOCK_H */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index adf7e77023b5..f1080e7de0c7 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -91,6 +91,9 @@ static void build_check_abi(void)
struct landlock_path_beneath_attr path_beneath_attr;
struct landlock_net_port_attr net_port_attr;
size_t ruleset_size, path_beneath_size, net_port_size;
+ struct landlock_supervise_event *event;
+ struct landlock_supervise_response response;
+ size_t supervise_evt_size, supervise_response_size;
/*
* For each user space ABI structures, first checks that there is no
@@ -114,6 +117,31 @@ static void build_check_abi(void)
net_port_size += sizeof(net_port_attr.port);
BUILD_BUG_ON(sizeof(net_port_attr) != net_port_size);
BUILD_BUG_ON(sizeof(net_port_attr) != 16);
+
+ /* Check that anything before the destname does not have holes */
+ supervise_evt_size = sizeof(event->hdr.type);
+ supervise_evt_size += sizeof(event->hdr.length);
+ supervise_evt_size += sizeof(event->hdr.cookie);
+ BUILD_BUG_ON(offsetofend(typeof(*event), hdr) != 8);
+ supervise_evt_size += sizeof(event->access_request);
+ supervise_evt_size += sizeof(event->accessor);
+ supervise_evt_size += sizeof(event->fd1);
+ supervise_evt_size += sizeof(event->fd2);
+ BUILD_BUG_ON(offsetof(typeof(*event), destname) != supervise_evt_size);
+ BUILD_BUG_ON(offsetof(typeof(*event), destname) != 28);
+
+ /*
+ * Make sure this struct does not end up with stricter
+ * alignment than 8
+ */
+ BUILD_BUG_ON(__alignof__(typeof(*event)) != 8);
+
+ supervise_response_size = sizeof(response.length);
+ supervise_response_size += sizeof(response.decision);
+ supervise_response_size += sizeof(response._reserved);
+ supervise_response_size += sizeof(response.cookie);
+ BUILD_BUG_ON(sizeof(response) != supervise_response_size);
+ BUILD_BUG_ON(sizeof(response) != 8);
}
/* Ruleset handling */
--
2.39.5
More information about the Linux-security-module-archive
mailing list