From patchwork Fri May 24 09:30:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672935 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 438D83FBB7; Fri, 24 May 2024 09:30:59 +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=1716543063; cv=none; b=MDSR7AHHyPO5kIVRVa9oq06r8sZctM/k9E6NjkQbpL2zDssXWkcSd+dJDrafLvU7lgrT33kyhAV2svSzqlNNsA5wBvp/HBO5RsUvOCjPQjyzQkzWR8zwbHNlijCqfto4oiFAjzUltoIOfSv3wmlCFzQfyCvyv2Igo3rjRfmu/lw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543063; c=relaxed/simple; bh=LLRcBUAZJ+4Mb0y2fxVj3cV21YGkJ5/ZPVoO9TnaErc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GRyqezwEYaMj9s17GPfnumHGj2/VavQCA9lREni3uXVjn8MDH1Jio8jUPLczM1fWAoGfvUcb92ofFvQ0xiwAAhmBgQgtldLiZYRmwKA7eOBi1o8Ta6ZqyTuxcS8qC+idFex8cH34Mk5QUe7zdiTagWwyMgQFqkE6oHM95qeMGhY= 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.162.112]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4Vm07s66vLz1ysKf; Fri, 24 May 2024 17:27:53 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 9B71E14037C; Fri, 24 May 2024 17:30:57 +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; Fri, 24 May 2024 17:30:55 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 01/12] landlock: Support socket access-control Date: Fri, 24 May 2024 17:30:04 +0800 Message-ID: <20240524093015.2402952-2-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC * Add new landlock rule type that corresponds to the restriction of socket protocols. This is represented as an landlock_socket_attr structure. Protocol allowed by landlock must be described by a family-type pair (see socket(2)). * Support socket rule storage in landlock ruleset. * Add flag LANDLOCK_ACCESS_SOCKET_CREATE that will provide the ability to control socket creation. * Add socket.c file that will contain socket rules management and hooks. Implement helper pack_socket_key() to convert 32-bit family and type values into uintptr_t. This is possible due to the fact that these values are limited to AF_MAX (=46), SOCK_MAX (=11) constants. Assumption is checked in build-time by the helper. * Support socket rules in landlock syscalls. Change ABI version to 6. Closes: https://github.com/landlock-lsm/linux/issues/6 Signed-off-by: Mikhail Ivanov --- Changes since v1: * Reverts landlock_key.data type from u64 to uinptr_t. * Adds helper to pack domain and type values into uintptr_t. * Denies inserting socket rule with invalid family and type. * Renames 'domain' to 'family' in landlock_socket_attr. * Updates ABI version to 6 since ioctl patches changed it to 5. * Formats code with clang-format. * Minor fixes. --- include/uapi/linux/landlock.h | 53 +++++++++++++++- security/landlock/Makefile | 2 +- security/landlock/limits.h | 5 ++ security/landlock/ruleset.c | 37 ++++++++++- security/landlock/ruleset.h | 41 +++++++++++- security/landlock/socket.c | 60 ++++++++++++++++++ security/landlock/socket.h | 17 +++++ security/landlock/syscalls.c | 66 ++++++++++++++++++-- tools/testing/selftests/landlock/base_test.c | 2 +- 9 files changed, 272 insertions(+), 11 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 68625e728f43..a25ba5983dfb 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_socket: 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,28 @@ 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; + /** + * @family: Protocol family used for communication + * (same as domain in socket(2)). + */ + int family; + /** + * @type: Socket type (see socket(2)). + */ + int type; +}; + /** * DOC: fs_access * @@ -251,7 +285,7 @@ struct landlock_net_port_attr { * DOC: net_access * * Network flags - * ~~~~~~~~~~~~~~~~ + * ~~~~~~~~~~~~~ * * These flags enable to restrict a sandboxed process to a set of network * actions. This is supported since the Landlock ABI version 4. @@ -266,4 +300,21 @@ 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_access + * + * Socket flags + * ~~~~~~~~~~~~ + * + * These flags enable to restrict a sanboxed process to a set of socket + * protocols. This is supported since the Landlock ABI version 6. + * + * The following access rights apply only to sockets: + * + * - %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 b4538b7cf7d2..ff1dd98f6a1b 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 20fdb5ff3514..448b4d596783 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/ruleset.c b/security/landlock/ruleset.c index e0a5fbf9201a..c782f7cd313d 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,9 @@ 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 +94,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 +154,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 +186,9 @@ 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 +412,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 +480,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 +521,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 +735,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 c7f1526784fd..a9773efd529b 100644 --- a/security/landlock/ruleset.h +++ b/security/landlock/ruleset.h @@ -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 (family, 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 access_mask_socket); void landlock_put_ruleset(struct landlock_ruleset *const ruleset); void landlock_put_ruleset_deferred(struct landlock_ruleset *const ruleset); @@ -282,6 +298,20 @@ 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 +339,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 000000000000..1249a4a36503 --- /dev/null +++ b/security/landlock/socket.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Landlock LSM - Socket management and hooks + * + * Copyright © 2024 Huawei Tech. Co., Ltd. + */ + +#include +#include +#include + +#include "limits.h" +#include "ruleset.h" +#include "socket.h" + +static uintptr_t pack_socket_key(const int family, const int type) +{ + union { + struct { + unsigned short family, type; + } __packed data; + uintptr_t packed; + } socket_key; + + /* Checks that all supported socket families and types can be stored in socket_key. */ + BUILD_BUG_ON(AF_MAX > (typeof(socket_key.data.family))~0); + BUILD_BUG_ON(SOCK_MAX > (typeof(socket_key.data.type))~0); + + /* Checks that socket_key can be stored in landlock_key. */ + BUILD_BUG_ON(sizeof(socket_key.data) > sizeof(socket_key.packed)); + BUILD_BUG_ON(sizeof(socket_key.packed) > + sizeof_field(union landlock_key, data)); + + socket_key.data.family = (unsigned short)family; + socket_key.data.type = (unsigned short)type; + + return socket_key.packed; +} + +int landlock_append_socket_rule(struct landlock_ruleset *const ruleset, + const int family, const int type, + access_mask_t access_rights) +{ + int err; + + const struct landlock_id id = { + .key.data = pack_socket_key(family, type), + .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 000000000000..8519357f1c39 --- /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 family, 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 03b470f5a85a..30c771f5e74f 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -24,12 +24,14 @@ #include #include #include +#include #include #include "cred.h" #include "fs.h" #include "limits.h" #include "net.h" +#include "socket.h" #include "ruleset.h" #include "setup.h" @@ -88,7 +90,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 +100,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 +113,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.family); + 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 +159,7 @@ static const struct file_operations ruleset_fops = { .write = fop_dummy_write, }; -#define LANDLOCK_ABI_VERSION 5 +#define LANDLOCK_ABI_VERSION 6 /** * sys_landlock_create_ruleset - Create a new ruleset @@ -213,9 +223,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 +387,45 @@ 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 family, type; + 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 socket 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; + + family = socket_attr.family; + type = socket_attr.type; + + /* Denies inserting a rule with unsupported socket family and type. */ + if (family < 0 || family >= AF_MAX) + return -EINVAL; + if (type < 0 || type >= SOCK_MAX) + return -EINVAL; + + /* Imports the new rule. */ + return landlock_append_socket_rule(ruleset, family, type, + socket_attr.allowed_access); +} + /** * sys_landlock_add_rule - Add a new rule to a ruleset * @@ -429,6 +484,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 3c1e9f35b531..52b00472a487 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(5, landlock_create_ruleset(NULL, 0, + ASSERT_EQ(6, landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION)); ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, From patchwork Fri May 24 09:30:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672936 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 6215A83A09; Fri, 24 May 2024 09:31:01 +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=1716543063; cv=none; b=gHFb1JLyw/rN20EY2WTory+22Rno/uZCoPkPMltFme8MPR1sZ/Q5lugDC+rLYgDL/dJMHPHOcLTcHNjk3/yYy//RrFOpqnEbHmw6/0OfZijhZFx4ogw0zbLJYLEF2AWXkXP+c1uc36Z7wOBBB6gNCrzEBotlU8ZyhceY7fGlcIw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543063; c=relaxed/simple; bh=rp1P44Lj4paszBTwxqlV9sGSYD1fJ72KyW0609FTmEQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=sNpAsKWMSmJ6qWZL3rIWazj5V9M1RxK3TCqx9vygZh28c7jNWQd+/OfuInSvZOV3vf/U63HRDKgBfwVw/+hA+iqG57YPBuktDuBDCx7Iq0ef7h8Lu42E8t5V2XMPgcfE0xTJBL0B8mf2/VzqE5/H7Y2RZ9Z5TycmX0AU9sKtjGo= 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 4Vm0775hFVzsRlm; Fri, 24 May 2024 17:27:15 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 5D33218007A; Fri, 24 May 2024 17:30:59 +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; Fri, 24 May 2024 17:30:57 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 02/12] landlock: Add hook on socket creation Date: Fri, 24 May 2024 17:30:05 +0800 Message-ID: <20240524093015.2402952-3-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC Add hook to security_socket_post_create(), which checks whether the socket type and family are allowed by domain. Hook is called after initializing the socket in the network stack to not wrongfully return EACCES for a family-type pair, which is considered invalid by the protocol. Signed-off-by: Mikhail Ivanov --- Changes since v1: * Use 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 | 70 ++++++++++++++++++++++++++++++++++++++ security/landlock/socket.h | 2 ++ 3 files changed, 74 insertions(+) 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 1249a4a36503..b2775473b3dc 100644 --- a/security/landlock/socket.c +++ b/security/landlock/socket.c @@ -8,7 +8,9 @@ #include #include #include +#include +#include "cred.h" #include "limits.h" #include "ruleset.h" #include "socket.h" @@ -58,3 +60,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, int family, + int type, + const access_mask_t access_request) +{ + 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; + + id.key.data = pack_socket_key(family, type); + + 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, family, type, + 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 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); From patchwork Fri May 24 09:30:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672937 Received: from szxga08-in.huawei.com (szxga08-in.huawei.com [45.249.212.255]) (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 228E5282E2; Fri, 24 May 2024 09:31:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.255 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543065; cv=none; b=vD6iuaIgCZ5InvURCxByyBbmtmoGaxf+RwwT/g8dv/Qv4WUDqWhWd2nZ6xvAG8nQiF3gDVyUsGuOnkERuvqiS2uWk9OETQ0mrjlL18Ao2aDV9noPWQkP92/8qUYZtKUDgp/oVn7pM7KK7vd6oiBXMscMBxsZEhsJZUZxsgCzrP0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543065; c=relaxed/simple; bh=u5P7SwWlxlkLkPdOZ5/gegigyxPtGC2QBP2iTb9MYWo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=L2Q6khIuNzCthygQYXlDweyvqTK6qGDv4la3EzMLynlaV8ABhuU6BEz5l6khquPdAgb+tXG5qyyikijFBRX6+QWPzCWPYBho2MJxkkJO+O6v7XM0ftOVEz2orLOcUrNM2nd/5W7EibrSS8q0XUz1YpVv3ikQAz9m8z5sDzzdUfs= 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.255 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.48]) by szxga08-in.huawei.com (SkyGuard) with ESMTP id 4Vm07D2GqCz1S4tG; Fri, 24 May 2024 17:27:20 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id E94B518007E; Fri, 24 May 2024 17:31:00 +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; Fri, 24 May 2024 17:30:59 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 03/12] selftests/landlock: Add protocol.create to socket tests Date: Fri, 24 May 2024 17:30:06 +0800 Message-ID: <20240524093015.2402952-4-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC Initiate socket_test.c selftests. Add protocol fixture for tests with changeable family-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: Mikhail Ivanov --- Changes since v1: * Replaces test_socket_create() and socket_variant() helpers with test_socket(). * Renames domain to family in protocol fixture. * Remove AF_UNSPEC fixture entry and add unspec_srv0 fixture field to check AF_UNSPEC socket creation case. * Formats code with clang-format. * Refactors commit message. --- .../testing/selftests/landlock/socket_test.c | 181 ++++++++++++++++++ 1 file changed, 181 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 000000000000..4c51f89ed578 --- /dev/null +++ b/tools/testing/selftests/landlock/socket_test.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Landlock tests - Socket + * + * Copyright © 2024 Huawei Tech. Co., Ltd. + * Copyright © 2024 Microsoft Corporation + */ + +#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 family; + 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 test_socket(const struct service_fixture *const srv) +{ + int fd; + + fd = socket(srv->protocol.family, srv->protocol.type | SOCK_CLOEXEC, 0); + if (fd < 0) + return errno; + /* + * Mixing error codes from close(2) and socket(2) should not lead to any + * (access type) confusion for this test. + */ + if (close(fd) != 0) + return errno; + return 0; +} + +FIXTURE(protocol) +{ + struct service_fixture srv0, unspec_srv0; +}; + +FIXTURE_VARIANT(protocol) +{ + const struct protocol_variant protocol; +}; + +FIXTURE_SETUP(protocol) +{ + const struct protocol_variant prot_unspec = { + .family = AF_UNSPEC, + .type = SOCK_STREAM, + }; + + disable_caps(_metadata); + self->srv0.protocol = variant->protocol; + self->unspec_srv0.protocol = prot_unspec; + setup_namespace(_metadata); +}; + +FIXTURE_TEARDOWN(protocol) +{ +} + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, unix_stream) { + /* clang-format on */ + .protocol = { + .family = AF_UNIX, + .type = SOCK_STREAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, unix_dgram) { + /* clang-format on */ + .protocol = { + .family = AF_UNIX, + .type = SOCK_DGRAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv4_tcp) { + /* clang-format on */ + .protocol = { + .family = AF_INET, + .type = SOCK_STREAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv4_udp) { + /* clang-format on */ + .protocol = { + .family = AF_INET, + .type = SOCK_DGRAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv6_tcp) { + /* clang-format on */ + .protocol = { + .family = AF_INET6, + .type = SOCK_STREAM, + }, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(protocol, ipv6_udp) { + /* clang-format on */ + .protocol = { + .family = AF_INET6, + .type = SOCK_DGRAM, + }, +}; + +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, + .family = self->srv0.protocol.family, + .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)); + + ASSERT_EQ(0, test_socket(&self->srv0)); + ASSERT_EQ(EAFNOSUPPORT, test_socket(&self->unspec_srv0)); + + /* 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)); + + ASSERT_EQ(EACCES, test_socket(&self->srv0)); + ASSERT_EQ(EAFNOSUPPORT, test_socket(&self->unspec_srv0)); +} + +TEST_HARNESS_MAIN From patchwork Fri May 24 09:30:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672938 Received: from szxga07-in.huawei.com (szxga07-in.huawei.com [45.249.212.35]) (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 CCFA03FBB7; Fri, 24 May 2024 09:31:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.35 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543066; cv=none; b=GC45rji10o3lNnmOnLn8TG54n0cPr0ECfo0IUx9U82w3iWXPmIsejyfekJfMDnamCruF4UzMVM/vLPDjYT1d96LYH4hI7EWCOyEpmr4HGBMZvbVtb0HMyV5fWdAauk4eJgal/xd1FGhwwYB/TFA294T//EbSq+AFwiq1rQMfMCw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543066; c=relaxed/simple; bh=ciE6nblL9ir8n009raQIHua22NLhPElD//QfkV0PARY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Aig2LUhqZlnUIkVleftFMeHbANJHJRP00565+IqIGd2JbrolKuU6CZRxQhNVZTLD6sC3ND940e3f3chiQztNYlt40CxxCUgavMdgg8imkputWLkR4S8mb84tREHlO9oh5LJKNb4QTg6s6x2/mHt255yCw25dtnKBbinBDZosBys= 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.35 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.214]) by szxga07-in.huawei.com (SkyGuard) with ESMTP id 4Vm07R3P3vz1S5bR; Fri, 24 May 2024 17:27:31 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 806891A016C; Fri, 24 May 2024 17:31:02 +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; Fri, 24 May 2024 17:31:00 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 04/12] selftests/landlock: Add protocol.socket_access_rights to socket tests Date: Fri, 24 May 2024 17:30:07 +0800 Message-ID: <20240524093015.2402952-5-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC Add test that checks possibility of adding rule with every possible access right. Signed-off-by: Mikhail Ivanov Reviewed-by: Günther Noack --- Changes since v1: * Formats code with clang-format. * Refactors commit message. --- .../testing/selftests/landlock/socket_test.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index 4c51f89ed578..eb5d62263460 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -178,4 +178,32 @@ TEST_F(protocol, create) ASSERT_EQ(EAFNOSUPPORT, test_socket(&self->unspec_srv0)); } +TEST_F(protocol, socket_access_rights) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = ACCESS_ALL, + }; + struct landlock_socket_attr protocol = { + .family = self->srv0.protocol.family, + .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 Fri May 24 09:30:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672939 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 E2C3E85925; Fri, 24 May 2024 09:31:05 +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=1716543067; cv=none; b=XSVi063cY5zu0RF+5d9ry8Qgintw4bgfgydDaJyFihCyHggu37SibaSd8QtDrpVI6dTj+iCFrgQFzuy0KPFKCkjx1sdbf33KeWlJca5sV9J4//vhPDk1akuGSa9XXqP0Wlrb3nvQzBLXjqL6Rh+QE1JCwA5T0hJvWNm0DZmZPXs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543067; c=relaxed/simple; bh=nfospkBlIKZ8TZMuU2G4eh17Fe3mW1kHAuWIHtr3KVU=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=KfLeL19xsuHkmuHyaoIyTplQqZscBULExNpIadmxnTd5RySgV2dK6pRnCBTckDpHk4o4ckQ78p3o5aWMMG/DjRy77ssDWQDiaaYAZ0gWr/XuQGSfrz0IbqrkaEOBtB4DqZufH3zFwQO9AM/Hc3GFUWd20gN4BpILzfCMji9yBmk= 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 4Vm07D3nKvzsRhb; Fri, 24 May 2024 17:27:20 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 1C93B18007A; Fri, 24 May 2024 17:31:04 +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; Fri, 24 May 2024 17:31:02 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 05/12] selftests/landlock: Add protocol.rule_with_unknown_access to socket tests Date: Fri, 24 May 2024 17:30:08 +0800 Message-ID: <20240524093015.2402952-6-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC Add test that validates behavior of landlock after rule with unknown access is added. Signed-off-by: Mikhail Ivanov Reviewed-by: Günther Noack --- Changes since v1: * Refactors commit messsage. --- .../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 eb5d62263460..57d5927906b8 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -206,4 +206,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_socket = ACCESS_ALL, + }; + struct landlock_socket_attr protocol = { + .family = self->srv0.protocol.family, + .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 Fri May 24 09:30:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672940 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) (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 2DC4E85C69; Fri, 24 May 2024 09:31:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.189 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543070; cv=none; b=jIjyGB+nKCTyeG0ZUQPJhIkFMwoloLHXUjBh+8lsuMKu6W+zEoGJij6zGnTec00AFUPEA76wKxhAZAjvcpbAmdzoGdSL3gRCbyUGRqJkQ589FHGY6iDxWzHPXjxcjT1OXOltfIwIOavwqA6CspFPqJSEyL8Jl/7RxUfTqy5XYnA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543070; c=relaxed/simple; bh=lctE3ZYtTldW/LPpaaEZTsFFKQkydhhY+bZxY4gyC18=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=s8GvBGXgRul6P8B6J/lgdC9jfCL1c9hjfx2GbdOiSvHFjNddJkOe5V1QuFzeGKvBI7UbdW8qaJnC6pp74CET4r42LV6pcj2GbZtPxh2Ae/ZX5MNo/3swxAtpzXW+SVtjWqNwj7py+/oqoeVSEzOPg6EXCOnODsBm2V26djsSu0Q= 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.189 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.174]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4Vm0813RlfzPkWS; Fri, 24 May 2024 17:28:01 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id ADA5A1400D1; Fri, 24 May 2024 17:31: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; Fri, 24 May 2024 17:31:04 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 06/12] selftests/landlock: Add protocol.rule_with_unhandled_access to socket tests Date: Fri, 24 May 2024 17:30:09 +0800 Message-ID: <20240524093015.2402952-7-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC Add test that validates behavior of landlock after rule with unhandled access is added. Signed-off-by: Mikhail Ivanov Reviewed-by: Günther Noack --- Changes since v1: * Refactors commit message. --- .../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 57d5927906b8..31af47de1937 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -232,4 +232,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 = { + .family = self->srv0.protocol.family, + .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 Fri May 24 09:30:10 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672941 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 15D0A85275; Fri, 24 May 2024 09:31:08 +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=1716543070; cv=none; b=czVJkTBT/nHkbn/JSDJLVaEgwgBDJzgyv3795uM8I8Gyc9OtO8YN+8bXysJeoT1XWcnvYSSGeZk6AhXvRqbIc6Lr1E2Tra3EUwd6pCzfMPcNAPgnsgkodXmoRlkg6ieYAEXNJBTu1243LMBFBFbp/R+Ew8DF7XvFakVEQNGjh2Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543070; c=relaxed/simple; bh=hEwvHWiLcPuJkjJV6oiQLy1VESlpWobpJivZ6lGSx6I=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YFibgh6a+3KD55WYKOCqFWOlh+t58L4qi3nX7IFA0QkKafT5Zt/1vVpgc8AYr8q6E3rh02Hkbl7Uw6No8B9hazNvSoAqorpil0lV4m4kSm0y9miPdUgqBJcx1r+ynqjbNxlTTheIEXSrkvX3SYay0rbRBD/Yq0conpKaPAkxbB8= 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.162.112]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4Vm0833MhXz1ymXf; Fri, 24 May 2024 17:28:03 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 3E10C14037C; Fri, 24 May 2024 17:31:07 +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; Fri, 24 May 2024 17:31:05 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 07/12] selftests/landlock: Add protocol.inval to socket tests Date: Fri, 24 May 2024 17:30:10 +0800 Message-ID: <20240524093015.2402952-8-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC Add test that validates behavior of landlock with fully access restriction. Signed-off-by: Mikhail Ivanov --- Changes since v1: * Refactors commit message. --- .../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 31af47de1937..751596c381fe 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -265,4 +265,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, + .family = self->srv0.protocol.family, + .type = self->srv0.protocol.type, + }; + + struct landlock_socket_attr protocol_denied = { + .allowed_access = 0, + .family = self->srv0.protocol.family, + .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 Fri May 24 09:30:11 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672942 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) (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 EF4128612C; Fri, 24 May 2024 09:31:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.189 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543072; cv=none; b=JbMwDmyaAvh2/fJcuvX1wX1Za1sgYbHuSCSp0agihg0S2Gekst4ewRqPUl8mEil0sdk5EFuVTjnGCBiJUWtCAx7n+WonT/9M14PVt8fvbyDKgv2E7HNejetugOizebKCD48WdQDGtphmQuqJBz1hvsB6AZ9VmRVij8uzKqgRELc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543072; c=relaxed/simple; bh=84g9o5v72dYyI4CMgJLcxvV2pF5YMVFNegl/wbvvSUQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l81zIl+t6hDgi90ApVtDEvOFq/tcyE1RzFqi0ThMjIa+sGEKmcXwnV4g1DiNZoSLolt5jbgA1bjmJaQs5FziHprb8O5ga+NSMRDhEE/+ox83SARHjbemsRrTR+tx7ytueSiXQKp0VcnBeX2f+8fMW1nkWL7yf+vJ9mcmiLmSRqA= 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.189 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 szxga03-in.huawei.com (SkyGuard) with ESMTP id 4Vm0845DJPzPlm4; Fri, 24 May 2024 17:28:04 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id E80F9140132; Fri, 24 May 2024 17:31: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; Fri, 24 May 2024 17:31:07 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 08/12] selftests/landlock: Add tcp_layers.ruleset_overlap to socket tests Date: Fri, 24 May 2024 17:30:11 +0800 Message-ID: <20240524093015.2402952-9-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC * 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: Mikhail Ivanov --- Changes since v1: * Replaces test_socket_create() with test_socket(). * Formats code with clang-format. * Refactors commit message. * Minor fixes. --- .../testing/selftests/landlock/socket_test.c | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index 751596c381fe..52edc1a8ac21 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -299,4 +299,113 @@ 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 = { + .family = 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, + .family = self->srv0.protocol.family, + .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)); + } + + if (variant->num_layers < 2) { + ASSERT_EQ(0, test_socket(&self->srv0)); + } else { + ASSERT_EQ(EACCES, test_socket(&self->srv0)); + } +} + TEST_HARNESS_MAIN From patchwork Fri May 24 09:30:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672943 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 850A885297; Fri, 24 May 2024 09:31: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=1716543074; cv=none; b=PRIQE/AKgPcTSwmID/X+HcUizr5y1xMyWykfcsLrJLHFRIZl6yXOySLWp/bncHxUgcYli05RTN2e7PmqfXATPpNPAoCszw96vxiUfChZLKS3uTzdeV2MJwHQIwNadnDr9ONXnwAyQK2REbBz4HYFRibnmjI0yAj9EtgQxkMWOH0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543074; c=relaxed/simple; bh=bL/0fFmFj3v4Jqh3lYGlL7CUYnF1mKWXXjO+y6Y+fak=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=OpvSe6ubLfZZ1IL+guwVlYfgNygG6uIW0CnaQrMjzx9PfqXTBo+jRe+6SDvjjwVVnyHSqiADjh4FjFBrQhQnbKP09TlbO6QROzhpI7kuiu4u/EDz68hkkhdAxlQC4MI72RsEjRu7OIg5fVsHHtJzpQvnx3vVins3EorYvYXKSOY= 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.48]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4Vm07M0bBKzsRhb; Fri, 24 May 2024 17:27:27 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id A41D518007E; Fri, 24 May 2024 17:31: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; Fri, 24 May 2024 17:31:08 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 09/12] selftests/landlock: Add mini.ruleset_with_unknown_access to socket tests Date: Fri, 24 May 2024 17:30:12 +0800 Message-ID: <20240524093015.2402952-10-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC * 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: Mikhail Ivanov --- Changes since v1: * Refactors commit message. --- .../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 52edc1a8ac21..c81f02ffef6c 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -408,4 +408,35 @@ TEST_F(tcp_layers, ruleset_overlap) } } +/* 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 Fri May 24 09:30:13 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672944 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 0B0B78612C; Fri, 24 May 2024 09:31:13 +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=1716543076; cv=none; b=LpqERxc9GF5hZZ20ODukFuCcXh7tA1zufhOEkFcirLSZjzhlNs5rAqBGeKByXKy5yCDB2kyqQQyuoO1n7Q4S9xneha8K99/eQAMAOH/CcfEf0WYILSdBuJwwKAEI6by7sAN9DJukZFyz/U2y0RAK3hbOsEbRHXJzUP9huLUqJvY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543076; c=relaxed/simple; bh=amUffNvgWr3XWgM3cDBGJHlFqjphGTGJejo4HcUHUHY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=i21Y2/Ndi4eeWLzGfBJEqj4vXZOn2mvEmLU8KCSgjh0atGzQaTehOYQQIqnfrpXhnfuVpGkeQHnTY10dwZvQ3Cym9GZp2HzGIJmcfAYn21oBarM3dcy6uvJTttuWnkNtJSICp7aR5tmADh65ddI0MjTQmj9hKs+/VOk8he9GPZU= 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.88.194]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4Vm07N4vzMzsRmP; Fri, 24 May 2024 17:27:28 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 42DA11402CE; Fri, 24 May 2024 17:31: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; Fri, 24 May 2024 17:31:10 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 10/12] selftests/landlock: Add mini.socket_overflow to socket tests Date: Fri, 24 May 2024 17:30:13 +0800 Message-ID: <20240524093015.2402952-11-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC * Add test validating that adding a rule for sockets that do not match the ranges (0 <= domain < AF_MAX), (0 <= type < SOCK_MAX) is prohibited. This test also checks that Landlock supports maximum possible domain, type values. * Add CONFIG_MCTP to selftests config to check the socket with maximum family (AF_MCTP). * Add CAP_NET_RAW capability to landlock selftests, which is required to create PACKET sockets (maximum type value). Signed-off-by: Mikhail Ivanov --- tools/testing/selftests/landlock/common.h | 1 + tools/testing/selftests/landlock/config | 1 + .../testing/selftests/landlock/socket_test.c | 93 +++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index 7e2b431b9f90..28df49fa22d5 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -66,6 +66,7 @@ static void _init_caps(struct __test_metadata *const _metadata, bool drop_all) CAP_NET_BIND_SERVICE, CAP_SYS_ADMIN, CAP_SYS_CHROOT, + CAP_NET_RAW, /* clang-format on */ }; const unsigned int noroot = SECBIT_NOROOT | SECBIT_NOROOT_LOCKED; diff --git a/tools/testing/selftests/landlock/config b/tools/testing/selftests/landlock/config index 0086efaa7b68..2820c481aefe 100644 --- a/tools/testing/selftests/landlock/config +++ b/tools/testing/selftests/landlock/config @@ -12,3 +12,4 @@ CONFIG_SHMEM=y CONFIG_SYSFS=y CONFIG_TMPFS=y CONFIG_TMPFS_XATTR=y +CONFIG_MCTP=y \ No newline at end of file diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index c81f02ffef6c..80c904380075 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -9,6 +9,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -439,4 +440,96 @@ TEST_F(mini, ruleset_with_unknown_access) } } +TEST_F(mini, socket_overflow) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE, + }; + /* + * Assuming that AF_MCTP == AF_MAX - 1 uses MCTP as protocol + * with maximum family value. Appropriate сheck for this is given below. + */ + const struct landlock_socket_attr create_socket_max_family = { + .allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE, + .family = AF_MCTP, + .type = SOCK_DGRAM, + }; + /* + * Assuming that SOCK_PACKET == SOCK_MAX - 1 uses PACKET socket as + * socket with maximum type value. Since SOCK_MAX cannot be accessed + * from selftests, this assumption is not verified. + */ + const struct landlock_socket_attr create_socket_max_type = { + .allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE, + .family = AF_PACKET, + .type = SOCK_PACKET, + }; + struct landlock_socket_attr create_socket_overflow = { + .allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE, + }; + const struct protocol_variant protocol_max_family = { + .family = create_socket_max_family.family, + .type = create_socket_max_family.type, + }; + const struct protocol_variant protocol_max_type = { + .family = create_socket_max_type.family, + .type = create_socket_max_type.type, + }; + const struct protocol_variant ipv4_tcp = { + .family = AF_INET, + .type = SOCK_STREAM, + }; + struct service_fixture srv_max_allowed_family, srv_max_allowed_type, + srv_denied; + int ruleset_fd; + + /* Checks protocol_max_family correctness. */ + ASSERT_EQ(AF_MCTP + 1, AF_MAX); + + srv_max_allowed_family.protocol = protocol_max_family; + srv_max_allowed_type.protocol = protocol_max_type; + srv_denied.protocol = ipv4_tcp; + + 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_max_family, 0)); + ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &create_socket_max_type, 0)); + + /* Checks the overflow variants for family, type values. */ +#define CHECK_RULE_OVERFLOW(family_val, type_val) \ + do { \ + create_socket_overflow.family = family_val; \ + create_socket_overflow.type = type_val; \ + EXPECT_EQ(-1, \ + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, \ + &create_socket_overflow, 0)); \ + EXPECT_EQ(EINVAL, errno); \ + } while (0) + + CHECK_RULE_OVERFLOW(AF_MAX, SOCK_STREAM); + CHECK_RULE_OVERFLOW(AF_INET, (SOCK_PACKET + 1)); + CHECK_RULE_OVERFLOW(AF_MAX, (SOCK_PACKET + 1)); + CHECK_RULE_OVERFLOW(-1, SOCK_STREAM); + CHECK_RULE_OVERFLOW(AF_INET, -1); + CHECK_RULE_OVERFLOW(-1, -1); + CHECK_RULE_OVERFLOW(INT16_MAX + 1, INT16_MAX + 1); + +#undef CHECK_RULE_OVERFLOW + + enforce_ruleset(_metadata, ruleset_fd); + + EXPECT_EQ(0, test_socket(&srv_max_allowed_family)); + + /* PACKET sockets can be used only with CAP_NET_RAW. */ + set_cap(_metadata, CAP_NET_RAW); + EXPECT_EQ(0, test_socket(&srv_max_allowed_type)); + clear_cap(_metadata, CAP_NET_RAW); + + EXPECT_EQ(EACCES, test_socket(&srv_denied)); +} + TEST_HARNESS_MAIN From patchwork Fri May 24 09:30:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672945 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 722CF85297; Fri, 24 May 2024 09:31:15 +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=1716543077; cv=none; b=VNsxgdkXyn/Fg1NH6YwLiEyr/lGSRIFDyesNeQpfmZTH2eSuID9zUTCAA8LZONPAMIcq4oTP0juyiBJzhwaGcfYSPEoo4cS/KIszAEy1t7ZL0ji874dHUeCjDEGW+qyYkejXc7YtxVpQC2Y2lxWZ+e3Ot+oTq3zvgfSxQ8tR1nk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543077; c=relaxed/simple; bh=Puej5jIel5y8wPIAmxPgow7Z7eZtFpvc/Z2nOyUo10Q=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QLFnj2NpMFZPB3Zf5CKJ/pFobL+Vswuvy2d6lLfHZYU9BIq4LLZHsdLocTq4mbtY0igEf3sNi5g1OSusXIfv3TP5ysjrS9oDeqRTrmkqxWSzt7/vSZQZVjWCSh2Z5F/t2jHLvZctE84F18loiI7DWwyiXZUV36ryiK7iVux9ySA= 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.48]) by szxga01-in.huawei.com (SkyGuard) with ESMTP id 4Vm07Q1z4lzsRlm; Fri, 24 May 2024 17:27:30 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id D428418007E; Fri, 24 May 2024 17:31:13 +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; Fri, 24 May 2024 17:31:12 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 11/12] selftests/landlock: Add mini.socket_invalid_type to socket tests Date: Fri, 24 May 2024 17:30:14 +0800 Message-ID: <20240524093015.2402952-12-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC Add test validating that landlock doesn't wrongfully return EACCES for socket with invalid type (e.g. UNIX socket with PACKET type). Signed-off-by: Mikhail Ivanov --- .../testing/selftests/landlock/socket_test.c | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tools/testing/selftests/landlock/socket_test.c b/tools/testing/selftests/landlock/socket_test.c index 80c904380075..b062001a778e 100644 --- a/tools/testing/selftests/landlock/socket_test.c +++ b/tools/testing/selftests/landlock/socket_test.c @@ -532,4 +532,50 @@ TEST_F(mini, socket_overflow) EXPECT_EQ(EACCES, test_socket(&srv_denied)); } +TEST_F(mini, socket_invalid_type) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_socket = LANDLOCK_ACCESS_SOCKET_CREATE, + }; + /* + * SOCK_PACKET is invalid type for UNIX socket + * (see net/unix/af_unix.c:unix_create()). + */ + const struct landlock_socket_attr create_unix_invalid = { + .allowed_access = LANDLOCK_ACCESS_SOCKET_CREATE, + .family = AF_UNIX, + .type = SOCK_PACKET, + }; + const struct protocol_variant protocol_invalid = { + .family = create_unix_invalid.family, + .type = create_unix_invalid.type, + }; + struct service_fixture srv_unix_invalid; + int ruleset_fd; + + srv_unix_invalid.protocol = protocol_invalid; + + /* Allowed created */ + 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_unix_invalid, 0)); + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + EXPECT_EQ(ESOCKTNOSUPPORT, test_socket(&srv_unix_invalid)); + + /* 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)); + + EXPECT_EQ(ESOCKTNOSUPPORT, test_socket(&srv_unix_invalid)); +} + TEST_HARNESS_MAIN From patchwork Fri May 24 09:30:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13672946 Received: from szxga07-in.huawei.com (szxga07-in.huawei.com [45.249.212.35]) (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 A59128665B; Fri, 24 May 2024 09:31:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.35 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543081; cv=none; b=lwHg1i+jdc+0wOmkAkFP4+cFjDMCmg+Q8TE3T/qZ0Krlvp4izWYKhFRJas5MZIkK1SzSadWuJk8VXl9XCavOVCRQWt/7+hzB1vBvY3UzztYzIqqtuecHZdtV1U9TEOhX7JQl1PFQZdh2hha2Qfjb15xb0Xn91XCG0k1IMZJ06Tk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716543081; c=relaxed/simple; bh=3o8Gg+0xa0qjpeE5jO6ta5rVgvxwriCbZEtCJNnAJV8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=GfuPfxLbOI4sSQkvnn4MrihXsWWRvWPS/31nKBlBXExacnT86QxYdYeUqq6v/H3+1mcGP8RewSikbJ4YBAvYsWVCvGwgalN+iUmwM455MQ4enRTELWkEpNFwxnlGKAlQql4gXvlOfGbmjUEl36oK6N0IdzM7U0UEXfc3Z9AaHZQ= 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.35 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.112]) by szxga07-in.huawei.com (SkyGuard) with ESMTP id 4Vm07h306Tz1S5c0; Fri, 24 May 2024 17:27:44 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 7220A14037C; Fri, 24 May 2024 17:31:15 +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; Fri, 24 May 2024 17:31:13 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 12/12] samples/landlock: Support socket protocol restrictions Date: Fri, 24 May 2024 17:30:15 +0800 Message-ID: <20240524093015.2402952-13-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> References: <20240524093015.2402952-1-ivanov.mikhail1@huawei-partners.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-ClientProxiedBy: mscpeml100004.china.huawei.com (7.188.51.133) To dggpemm500020.china.huawei.com (7.185.36.49) X-Patchwork-State: RFC * Add socket protocol control support in sandboxer demo. It's possible to allow a sandboxer to create sockets with specified family 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 parse_socket_protocol() method to parse socket family and type strings to the appropriate constants. Add CHECK_FAMILY() and CHECK_TYPE() macroses to prevent copypaste in method. * Change LANDLOCK_ABI_LAST to 6. Signed-off-by: Mikhail Ivanov --- Changes since v1: * Refactors get_socket_protocol(). Rename it to parse_socket_protocol(). * Changes LANDLOCK_ABI_LAST to 6 since ioctl patchlist updated it to 5. * Refactors commit message. * Formats with clang-format. * Minor changes. --- samples/landlock/sandboxer.c | 141 +++++++++++++++++++++++++++++++---- 1 file changed, 127 insertions(+), 14 deletions(-) diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c index e8223c3e781a..b6afe011e563 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; @@ -86,6 +90,42 @@ static int parse_path(char *env_path, const char ***const path_list) /* clang-format on */ +static int parse_socket_protocol(char *strfamily, char *strtype, + struct landlock_socket_attr *protocol) +{ + protocol->family = -1; + protocol->type = -1; + +#define CHECK_FAMILY(family_variant) \ + do { \ + if (strcmp(strfamily, #family_variant) == 0) { \ + protocol->family = family_variant; \ + } \ + } while (0) + +#define CHECK_TYPE(type_variant) \ + do { \ + if (strcmp(strtype, #type_variant) == 0) { \ + protocol->type = type_variant; \ + } \ + } while (0) + + CHECK_FAMILY(AF_UNIX); + CHECK_FAMILY(AF_INET); + CHECK_FAMILY(AF_INET6); + + CHECK_TYPE(SOCK_STREAM); + CHECK_TYPE(SOCK_DGRAM); + +#undef CHECK_FAMILY +#undef CHECK_TYPE + + /* Unknown protocol or type. */ + if (protocol->family == -1 || protocol->type == -1) + return 1; + return 0; +} + static int populate_ruleset_fs(const char *const env_var, const int ruleset_fd, const __u64 allowed_access) { @@ -184,6 +224,61 @@ 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, *strprotocol, *strfamily, *strtype; + struct landlock_socket_attr protocol = { + .allowed_access = allowed_access, + .family = 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); + + while ((strprotocol = strsep(&env_protocol_name, ENV_DELIMITER))) { + strfamily = 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 (parse_socket_protocol(strfamily, strtype, &protocol)) { + fprintf(stderr, + "Failed to extract socket protocol with " + "domain: \"%s\", type: \"%s\"\n" + "Sandboxer currently supports AF_UNIX, AF_INET, AF_INET6 " + "families and SOCK_STREAM, SOCK_DGRAM types\n", + strfamily, strtype); + goto out_free_name; + } + + if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_SOCKET, + &protocol, 0)) { + fprintf(stderr, + "Failed to update the ruleset with " + "family \"%s\" and type \"%s\": %s\n", + strfamily, 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 ( \ @@ -208,14 +303,14 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd, /* clang-format on */ -#define LANDLOCK_ABI_LAST 5 +#define LANDLOCK_ABI_LAST 6 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; @@ -223,18 +318,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", @@ -243,7 +339,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", @@ -251,22 +347,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_DGRAM: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; @@ -326,7 +425,11 @@ int main(const int argc, char *const argv[], char *const *const envp) case 4: /* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */ ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV; - + __attribute__((fallthrough)); + case 5: + /* Removes socket support for ABI < 6 */ + ruleset_attr.handled_access_socket &= + ~LANDLOCK_ACCESS_SOCKET_CREATE; fprintf(stderr, "Hint: You should update the running kernel " "to leverage Landlock features " @@ -346,18 +449,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) { @@ -381,6 +489,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;