diff mbox series

[RFC,v3,02/19] landlock: Add hook on socket creation

Message ID 20240904104824.1844082-3-ivanov.mikhail1@huawei-partners.com
State RFC
Headers show
Series Support socket access-control | expand

Commit Message

Mikhail Ivanov Sept. 4, 2024, 10:48 a.m. UTC
Add hook on security_socket_post_create(), which checks whether the socket
type and address family are allowed by domain. Hook is called after
initializing the socket to let network stack to perform all necessary
internal checks.

Signed-off-by: Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com>
---
Changes since v2:
* Adds check in `hook_socket_create()` to not restrict kernel space
  sockets.
* Inlines `current_check_access_socket()` in the `hook_socket_create()`.
* Fixes commit message.

Changes since v1:
* Uses lsm hook arguments instead of struct socket fields as family-type
  values.
* Packs socket family and type using helper.
* Fixes commit message.
* Formats with clang-format.
---
 security/landlock/setup.c  |  2 ++
 security/landlock/socket.c | 68 ++++++++++++++++++++++++++++++++++++++
 security/landlock/socket.h |  2 ++
 3 files changed, 72 insertions(+)
diff mbox series

Patch

diff --git a/security/landlock/setup.c b/security/landlock/setup.c
index 28519a45b11f..fd4e7e8f3cb2 100644
--- a/security/landlock/setup.c
+++ b/security/landlock/setup.c
@@ -14,6 +14,7 @@ 
 #include "cred.h"
 #include "fs.h"
 #include "net.h"
+#include "socket.h"
 #include "setup.h"
 #include "task.h"
 
@@ -37,6 +38,7 @@  static int __init landlock_init(void)
 	landlock_add_task_hooks();
 	landlock_add_fs_hooks();
 	landlock_add_net_hooks();
+	landlock_add_socket_hooks();
 	landlock_initialized = true;
 	pr_info("Up and running.\n");
 	return 0;
diff --git a/security/landlock/socket.c b/security/landlock/socket.c
index cad89bb91678..60dbcf38540e 100644
--- a/security/landlock/socket.c
+++ b/security/landlock/socket.c
@@ -8,7 +8,9 @@ 
 #include <linux/net.h>
 #include <linux/socket.h>
 #include <linux/stddef.h>
+#include <net/ipv6.h>
 
+#include "cred.h"
 #include "limits.h"
 #include "ruleset.h"
 #include "socket.h"
@@ -67,3 +69,69 @@  int landlock_append_socket_rule(struct landlock_ruleset *const ruleset,
 
 	return err;
 }
+
+static access_mask_t
+get_raw_handled_socket_accesses(const struct landlock_ruleset *const domain)
+{
+	access_mask_t access_dom = 0;
+	size_t layer_level;
+
+	for (layer_level = 0; layer_level < domain->num_layers; layer_level++)
+		access_dom |=
+			landlock_get_socket_access_mask(domain, layer_level);
+	return access_dom;
+}
+
+static const struct landlock_ruleset *get_current_socket_domain(void)
+{
+	const struct landlock_ruleset *const dom =
+		landlock_get_current_domain();
+
+	if (!dom || !get_raw_handled_socket_accesses(dom))
+		return NULL;
+
+	return dom;
+}
+
+static int hook_socket_create(struct socket *const sock, int family, int type,
+			      int protocol, int kern)
+{
+	layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_SOCKET] = {};
+	const struct landlock_rule *rule;
+	access_mask_t handled_access;
+	struct landlock_id id = {
+		.type = LANDLOCK_KEY_SOCKET,
+	};
+	const struct landlock_ruleset *dom;
+
+	/* Checks only user space sockets. */
+	if (kern)
+		return 0;
+
+	dom = get_current_socket_domain();
+	if (!dom)
+		return 0;
+	if (WARN_ON_ONCE(dom->num_layers < 1))
+		return -EACCES;
+
+	id.key.data = pack_socket_key(family, type);
+
+	rule = landlock_find_rule(dom, id);
+	handled_access =
+		landlock_init_layer_masks(dom, LANDLOCK_ACCESS_SOCKET_CREATE,
+					  &layer_masks, LANDLOCK_KEY_SOCKET);
+	if (landlock_unmask_layers(rule, handled_access, &layer_masks,
+				   ARRAY_SIZE(layer_masks)))
+		return 0;
+	return -EACCES;
+}
+
+static struct security_hook_list landlock_hooks[] __ro_after_init = {
+	LSM_HOOK_INIT(socket_post_create, hook_socket_create),
+};
+
+__init void landlock_add_socket_hooks(void)
+{
+	security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
+			   &landlock_lsmid);
+}
diff --git a/security/landlock/socket.h b/security/landlock/socket.h
index 8519357f1c39..5c36eae9732f 100644
--- a/security/landlock/socket.h
+++ b/security/landlock/socket.h
@@ -10,6 +10,8 @@ 
 
 #include "ruleset.h"
 
+__init void landlock_add_socket_hooks(void);
+
 int landlock_append_socket_rule(struct landlock_ruleset *const ruleset,
 				const int family, const int type,
 				access_mask_t access_rights);