@@ -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;
@@ -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);
+}
@@ -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);
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(+)