From patchwork Mon Apr 8 09:39:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620897 Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0B779482C2; Mon, 8 Apr 2024 09:40:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.190 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569211; cv=none; b=BoAo50xC/4MQEi2T9tUxYP19yHnTvo06CXGjP2cPWKaCwOiwHlA7MvSXJDmvoU31ulDzmZQWSVyhms9yGpqNBmpI3PK1B/vLHpOlc6652xnBM28IRFQuoYkkv5zOgBcNDlASgf+JdOWa+k8OEhHLjcVTJ8f7QXJdTB+f59G2xMA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569211; c=relaxed/simple; bh=kcCTq1AVFjWJZMDG2thNPXI906vRF5PYNOxjJx4Zcls=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Se3qKK5SF99tl9dHprO4Yf7N7bXt9NOXldz6ZYvxj4kOBAQngBE5VcHcX4or9bO9zscawwVDD3YBlnKvSKZiE8CzwTYfVeG7dxdnPV/VQaUDibsQbmgXn+sVWx3x7JCRpV9TY0J/JY0k7onHnj5qDZ9+e6nZ2ckli/VyjCARqeA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.190 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.163.44]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4VCkWv691kz29dPS; Mon, 8 Apr 2024 17:37:15 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id F020E1401E9; Mon, 8 Apr 2024 17:40:05 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:03 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 01/10] landlock: Support socket access-control Date: Mon, 8 Apr 2024 17:39:18 +0800 Message-ID: <20240408093927.1759381-2-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add new socket-related rule type, presented via landlock_socket_attr struct. Add all neccessary entities for socket ruleset support. Add flag LANDLOCK_ACCESS_SOCKET_CREATE that will provide the ability to control socket creation. Change landlock_key.data type from uinptr_t to u64. Socket rule has to contain 32-bit socket family and type values, so landlock_key can be represented as 64-bit number the first 32 bits of which correspond to the socket family and last - to the type. Change ABI version to 5. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- include/uapi/linux/landlock.h | 49 +++++++++++++++++ security/landlock/Makefile | 2 +- security/landlock/limits.h | 5 ++ security/landlock/net.c | 2 +- security/landlock/ruleset.c | 35 +++++++++++-- security/landlock/ruleset.h | 44 ++++++++++++++-- security/landlock/socket.c | 43 +++++++++++++++ security/landlock/socket.h | 17 ++++++ security/landlock/syscalls.c | 55 ++++++++++++++++++-- tools/testing/selftests/landlock/base_test.c | 2 +- 10 files changed, 241 insertions(+), 13 deletions(-) create mode 100644 security/landlock/socket.c create mode 100644 security/landlock/socket.h diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index 25c8d7677..8551ade38 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -37,6 +37,13 @@ struct landlock_ruleset_attr { * rule explicitly allow them. */ __u64 handled_access_net; + + /** + * @handled_access_net: Bitmask of actions (cf. `Socket flags`_) + * that is handled by this ruleset and should then be forbidden if no + * rule explicitly allow them. + */ + __u64 handled_access_socket; }; /* @@ -65,6 +72,11 @@ enum landlock_rule_type { * landlock_net_port_attr . */ LANDLOCK_RULE_NET_PORT, + /** + * @LANDLOCK_RULE_SOCKET: Type of a &struct + * landlock_socket_attr . + */ + LANDLOCK_RULE_SOCKET, }; /** @@ -115,6 +127,27 @@ struct landlock_net_port_attr { __u64 port; }; +/** + * struct landlock_socket_attr - Socket definition + * + * Argument of sys_landlock_add_rule(). + */ +struct landlock_socket_attr { + /** + * @allowed_access: Bitmask of allowed access for a socket + * (cf. `Socket flags`_). + */ + __u64 allowed_access; + /** + * @domain: Protocol family used for communication (see socket(2)). + */ + int domain; + /** + * @type: Socket type (see socket(2)). + */ + int type; +}; + /** * DOC: fs_access * @@ -244,4 +277,20 @@ struct landlock_net_port_attr { #define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0) #define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1) /* clang-format on */ + +/** + * DOC: socket_acess + * + * Socket flags + * ~~~~~~~~~~~~~~~~ + * + * These flags enable to restrict a sandboxed process to a set of + * socket-related actions for specific protocols. This is supported + * since the Landlock ABI version 5. + * + * - %LANDLOCK_ACCESS_SOCKET_CREATE: Create a socket + */ +/* clang-format off */ +#define LANDLOCK_ACCESS_SOCKET_CREATE (1ULL << 0) +/* clang-format on */ #endif /* _UAPI_LINUX_LANDLOCK_H */ diff --git a/security/landlock/Makefile b/security/landlock/Makefile index b4538b7cf..ff1dd98f6 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 socket.o landlock-$(CONFIG_INET) += net.o diff --git a/security/landlock/limits.h b/security/landlock/limits.h index 93c9c6f91..ebdab587c 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -28,6 +28,11 @@ #define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET) #define LANDLOCK_SHIFT_ACCESS_NET LANDLOCK_NUM_ACCESS_FS +#define LANDLOCK_LAST_ACCESS_SOCKET LANDLOCK_ACCESS_SOCKET_CREATE +#define LANDLOCK_MASK_ACCESS_SOCKET ((LANDLOCK_LAST_ACCESS_SOCKET << 1) - 1) +#define LANDLOCK_NUM_ACCESS_SOCKET __const_hweight64(LANDLOCK_MASK_ACCESS_SOCKET) +#define LANDLOCK_SHIFT_ACCESS_SOCKET LANDLOCK_NUM_ACCESS_SOCKET + /* clang-format on */ #endif /* _SECURITY_LANDLOCK_LIMITS_H */ diff --git a/security/landlock/net.c b/security/landlock/net.c index c8bcd29bd..0e3770d14 100644 --- a/security/landlock/net.c +++ b/security/landlock/net.c @@ -159,7 +159,7 @@ static int current_check_access_socket(struct socket *const sock, return -EINVAL; } - id.key.data = (__force uintptr_t)port; + id.key.data = (__force u64)port; BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); rule = landlock_find_rule(dom, id); diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c index e0a5fbf92..1f1ed8181 100644 --- a/security/landlock/ruleset.c +++ b/security/landlock/ruleset.c @@ -40,6 +40,7 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers) #if IS_ENABLED(CONFIG_INET) new_ruleset->root_net_port = RB_ROOT; #endif /* IS_ENABLED(CONFIG_INET) */ + new_ruleset->root_socket = RB_ROOT; new_ruleset->num_layers = num_layers; /* @@ -52,12 +53,13 @@ static struct landlock_ruleset *create_ruleset(const u32 num_layers) struct landlock_ruleset * landlock_create_ruleset(const access_mask_t fs_access_mask, - const access_mask_t net_access_mask) + const access_mask_t net_access_mask, + const access_mask_t socket_access_mask) { struct landlock_ruleset *new_ruleset; /* Informs about useless ruleset. */ - if (!fs_access_mask && !net_access_mask) + if (!fs_access_mask && !net_access_mask && !socket_access_mask) return ERR_PTR(-ENOMSG); new_ruleset = create_ruleset(1); if (IS_ERR(new_ruleset)) @@ -66,6 +68,8 @@ landlock_create_ruleset(const access_mask_t fs_access_mask, landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0); if (net_access_mask) landlock_add_net_access_mask(new_ruleset, net_access_mask, 0); + if (socket_access_mask) + landlock_add_socket_access_mask(new_ruleset, socket_access_mask, 0); return new_ruleset; } @@ -89,6 +93,9 @@ static bool is_object_pointer(const enum landlock_key_type key_type) return false; #endif /* IS_ENABLED(CONFIG_INET) */ + case LANDLOCK_KEY_SOCKET: + return false; + default: WARN_ON_ONCE(1); return false; @@ -146,6 +153,9 @@ static struct rb_root *get_root(struct landlock_ruleset *const ruleset, return &ruleset->root_net_port; #endif /* IS_ENABLED(CONFIG_INET) */ + case LANDLOCK_KEY_SOCKET: + return &ruleset->root_socket; + default: WARN_ON_ONCE(1); return ERR_PTR(-EINVAL); @@ -175,7 +185,8 @@ static void build_check_ruleset(void) BUILD_BUG_ON(ruleset.num_layers < LANDLOCK_MAX_NUM_LAYERS); BUILD_BUG_ON(access_masks < ((LANDLOCK_MASK_ACCESS_FS << LANDLOCK_SHIFT_ACCESS_FS) | - (LANDLOCK_MASK_ACCESS_NET << LANDLOCK_SHIFT_ACCESS_NET))); + (LANDLOCK_MASK_ACCESS_NET << LANDLOCK_SHIFT_ACCESS_NET) | + (LANDLOCK_MASK_ACCESS_SOCKET << LANDLOCK_SHIFT_ACCESS_SOCKET))); } /** @@ -399,6 +410,11 @@ static int merge_ruleset(struct landlock_ruleset *const dst, goto out_unlock; #endif /* IS_ENABLED(CONFIG_INET) */ + /* Merges the @src socket tree. */ + err = merge_tree(dst, src, LANDLOCK_KEY_SOCKET); + if (err) + goto out_unlock; + out_unlock: mutex_unlock(&src->lock); mutex_unlock(&dst->lock); @@ -462,6 +478,11 @@ static int inherit_ruleset(struct landlock_ruleset *const parent, goto out_unlock; #endif /* IS_ENABLED(CONFIG_INET) */ + /* Copies the @parent socket tree. */ + err = inherit_tree(parent, child, LANDLOCK_KEY_SOCKET); + if (err) + goto out_unlock; + if (WARN_ON_ONCE(child->num_layers <= parent->num_layers)) { err = -EINVAL; goto out_unlock; @@ -498,6 +519,10 @@ static void free_ruleset(struct landlock_ruleset *const ruleset) free_rule(freeme, LANDLOCK_KEY_NET_PORT); #endif /* IS_ENABLED(CONFIG_INET) */ + rbtree_postorder_for_each_entry_safe(freeme, next, + &ruleset->root_socket, node) + free_rule(freeme, LANDLOCK_KEY_SOCKET); + put_hierarchy(ruleset->hierarchy); kfree(ruleset); } @@ -708,6 +733,10 @@ landlock_init_layer_masks(const struct landlock_ruleset *const domain, break; #endif /* IS_ENABLED(CONFIG_INET) */ + case LANDLOCK_KEY_SOCKET: + get_access_mask = landlock_get_socket_access_mask; + num_access = LANDLOCK_NUM_ACCESS_SOCKET; + break; default: WARN_ON_ONCE(1); return 0; diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h index c7f152678..f4213db09 100644 --- a/security/landlock/ruleset.h +++ b/security/landlock/ruleset.h @@ -72,10 +72,10 @@ union landlock_key { */ struct landlock_object *object; /** - * @data: Raw data to identify an arbitrary 32-bit value + * @data: Raw data to identify an arbitrary 64-bit value * (e.g. a TCP port). */ - uintptr_t data; + u64 data; }; /** @@ -92,6 +92,12 @@ enum landlock_key_type { * node keys. */ LANDLOCK_KEY_NET_PORT, + + /** + * @LANDLOCK_KEY_SOCKET: Type of &landlock_ruleset.root_socket's + * node keys. + */ + LANDLOCK_KEY_SOCKET, }; /** @@ -177,6 +183,15 @@ struct landlock_ruleset { struct rb_root root_net_port; #endif /* IS_ENABLED(CONFIG_INET) */ + /** + * @root_socket: Root of a red-black tree containing &struct + * landlock_rule nodes with socket type, described by (domain, type) + * pair (see socket(2)). Once a ruleset is tied to a + * process (i.e. as a domain), this tree is immutable until @usage + * reaches zero. + */ + struct rb_root root_socket; + /** * @hierarchy: Enables hierarchy identification even when a parent * domain vanishes. This is needed for the ptrace protection. @@ -233,7 +248,8 @@ struct landlock_ruleset { struct landlock_ruleset * landlock_create_ruleset(const access_mask_t access_mask_fs, - const access_mask_t access_mask_net); + const access_mask_t access_mask_net, + const access_mask_t socket_access_mask); void landlock_put_ruleset(struct landlock_ruleset *const ruleset); void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset); @@ -282,6 +298,19 @@ landlock_add_net_access_mask(struct landlock_ruleset *const ruleset, (net_mask << LANDLOCK_SHIFT_ACCESS_NET); } +static inline void +landlock_add_socket_access_mask(struct landlock_ruleset *const ruleset, + const access_mask_t socket_access_mask, + const u16 layer_level) +{ + access_mask_t socket_mask = socket_access_mask & LANDLOCK_MASK_ACCESS_SOCKET; + + /* Should already be checked in sys_landlock_create_ruleset(). */ + WARN_ON_ONCE(socket_access_mask != socket_mask); + ruleset->access_masks[layer_level] |= + (socket_mask << LANDLOCK_SHIFT_ACCESS_SOCKET); +} + static inline access_mask_t landlock_get_raw_fs_access_mask(const struct landlock_ruleset *const ruleset, const u16 layer_level) @@ -309,6 +338,15 @@ landlock_get_net_access_mask(const struct landlock_ruleset *const ruleset, LANDLOCK_MASK_ACCESS_NET; } +static inline access_mask_t +landlock_get_socket_access_mask(const struct landlock_ruleset *const ruleset, + const u16 layer_level) +{ + return (ruleset->access_masks[layer_level] >> + LANDLOCK_SHIFT_ACCESS_SOCKET) & + LANDLOCK_MASK_ACCESS_SOCKET; +} + bool landlock_unmask_layers(const struct landlock_rule *const rule, const access_mask_t access_request, layer_mask_t (*const layer_masks)[], diff --git a/security/landlock/socket.c b/security/landlock/socket.c new file mode 100644 index 000000000..88b4ef3a1 --- /dev/null +++ b/security/landlock/socket.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Landlock LSM - Socket management and hooks + * + * Copyright © 2024 Huawei Tech. Co., Ltd. + */ + +#include "limits.h" +#include "ruleset.h" +#include "socket.h" + +union socket_key { + struct { + int domain; + int type; + } __packed content; + u64 val; +}; + +int landlock_append_socket_rule(struct landlock_ruleset *const ruleset, + const int domain, const int type, access_mask_t access_rights) +{ + int err; + const union socket_key socket_key = { + .content.domain = domain, + .content.type = type + }; + + const struct landlock_id id = { + .key.data = socket_key.val, + .type = LANDLOCK_KEY_SOCKET, + }; + + /* Transforms relative access rights to absolute ones. */ + access_rights |= LANDLOCK_MASK_ACCESS_SOCKET & + ~landlock_get_socket_access_mask(ruleset, 0); + + mutex_lock(&ruleset->lock); + err = landlock_insert_rule(ruleset, id, access_rights); + mutex_unlock(&ruleset->lock); + + return err; +} diff --git a/security/landlock/socket.h b/security/landlock/socket.h new file mode 100644 index 000000000..2b8f9ae7d --- /dev/null +++ b/security/landlock/socket.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Landlock LSM - Socket management and hooks + * + * Copyright © 2024 Huawei Tech. Co., Ltd. + */ + +#ifndef _SECURITY_LANDLOCK_SOCKET_H +#define _SECURITY_LANDLOCK_SOCKET_H + +#include "ruleset.h" + +int landlock_append_socket_rule(struct landlock_ruleset *const ruleset, + const int domain, const int type, + access_mask_t access_rights); + +#endif /* _SECURITY_LANDLOCK_SOCKET_H */ diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index 6788e73b6..66c9800c2 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -30,6 +30,7 @@ #include "fs.h" #include "limits.h" #include "net.h" +#include "socket.h" #include "ruleset.h" #include "setup.h" @@ -88,7 +89,8 @@ static void build_check_abi(void) struct landlock_ruleset_attr ruleset_attr; 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_socket_attr socket_attr; + size_t ruleset_size, path_beneath_size, net_port_size, socket_size; /* * For each user space ABI structures, first checks that there is no @@ -97,8 +99,9 @@ static void build_check_abi(void) */ ruleset_size = sizeof(ruleset_attr.handled_access_fs); ruleset_size += sizeof(ruleset_attr.handled_access_net); + ruleset_size += sizeof(ruleset_attr.handled_access_socket); BUILD_BUG_ON(sizeof(ruleset_attr) != ruleset_size); - BUILD_BUG_ON(sizeof(ruleset_attr) != 16); + BUILD_BUG_ON(sizeof(ruleset_attr) != 24); path_beneath_size = sizeof(path_beneath_attr.allowed_access); path_beneath_size += sizeof(path_beneath_attr.parent_fd); @@ -109,6 +112,12 @@ 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); + + socket_size = sizeof(socket_attr.allowed_access); + socket_size += sizeof(socket_attr.domain); + socket_size += sizeof(socket_attr.type); + BUILD_BUG_ON(sizeof(socket_attr) != socket_size); + BUILD_BUG_ON(sizeof(socket_attr) != 16); } /* Ruleset handling */ @@ -149,7 +158,7 @@ static const struct file_operations ruleset_fops = { .write = fop_dummy_write, }; -#define LANDLOCK_ABI_VERSION 4 +#define LANDLOCK_ABI_VERSION 5 /** * sys_landlock_create_ruleset - Create a new ruleset @@ -213,9 +222,15 @@ SYSCALL_DEFINE3(landlock_create_ruleset, LANDLOCK_MASK_ACCESS_NET) return -EINVAL; + /* Checks socket content (and 32-bits cast). */ + if ((ruleset_attr.handled_access_socket | LANDLOCK_MASK_ACCESS_SOCKET) != + LANDLOCK_MASK_ACCESS_SOCKET) + return -EINVAL; + /* Checks arguments and transforms to kernel struct. */ ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs, - ruleset_attr.handled_access_net); + ruleset_attr.handled_access_net, + ruleset_attr.handled_access_socket); if (IS_ERR(ruleset)) return PTR_ERR(ruleset); @@ -371,6 +386,35 @@ static int add_rule_net_port(struct landlock_ruleset *ruleset, net_port_attr.allowed_access); } +static int add_rule_socket(struct landlock_ruleset *ruleset, + const void __user *const rule_attr) +{ + struct landlock_socket_attr socket_attr; + int res; + access_mask_t mask; + + /* Copies raw user space buffer. */ + res = copy_from_user(&socket_attr, rule_attr, sizeof(socket_attr)); + if (res) + return -EFAULT; + + /* + * Informs about useless rule: empty allowed_access (i.e. deny rules) + * are ignored by network actions. + */ + if (!socket_attr.allowed_access) + return -ENOMSG; + + /* Checks that allowed_access matches the @ruleset constraints. */ + mask = landlock_get_socket_access_mask(ruleset, 0); + if ((socket_attr.allowed_access | mask) != mask) + return -EINVAL; + + /* Imports the new rule. */ + return landlock_append_socket_rule(ruleset, socket_attr.domain, + socket_attr.type, socket_attr.allowed_access); +} + /** * sys_landlock_add_rule - Add a new rule to a ruleset * @@ -429,6 +473,9 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd, case LANDLOCK_RULE_NET_PORT: err = add_rule_net_port(ruleset, rule_attr); break; + case LANDLOCK_RULE_SOCKET: + err = add_rule_socket(ruleset, rule_attr); + break; default: err = -EINVAL; break; diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c index 646f778df..d292b419c 100644 --- a/tools/testing/selftests/landlock/base_test.c +++ b/tools/testing/selftests/landlock/base_test.c @@ -75,7 +75,7 @@ TEST(abi_version) const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, }; - ASSERT_EQ(4, landlock_create_ruleset(NULL, 0, + ASSERT_EQ(5, landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION)); ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, From patchwork Mon Apr 8 09:39:19 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620898 Received: from szxga06-in.huawei.com (szxga06-in.huawei.com [45.249.212.32]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 77FE1495CB; Mon, 8 Apr 2024 09:40:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.32 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569213; cv=none; b=hqxKKLSkl9B5db9Y66YTIa5X1LDCB3kePNXJH5fWbNlIRPFXrRZ2lNtbqfwKKwefqoZquFDuM59Afxwfkm6Cvnjdmm6JtFmV5mXOxwAH/K35nBe7LbRHXIXu7qJNC7+wajL9KjNSjl6B41nQqaK+igB6q69VtWAHZXEYozEQFlw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569213; c=relaxed/simple; bh=q/+Fvly02sF3SZAhyGWyIMgwnxDakSyLqu51kle4Hvg=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Vq+akBrdxIHEcZaUPd6qXi15X4OAUfhLZsxRnBQFBc22ZSH/mcgKDh2xFyQmwyxb7k0yZ2b34bHhgDLC2yflB8IMvgKnE9npU0UigXrmY65NKg7f7aqvHK9WqIwIFkx3bdxLRCMT5cfEfoTMvxo0FkdUCeVp274NerSAB30zlk0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.32 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.163.44]) by szxga06-in.huawei.com (SkyGuard) with ESMTP id 4VCkZ94d1Rz21kf8; Mon, 8 Apr 2024 17:39:13 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 344C61401E9; Mon, 8 Apr 2024 17:40:08 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:06 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 02/10] landlock: Add hook on socket_create() Date: Mon, 8 Apr 2024 17:39:19 +0800 Message-ID: <20240408093927.1759381-3-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add hook on socket_create() method. Since it'll be better to have control over possible socket changes after family-related create() call, hook is called on socket_post_create(). Handler only checks if the socket type and family are allowed by domain. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- security/landlock/setup.c | 2 ++ security/landlock/socket.c | 72 ++++++++++++++++++++++++++++++++++++++ security/landlock/socket.h | 2 ++ 3 files changed, 76 insertions(+) diff --git a/security/landlock/setup.c b/security/landlock/setup.c index 28519a45b..fd4e7e8f3 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 88b4ef3a1..cba584543 100644 --- a/security/landlock/socket.c +++ b/security/landlock/socket.c @@ -5,6 +5,10 @@ * Copyright © 2024 Huawei Tech. Co., Ltd. */ +#include +#include + +#include "cred.h" #include "limits.h" #include "ruleset.h" #include "socket.h" @@ -41,3 +45,71 @@ 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 current_check_access_socket(struct socket *const sock, + const access_mask_t access_request) +{ + union socket_key socket_key; + 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 *const dom = get_current_socket_domain(); + + if (!dom) + return 0; + if (WARN_ON_ONCE(dom->num_layers < 1)) + return -EACCES; + + socket_key.content.type = sock->type; + socket_key.content.domain = sock->sk->__sk_common.skc_family; + id.key.data = socket_key.val; + + rule = landlock_find_rule(dom, id); + handled_access = landlock_init_layer_masks( + dom, access_request, &layer_masks, LANDLOCK_KEY_SOCKET); + if (landlock_unmask_layers(rule, handled_access, &layer_masks, + ARRAY_SIZE(layer_masks))) + return 0; + return -EACCES; +} + +static int hook_socket_create(struct socket *const sock, + int family, int type, int protocol, int kern) +{ + return current_check_access_socket(sock, LANDLOCK_ACCESS_SOCKET_CREATE); +} + +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 2b8f9ae7d..152f4d427 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 domain, const int type, access_mask_t access_rights); From patchwork Mon Apr 8 09:39:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620899 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 55A194C634; Mon, 8 Apr 2024 09:40:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569215; cv=none; b=Pefzc0YDAOMoWlPLZ6/04TaFu5uKtlWaebgwbPEigYkAjtcRP/0TphIauT6+6qV8hKgYmX5SzenP+LdKB0gyNVZmD+sMoQ1DpmOcXyDRODoKAn1+DQHT06lMnt0Cgl4IoUkTJ4uQWuJF315wwWNWG8iOetKhAh+vtjJRjSm5/Po= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569215; c=relaxed/simple; bh=n2+4BF++X1ceQbrRCeBct5e2pXVkZ36iXd8vV/rip7s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iD5psf48Q/sNiWnUuRFfClY+NUtTif/aT53uUPAJwMLaRc8qJ2SvCdD6XeCBJhst7hiRwqDAe9N36s9iVCPzPB6ej/13ylMfKmMW2Jp9bIGscqqXzj5xBQUFsc8J+Q5X0vTBE7GOobh6wl0K4okFj4b7C7WfhEqosFKhALikxLs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.162.254]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4VCkX933h8ztRvC; Mon, 8 Apr 2024 17:37:29 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 35F8418001C; Mon, 8 Apr 2024 17:40:10 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:08 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 03/10] selftests/landlock: Create 'create' test Date: Mon, 8 Apr 2024 17:39:20 +0800 Message-ID: <20240408093927.1759381-4-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Initiate socket_test.c selftests. Add protocol fixture for tests with changeable domain/type values. Only most common variants of protocols (like ipv4-tcp,ipv6-udp, unix) were added. Add simple socket access right checking test. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- .../testing/selftests/landlock/socket_test.c | 197 ++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 tools/testing/selftests/landlock/socket_test.c diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c new file mode 100644 index 000000000..525f4f7df --- /dev/null +++ b/tools/testing/selftests/landlock/socket_test.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Landlock tests - Socket + * + * Copyright © 2024 Huawei Tech. Co., Ltd. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* clang-format off */ + +#define ACCESS_LAST LANDLOCK_ACCESS_SOCKET_CREATE + +#define ACCESS_ALL ( \ + LANDLOCK_ACCESS_SOCKET_CREATE) + +/* clang-format on */ + +struct protocol_variant { + int domain; + int type; +}; + +struct service_fixture { + struct protocol_variant protocol; +}; + +static void setup_namespace(struct __test_metadata *const _metadata) +{ + set_cap(_metadata, CAP_SYS_ADMIN); + ASSERT_EQ(0, unshare(CLONE_NEWNET)); + clear_cap(_metadata, CAP_SYS_ADMIN); +} + +static int socket_variant(const struct service_fixture *const srv) +{ + int ret; + + ret = socket(srv->protocol.domain, srv->protocol.type | SOCK_CLOEXEC, + 0); + if (ret < 0) + return -errno; + return ret; +} + +FIXTURE(protocol) +{ + struct service_fixture srv0; +}; + +FIXTURE_VARIANT(protocol) +{ + const struct protocol_variant protocol; +}; + +FIXTURE_SETUP(protocol) +{ + disable_caps(_metadata); + self->srv0.protocol = variant->protocol; + setup_namespace(_metadata); +}; + +FIXTURE_TEARDOWN(protocol) +{ +} + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, unspec) { + /* clang-format on */ + .protocol = { + .domain = AF_UNSPEC, + .type = SOCK_STREAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, unix_stream) { + /* clang-format on */ + .protocol = { + .domain = AF_UNIX, + .type = SOCK_STREAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, unix_dgram) { + /* clang-format on */ + .protocol = { + .domain = AF_UNIX, + .type = SOCK_DGRAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv4_tcp) { + /* clang-format on */ + .protocol = { + .domain = AF_INET, + .type = SOCK_STREAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv4_udp) { + /* clang-format on */ + .protocol = { + .domain = AF_INET, + .type = SOCK_DGRAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv6_tcp) { + /* clang-format on */ + .protocol = { + .domain = AF_INET6, + .type = SOCK_STREAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv6_udp) { + /* clang-format on */ + .protocol = { + .domain = AF_INET6, + .type = SOCK_DGRAM, + }, +}; + +static void test_socket_create(struct __test_metadata *const _metadata, + const struct service_fixture *const srv, + const bool deny_create) +{ + int fd; + + fd = socket_variant(srv); + if (srv->protocol.domain == AF_UNSPEC) { + EXPECT_EQ(fd, -EAFNOSUPPORT); + } else if (deny_create) { + EXPECT_EQ(fd, -EACCES); + } else { + EXPECT_LE(0, fd) + { + TH_LOG("Failed to create socket: %s", strerror(errno)); + } + EXPECT_EQ(0, close(fd)); + } +} + +TEST_F(protocol, create) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE, + }; + const struct landlock_socket_attr create_socket_attr = { + .allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE, + .domain = self->srv0.protocol.domain, + .type = self->srv0.protocol.type, + }; + + int ruleset_fd; + + /* Allowed create */ + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &create_socket_attr, 0)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + test_socket_create(_metadata, &self->srv0, false); + + /* Denied create */ + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + test_socket_create(_metadata, &self->srv0, true); +} + +TEST_HARNESS_MAIN From patchwork Mon Apr 8 09:39:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620900 Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 28656495CB; Mon, 8 Apr 2024 09:40:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.190 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569216; cv=none; b=jo7CEP3ai5FNGHin8XztOSlVkTeMJ2BtReRHn2gO5hYopspsORGmY9JnC1Cn57smN6BdONQ+WhE5WQEJ1iCTPsEF8jh6EMFOL85b8RR/ws8KUWa0Mxi98gQHlnkNRsUuClrJ263XuNTgQX4ToL2IjVsJ20n5/wmougvxZtmiOFs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569216; c=relaxed/simple; bh=YHPh52Z03W1pKn7SJKKJSBKFh12yRe6HRgBf4lWwxK4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JqOe6zxolCM4YCapsj+FOPiyTf/OW76s9KlMGtKnYc1X7vMcB8l3ypARGYGKgwaVTWjGXSugDGsscHzDPnvxynyuhUYOr808qI5/vK2m18eb4kPGvkcl9OL6DT72Hz+WcvYDvddeGrUYCkpaP5B46Ac2BVwXfTizeOHt78SAMic= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.190 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.88.163]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4VCkX20rKBz29dPS; Mon, 8 Apr 2024 17:37:22 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 3BCE518005F; Mon, 8 Apr 2024 17:40:12 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:10 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 04/10] selftests/landlock: Create 'socket_access_rights' test Date: Mon, 8 Apr 2024 17:39:21 +0800 Message-ID: <20240408093927.1759381-5-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add test that checks possibility of adding rule with every possible access right. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- .../testing/selftests/landlock/socket_test.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index 525f4f7df..7f31594bf 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -194,4 +194,33 @@ TEST_F(protocol, create) test_socket_create(_metadata, &self->srv0, true); } +TEST_F(protocol, socket_access_rights) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = ACCESS_ALL, + }; + struct landlock_socket_attr protocol = { + .domain = self->srv0.protocol.domain, + .type = self->srv0.protocol.type, + }; + int ruleset_fd; + __u64 access; + + ruleset_fd = + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + for (access = 1; access <= ACCESS_LAST; access <<= 1) { + protocol.allowed_access = access; + EXPECT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &protocol, 0)) + { + TH_LOG("Failed to add rule with access 0x%llx: %s", + access, strerror(errno)); + } + } + EXPECT_EQ(0, close(ruleset_fd)); +} + TEST_HARNESS_MAIN From patchwork Mon Apr 8 09:39:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620902 Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 969A24645B; Mon, 8 Apr 2024 09:40:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.191 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569223; cv=none; b=DH0znytqg8dHuCsb0gBWlHuXdI3ihIF/j07zaSI1jH1v295kWl/occpETZxAlCHaEUYnpGRTPDBBhAM8wOkaP7lUvS4D6HZOqw7hmiPTWplVSxFisae9ZOWk5558a1OPBl1txMdbgQaiU/Qkokldv/oe/5Fxb+RVXi/Mnpp09R0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569223; c=relaxed/simple; bh=drN9bL8JdjKHCjq13VMq/OXZxDd2Gc+wVCkJQC4rqf8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=VPSZGJEn916cTwHZClGtekzvto5bAHc9aYXPcwALh7kjNC9QxHFTcWUvQ5uCkp9jlh2Q6YWUVVDL9tw6xow2BiddEAf0Vses900r8RIUAj7ZHZrOMjSizpbEvsMdlKeZ0t6HzNiZtyfCAg2309e1wPQNO7DBL4VGhb3WZgKljgQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.191 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.163.17]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4VCkZV30KYz1GGKc; Mon, 8 Apr 2024 17:39:30 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 495E51A0172; Mon, 8 Apr 2024 17:40:14 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:12 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 05/10] selftests/landlock: Create 'rule_with_unknown_access' test Date: Mon, 8 Apr 2024 17:39:22 +0800 Message-ID: <20240408093927.1759381-6-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add test that validates behavior of landlock after rule with unknown access is added. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- .../testing/selftests/landlock/socket_test.c | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index 7f31594bf..5577b08d5 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -223,4 +223,30 @@ TEST_F(protocol, socket_access_rights) EXPECT_EQ(0, close(ruleset_fd)); } +TEST_F(protocol, rule_with_unknown_access) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = ACCESS_ALL, + }; + struct landlock_socket_attr protocol = { + .domain = self->srv0.protocol.domain, + .type = self->srv0.protocol.type, + }; + int ruleset_fd; + __u64 access; + + ruleset_fd = + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + for (access = 1ULL << 63; access != ACCESS_LAST; access >>= 1) { + protocol.allowed_access = access; + EXPECT_EQ(-1, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &protocol, 0)); + EXPECT_EQ(EINVAL, errno); + } + EXPECT_EQ(0, close(ruleset_fd)); +} + TEST_HARNESS_MAIN From patchwork Mon Apr 8 09:39:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620901 Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 19C814D59B; Mon, 8 Apr 2024 09:40:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.190 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569219; cv=none; b=ttOvxAauvB+Hkep0NM3EXKXVtlBuiE0TO3WUsBMOmtL9MYDoLJmyOp1E4UokMWHzMtRpIWuyzzzrTCtTmk+VVhRFRzCBnrRhOyVfZFoKLSB8rJe6xM+Mowp4NQFpMwguw1aTIm9QgaQSXKyP/pRsMLfHPbXfSbC8DeFZHWhEI1s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569219; c=relaxed/simple; bh=8SeWdBwFx4/0oEQ+jBIUZiY0+zJ2LpipA1kIPPkJMKY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JkDt2zICASc40hzMoVzw+fRtL8QHLrLY09RSHRAJzlG2NHhi6YvO6X2SsRkj/ULToButaJe9Ogq1Js3GF6NejohkA+K+y22jOlZF8piuxI6bLUYa+3MfStrsRTRb060el4iO1S4hwIJEg/H2hXuOCMSKWXbYxRm/HS5OXe7Wceo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.190 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.163.44]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4VCkXp6FNvz1ymHY; Mon, 8 Apr 2024 17:38:02 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 572C01401E9; Mon, 8 Apr 2024 17:40:16 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:14 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 06/10] selftests/landlock: Create 'rule_with_unhandled_access' test Date: Mon, 8 Apr 2024 17:39:23 +0800 Message-ID: <20240408093927.1759381-7-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add test that validates behavior of landlock after rule with unhandled access is added. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- .../testing/selftests/landlock/socket_test.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index 5577b08d5..c1c2b5d30 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -249,4 +249,37 @@ TEST_F(protocol, rule_with_unknown_access) EXPECT_EQ(0, close(ruleset_fd)); } +TEST_F(protocol, rule_with_unhandled_access) +{ + struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE, + }; + struct landlock_socket_attr protocol = { + .domain = self->srv0.protocol.domain, + .type = self->srv0.protocol.type, + }; + int ruleset_fd; + __u64 access; + + ruleset_fd = + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + for (access = 1; access > 0; access <<= 1) { + int err; + + protocol.allowed_access = access; + err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &protocol, 0); + if (access == ruleset_attr.handled_access_socket) { + EXPECT_EQ(0, err); + } else { + EXPECT_EQ(-1, err); + EXPECT_EQ(EINVAL, errno); + } + } + + EXPECT_EQ(0, close(ruleset_fd)); +} + TEST_HARNESS_MAIN From patchwork Mon Apr 8 09:39:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620904 Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8B62E5026E; Mon, 8 Apr 2024 09:40:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.191 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569227; cv=none; b=U2odmeXtLy5xMEkUs9fNBdigX20tlzip+SDKWZd/hCl9DQ+MCXlmSnN0Nav/e8bCFUEpwwivWqbQySwUOO3DLwQEtW8UJd+eo2TTqCNXlmSp7nTo9q28ZUZLdf8gUHgh6U4NaYZRnkf15M4C8bwLI4Y8aIRSk/6+5vyACi2x0Ns= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569227; c=relaxed/simple; bh=mKZkpuliNtqp3tlVBfZvyfHJ/YMtjtq+d2jWOezvQBQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=eSWQpiycgvnvIaIecn6YK8yN7V1jPUn4eOIqh5j4sHLSH06y4xSnbEqXmOHm9i7HbaPbEoc8DmUSbB+Ba2F49yhCXR8zSMy0F0NJNIVFzilsYRGw7+5YP9r/8ERx1GdGZBhc3Lt+ALhKZWGUvuawNJJPQ8llH4l/2EzVbj4i3b8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.191 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.163.17]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4VCkX83KxRz1h64b; Mon, 8 Apr 2024 17:37:28 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 6168D1A0172; Mon, 8 Apr 2024 17:40:18 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:16 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 07/10] selftests/landlock: Create 'inval' test Date: Mon, 8 Apr 2024 17:39:24 +0800 Message-ID: <20240408093927.1759381-8-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add test that validates behavior of landlock with fully access restriction. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- .../testing/selftests/landlock/socket_test.c | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index c1c2b5d30..dd105489d 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -282,4 +282,38 @@ TEST_F(protocol, rule_with_unhandled_access) EXPECT_EQ(0, close(ruleset_fd)); } +TEST_F(protocol, inval) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE + }; + + struct landlock_socket_attr protocol = { + .allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE, + .domain = self->srv0.protocol.domain, + .type = self->srv0.protocol.type, + }; + + struct landlock_socket_attr protocol_denied = { + .allowed_access = 0, + .domain = self->srv0.protocol.domain, + .type = self->srv0.protocol.type, + }; + + int ruleset_fd; + + ruleset_fd = + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Checks zero access value. */ + EXPECT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &protocol_denied, 0)); + EXPECT_EQ(ENOMSG, errno); + + /* Adds with legitimate values. */ + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &protocol, 0)); +} + TEST_HARNESS_MAIN From patchwork Mon Apr 8 09:39:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620903 Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9E5A2482E9; Mon, 8 Apr 2024 09:40:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.191 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569224; cv=none; b=HhW7ivmj6gnWKdt+sis8c/KQ5waQc99/MKINceZQWfLQbRRP8EzZJheyCYWAWC4i1w3DjhKdYeUpgq4diGrzDM6+xT4b204C0AqACdZNqSswZyJLJpmfZhECJBgma/0MImU/ss6pkQOz7HVvqoTYqswYs9K7OL3Fx5As9kYHwio= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569224; c=relaxed/simple; bh=JrikPBy7AnB+J5XvO4rxiRuxdBWn74dh3dvl28232M4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DPeaHKpmXZJZY/epWyFCVjrVeGvI9TcQ/GBibsNdOuXj+3Cc+qD5UJnAIhMnN2YZbW0xWcpnFfkdyQeTKyTVG+f8kRcEG2EjeF1SxCcOcUIZb0coSSYaUq3nuszzwgJvBle7keg+YvX6MupmzcnVuIKzrlpKWJILPj3LkUG4i5o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.191 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.88.163]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4VCkXB4dzXz1h64n; Mon, 8 Apr 2024 17:37:30 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 8D62F18005F; Mon, 8 Apr 2024 17:40:20 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:18 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 08/10] selftests/landlock: Create 'ruleset_overlap' test Date: Mon, 8 Apr 2024 17:39:25 +0800 Message-ID: <20240408093927.1759381-9-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add tcp_layers fixture for tests that check multiple layer configuration scenarios. Add test that validates multiple layer behavior with overlapped restrictions. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- .../testing/selftests/landlock/socket_test.c | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index dd105489d..07f73618d 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -316,4 +316,111 @@ TEST_F(protocol, inval) &protocol, 0)); } +FIXTURE(tcp_layers) +{ + struct service_fixture srv0; +}; + +FIXTURE_VARIANT(tcp_layers) +{ + const size_t num_layers; +}; + +FIXTURE_SETUP(tcp_layers) +{ + const struct protocol_variant prot = { + .domain = AF_INET, + .type = SOCK_STREAM, + }; + + disable_caps(_metadata); + self->srv0.protocol = prot; + setup_namespace(_metadata); +}; + +FIXTURE_TEARDOWN(tcp_layers) +{ +} + +/* clang-format off */ +FIXTURE_VARIANT_ADD(tcp_layers, no_sandbox_with_ipv4) { + /* clang-format on */ + .num_layers = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(tcp_layers, one_sandbox_with_ipv4) { + /* clang-format on */ + .num_layers = 1, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(tcp_layers, two_sandboxes_with_ipv4) { + /* clang-format on */ + .num_layers = 2, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(tcp_layers, three_sandboxes_with_ipv4) { + /* clang-format on */ + .num_layers = 3, +}; + +TEST_F(tcp_layers, ruleset_overlap) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE, + }; + const struct landlock_socket_attr tcp_create = { + .allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE, + .domain = self->srv0.protocol.domain, + .type = self->srv0.protocol.type, + }; + + if (variant->num_layers >= 1) { + int ruleset_fd; + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Allows create. */ + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &tcp_create, 0)); + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + + if (variant->num_layers >= 2) { + int ruleset_fd; + + /* Creates another ruleset layer with denied create. */ + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + + if (variant->num_layers >= 3) { + int ruleset_fd; + + /* Creates another ruleset layer. */ + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Try to allow create second time. */ + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &tcp_create, 0)); + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + + test_socket_create(_metadata, &self->srv0, variant->num_layers >= 2); +} + TEST_HARNESS_MAIN From patchwork Mon Apr 8 09:39:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620906 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7507A4AEC4; Mon, 8 Apr 2024 09:40:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.188 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569233; cv=none; b=j74CUmy6qP3pagWp5vqK1WEyI6FzSkcFSF7QresQCroK8WbLR5Iq5H+XjjKQ072032eYferD7/niT0NxrQSAqFF1hdjvNiyLO0tlUMe4gjXzqd7cSjEuClC4waqqBEbfOf6gIxtn2SNHmPG5fBewtgt4aZE2NHy/8OV4a8CRHxI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569233; c=relaxed/simple; bh=jwu0EAwlmhLGvck+G5CvcpDLqvTG2JxNNqABG8lI7Jc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=cpLT0yu2DZ75yoW/Vnji+fSQr94Y2sBPzZE4ExK444vmad271MN58ySRWjix8nSyFtn0Re+FNvJMJ0IQ6SjJiydYlpJ9Za+5vNRcJaV1d9gJvept55KShx/glsk97dfnOBoAcySpPDiZJbV94/wCc3/jNuukzethx+IBgJYchos= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.188 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.88.194]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4VCkWx3HX7zXl35; Mon, 8 Apr 2024 17:37:17 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 9A1EB140415; Mon, 8 Apr 2024 17:40:22 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:20 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 09/10] selftests/landlock: Create 'ruleset_with_unknown_access' test Date: Mon, 8 Apr 2024 17:39:26 +0800 Message-ID: <20240408093927.1759381-10-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add fixture mini for tests that check specific cases. Add test that validates behavior of landlock after ruleset with unknown access is created. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- .../testing/selftests/landlock/socket_test.c | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index 07f73618d..afc57556d 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -423,4 +423,35 @@ TEST_F(tcp_layers, ruleset_overlap) test_socket_create(_metadata, &self->srv0, variant->num_layers >= 2); } +/* clang-format off */ +FIXTURE(mini) {}; +/* clang-format on */ + +FIXTURE_SETUP(mini) +{ + disable_caps(_metadata); + + setup_namespace(_metadata); +}; + +FIXTURE_TEARDOWN(mini) +{ +} + +TEST_F(mini, ruleset_with_unknown_access) +{ + __u64 access_mask; + + for (access_mask = 1ULL << 63; access_mask != ACCESS_LAST; + access_mask >>= 1) { + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = access_mask, + }; + + EXPECT_EQ(-1, landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0)); + EXPECT_EQ(EINVAL, errno); + } +} + TEST_HARNESS_MAIN From patchwork Mon Apr 8 09:39:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13620905 Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51DEB5027B; Mon, 8 Apr 2024 09:40:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569229; cv=none; b=FqE/an16NqeYH8fItQKulxnc6xyWb1oU+pxW/cEz7LNaCvKKApyq6GXBSQODU3aYlPwryA6vLf5VErZSTqM3kmXDkykdXEvSWSyoWRRJnRZgLoCLn15RzTWbuj36dgFI8dPGxJWDAIlFqF6OYj5Cf0f+Q5NjF9q0Mdg1LsVsVpM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1712569229; c=relaxed/simple; bh=NY+y50EeFT3zDJgNa//Ls2FXBG/qKme14tasGwEfcRo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=dma+0R1IpX+yKawIoNgF0n8fNK3KMVuKwM2lPxzINcOMWe53PKGQ3r9ayI0A6RBsCCtEomyoZZcrAziDZtBDXV/rF8FJo9WP8lpSkdkxUjvVYz1Dk4ogDE1Lw++zDBfshT7nnUkYZLvXrSrM4CQrlH9NkJKw0UwLpSu6ekzusbA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com; spf=pass smtp.mailfrom=huawei-partners.com; arc=none smtp.client-ip=45.249.212.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei-partners.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei-partners.com Received: from mail.maildlp.com (unknown [172.19.163.252]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4VCkXC4RNWzwRZc; Mon, 8 Apr 2024 17:37:31 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id DA2B818007D; Mon, 8 Apr 2024 17:40:24 +0800 (CST) Received: from mscphis02103.huawei.com (10.123.65.215) by dggpemm500020.china.huawei.com (7.185.36.49) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.35; Mon, 8 Apr 2024 17:40:22 +0800 From: Ivanov Mikhail To: CC: , , , , , , , Subject: [RFC PATCH v1 10/10] samples/landlock: Support socket protocol restrictions Date: Mon, 8 Apr 2024 17:39:27 +0800 Message-ID: <20240408093927.1759381-11-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> References: <20240408093927.1759381-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: linux-security-module@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100003.china.huawei.com (10.199.174.67) To dggpemm500020.china.huawei.com (7.185.36.49) Add socket protocol control support in sandboxer demo. It's possible to allow a sandboxer to create sockets with specified family(domain) and type values. This is controlled with the new LL_SOCKET_CREATE environment variable. Single token in this variable looks like this: 'FAMILY.TYPE', where FAMILY corresponds to one of the possible socket family name and TYPE to the possible socket type name (see socket(2)). Add ENV_TOKEN_INTERNAL_DELIMITER. Add get_socket_protocol() method to parse socket family and type strings to the appropriate constants. Add CHECK_DOMAIN() and CHECK_TYPE() macroses to prevent copypaste. Signed-off-by: Ivanov Mikhail Reviewed-by: Konstantin Meskhidze --- samples/landlock/sandboxer.c | 149 ++++++++++++++++++++++++++++++++--- 1 file changed, 136 insertions(+), 13 deletions(-) diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c index 32e930c85..4642a7437 100644 --- a/samples/landlock/sandboxer.c +++ b/samples/landlock/sandboxer.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -55,8 +56,11 @@ static inline int landlock_restrict_self(const int ruleset_fd, #define ENV_FS_RW_NAME "LL_FS_RW" #define ENV_TCP_BIND_NAME "LL_TCP_BIND" #define ENV_TCP_CONNECT_NAME "LL_TCP_CONNECT" +#define ENV_SOCKET_CREATE_NAME "LL_SOCKET_CREATE" #define ENV_DELIMITER ":" +#define ENV_TOKEN_INTERNAL_DELIMITER "." + static int parse_path(char *env_path, const char ***const path_list) { int i, num_paths = 0; @@ -85,6 +89,49 @@ static int parse_path(char *env_path, const char ***const path_list) /* clang-format on */ +#define CHECK_DOMAIN(domain_variant) \ + do { \ + if (strcmp(strdomain, #domain_variant) == 0) { \ + protocol->domain = domain_variant; \ + domain_parsed = 1; \ + goto domain_check; \ + } \ + } while (0) + +#define CHECK_TYPE(type_variant) \ + do { \ + if (strcmp(strtype, #type_variant) == 0) { \ + protocol->type = type_variant; \ + type_parsed = 1; \ + goto type_check; \ + } \ + } while (0) + +static int get_socket_protocol(char *strdomain, char *strtype, + struct landlock_socket_attr *protocol) +{ + int domain_parsed = 0, type_parsed = 0; + + CHECK_DOMAIN(AF_UNIX); + CHECK_DOMAIN(AF_INET); + CHECK_DOMAIN(AF_INET6); + +domain_check: + if (!domain_parsed) + return 1; + + CHECK_TYPE(SOCK_STREAM); + CHECK_TYPE(SOCK_DGRAM); + +type_check: + if (!type_parsed) + return 1; + return 0; +} + +#undef CHECK_DOMAIN +#undef CHECK_TYPE + static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd, const __u64 allowed_access) { @@ -182,6 +229,58 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd, return ret; } +static int populate_ruleset_socket(const char *const env_var, + const int ruleset_fd, const __u64 allowed_access) +{ + int ret = 1; + char *env_protocol_name, *env_protocol_name_next; + char *strprotocol, *strdomain, *strtype; + struct landlock_socket_attr protocol = { + .allowed_access = allowed_access, + .domain = 0, + .type = 0, + }; + + env_protocol_name = getenv(env_var); + if (!env_protocol_name) + return 0; + env_protocol_name = strdup(env_protocol_name); + unsetenv(env_var); + + env_protocol_name_next = env_protocol_name; + while ((strprotocol = strsep(&env_protocol_name_next, ENV_DELIMITER))) { + strdomain = strsep(&strprotocol, ENV_TOKEN_INTERNAL_DELIMITER); + strtype = strsep(&strprotocol, ENV_TOKEN_INTERNAL_DELIMITER); + + if (!strtype) { + fprintf(stderr, "Failed to extract socket protocol with " + "unspecified type value\n"); + goto out_free_name; + } + + if (get_socket_protocol(strdomain, strtype, &protocol)) { + fprintf(stderr, "Failed to extract socket protocol with " + "domain: \"%s\", type: \"%s\"\n", + strdomain, strtype); + goto out_free_name; + } + + if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &protocol, 0)) { + fprintf(stderr, + "Failed to update the ruleset with " + "domain \"%s\" and type \"%s\": %s\n", + strdomain, strtype, strerror(errno)); + goto out_free_name; + } + } + ret = 0; + +out_free_name: + free(env_protocol_name); + return ret; +} + /* clang-format off */ #define ACCESS_FS_ROUGHLY_READ ( \ @@ -205,14 +304,14 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd, /* clang-format on */ -#define LANDLOCK_ABI_LAST 4 +#define LANDLOCK_ABI_LAST 5 int main(const int argc, char *const argv[], char *const *const envp) { const char *cmd_path; char *const *cmd_argv; int ruleset_fd, abi; - char *env_port_name; + char *env_optional_name; __u64 access_fs_ro = ACCESS_FS_ROUGHLY_READ, access_fs_rw = ACCESS_FS_ROUGHLY_READ | ACCESS_FS_ROUGHLY_WRITE; @@ -220,18 +319,19 @@ int main(const int argc, char *const argv[], char *const *const envp) .handled_access_fs = access_fs_rw, .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP, + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE, }; if (argc < 2) { fprintf(stderr, - "usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\"%s " + "usage: %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\" %s=\"...\"%s " " [args]...\n\n", ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME, - ENV_TCP_CONNECT_NAME, argv[0]); + ENV_TCP_CONNECT_NAME, ENV_SOCKET_CREATE_NAME, argv[0]); fprintf(stderr, "Execute a command in a restricted environment.\n\n"); fprintf(stderr, - "Environment variables containing paths and ports " + "Environment variables containing paths, ports and protocols " "each separated by a colon:\n"); fprintf(stderr, "* %s: list of paths allowed to be used in a read-only way.\n", @@ -240,7 +340,7 @@ int main(const int argc, char *const argv[], char *const *const envp) "* %s: list of paths allowed to be used in a read-write way.\n\n", ENV_FS_RW_NAME); fprintf(stderr, - "Environment variables containing ports are optional " + "Environment variables containing ports or protocols are optional " "and could be skipped.\n"); fprintf(stderr, "* %s: list of ports allowed to bind (server).\n", @@ -248,22 +348,25 @@ int main(const int argc, char *const argv[], char *const *const envp) fprintf(stderr, "* %s: list of ports allowed to connect (client).\n", ENV_TCP_CONNECT_NAME); + fprintf(stderr, + "* %s: list of socket protocols allowed to be created.\n", + ENV_SOCKET_CREATE_NAME); fprintf(stderr, "\nexample:\n" "%s=\"${PATH}:/lib:/usr:/proc:/etc:/dev/urandom\" " "%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" " "%s=\"9418\" " "%s=\"80:443\" " + "%s=\"AF_INET6.SOCK_STREAM:AF_UNIX.SOCK_STREAM\" " "%s bash -i\n\n", ENV_FS_RO_NAME, ENV_FS_RW_NAME, ENV_TCP_BIND_NAME, - ENV_TCP_CONNECT_NAME, argv[0]); + ENV_TCP_CONNECT_NAME, ENV_SOCKET_CREATE_NAME, argv[0]); fprintf(stderr, "This sandboxer can use Landlock features " "up to ABI version %d.\n", LANDLOCK_ABI_LAST); return 1; } - abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION); if (abi < 0) { const int err = errno; @@ -325,6 +428,16 @@ int main(const int argc, char *const argv[], char *const *const envp) "provided by ABI version %d (instead of %d).\n", LANDLOCK_ABI_LAST, abi); __attribute__((fallthrough)); + case 4: + /* Removes socket support for ABI < 5 */ + ruleset_attr.handled_access_socket &= + ~LANDLOCK_ACCESS_SOCKET_CREATE; + fprintf(stderr, + "Hint: You should update the running kernel " + "to leverage Landlock features " + "provided by ABI version %d (instead of %d).\n", + LANDLOCK_ABI_LAST, abi); + __attribute__((fallthrough)); case LANDLOCK_ABI_LAST: break; default: @@ -338,18 +451,23 @@ int main(const int argc, char *const argv[], char *const *const envp) access_fs_rw &= ruleset_attr.handled_access_fs; /* Removes bind access attribute if not supported by a user. */ - env_port_name = getenv(ENV_TCP_BIND_NAME); - if (!env_port_name) { + env_optional_name = getenv(ENV_TCP_BIND_NAME); + if (!env_optional_name) { ruleset_attr.handled_access_net &= ~LANDLOCK_ACCESS_NET_BIND_TCP; } /* Removes connect access attribute if not supported by a user. */ - env_port_name = getenv(ENV_TCP_CONNECT_NAME); - if (!env_port_name) { + env_optional_name = getenv(ENV_TCP_CONNECT_NAME); + if (!env_optional_name) { ruleset_attr.handled_access_net &= ~LANDLOCK_ACCESS_NET_CONNECT_TCP; } - + /* Removes socket create access attribute if not supported by a user. */ + env_optional_name = getenv(ENV_SOCKET_CREATE_NAME); + if (!env_optional_name) { + ruleset_attr.handled_access_socket &= + ~LANDLOCK_ACCESS_SOCKET_CREATE; + } ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); if (ruleset_fd < 0) { @@ -373,6 +491,11 @@ int main(const int argc, char *const argv[], char *const *const envp) goto err_close_ruleset; } + if (populate_ruleset_socket(ENV_SOCKET_CREATE_NAME, ruleset_fd, + LANDLOCK_ACCESS_SOCKET_CREATE)) { + goto err_close_ruleset; + } + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("Failed to restrict privileges"); goto err_close_ruleset;