From patchwork Wed Aug 14 03:01:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762787 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 430681BDD0; Wed, 14 Aug 2024 03:02:09 +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=1723604533; cv=none; b=mrd4RP189gPQesb5I7R9eLcRFfomqS/UDXnDInYhu20lbHE365W5wxvH0GjwsQS9hqA90249sn6catqnEKYnau8sJuCbwcCHjpukrCWOaQ1YEHfDKDBbB1D5NWKBlislMEbhBTJUWeIrkU9J+4gbREp9EN+9ZuJyfjGSmMu7d7o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604533; c=relaxed/simple; bh=Bq0J4dM/Ssad6W6jRFHjz+IF5IINDQDZBd7EC9wLw2M=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hy9d1zoiU6B1TRZHHIlH5/QpgGJ2xcK8tfcnoZdirujFu9umcFlRKSag1MWBn/xHzYJEWFjT7gFCnpQiHT3MZ57JTqmMVuoML7kI34UvaMEZ/aY6N4iKmiMyaY0V3hLsUhJaup6S8J9irnYFdHG6NulS6/TUD6jO9xjFTJdIe4w= 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.162.254]) by szxga08-in.huawei.com (SkyGuard) with ESMTP id 4WkChF4pLQz1T6r8; Wed, 14 Aug 2024 11:01:33 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 02C771800D0; Wed, 14 Aug 2024 11:02:03 +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.39; Wed, 14 Aug 2024 11:02:01 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 1/9] landlock: Refactor current_check_access_socket() access right check Date: Wed, 14 Aug 2024 11:01:43 +0800 Message-ID: <20240814030151.2380280-2-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) The current_check_access_socket() function contains a set of address validation checks for bind(2) and connect(2) hooks. Separate them from an actual port access right checking. It is required for the (future) hooks that do not perform address validation. Signed-off-by: Mikhail Ivanov --- security/landlock/net.c | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/security/landlock/net.c b/security/landlock/net.c index c8bcd29bde09..669ba260342f 100644 --- a/security/landlock/net.c +++ b/security/landlock/net.c @@ -2,7 +2,7 @@ /* * Landlock LSM - Network management and hooks * - * Copyright © 2022-2023 Huawei Tech. Co., Ltd. + * Copyright © 2022-2024 Huawei Tech. Co., Ltd. * Copyright © 2022-2023 Microsoft Corporation */ @@ -61,17 +61,34 @@ static const struct landlock_ruleset *get_current_net_domain(void) return dom; } -static int current_check_access_socket(struct socket *const sock, - struct sockaddr *const address, - const int addrlen, - access_mask_t access_request) +static int check_access_socket(const struct landlock_ruleset *const dom, + __be16 port, access_mask_t access_request) { - __be16 port; layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_NET] = {}; const struct landlock_rule *rule; struct landlock_id id = { .type = LANDLOCK_KEY_NET_PORT, }; + + id.key.data = (__force uintptr_t)port; + BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); + + rule = landlock_find_rule(dom, id); + access_request = landlock_init_layer_masks( + dom, access_request, &layer_masks, LANDLOCK_KEY_NET_PORT); + if (landlock_unmask_layers(rule, access_request, &layer_masks, + ARRAY_SIZE(layer_masks))) + return 0; + + return -EACCES; +} + +static int current_check_access_socket(struct socket *const sock, + struct sockaddr *const address, + const int addrlen, + access_mask_t access_request) +{ + __be16 port; const struct landlock_ruleset *const dom = get_current_net_domain(); if (!dom) @@ -159,17 +176,7 @@ static int current_check_access_socket(struct socket *const sock, return -EINVAL; } - id.key.data = (__force uintptr_t)port; - BUILD_BUG_ON(sizeof(port) > sizeof(id.key.data)); - - rule = landlock_find_rule(dom, id); - access_request = landlock_init_layer_masks( - dom, access_request, &layer_masks, LANDLOCK_KEY_NET_PORT); - if (landlock_unmask_layers(rule, access_request, &layer_masks, - ARRAY_SIZE(layer_masks))) - return 0; - - return -EACCES; + return check_access_socket(dom, port, access_request); } static int hook_socket_bind(struct socket *const sock, From patchwork Wed Aug 14 03:01:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762783 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 7339F2594; Wed, 14 Aug 2024 03:02:07 +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=1723604531; cv=none; b=oeqfQHiv6rF3g+yDDDMDU8Z+r6j1+RwS+nmkVWZs7jxKSWiFl8Tf7O0xvHyW0/3k21gK3X/iLh+kCkP6VSHtfjnVAut593WZ2dVNvd6VdvcDBVnxLXqr8JH6wO0PdAP6HzkpR+xC+gH9/M8XmAMba8va0Zj0eIQVckWIMg+2kyY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604531; c=relaxed/simple; bh=O/hm1gd2D2ZroA2MqIVSAhu2IbPtE3RppzDibS1Z2sI=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DgxHbPQdLfxje12w7SVxaQXXBjhcJt6/30FNadVlvwfK/ELHXtmkvUQmLz1kupqeoViPY+4uwJYgRtU0Kpdca3827XSxNaJypJFI0fLOlzXeC31V8aE5RSDxLjW1Y7jDTGE7wrQO2U5AVWieLcxCDh4+GcYBbxN/28KujAoixGE= 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.88.234]) by szxga06-in.huawei.com (SkyGuard) with ESMTP id 4WkCfj2q5lz1xv5G; Wed, 14 Aug 2024 11:00:13 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id A6DAE1402D0; Wed, 14 Aug 2024 11:02: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.39; Wed, 14 Aug 2024 11:02:03 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 2/9] landlock: Support TCP listen access-control Date: Wed, 14 Aug 2024 11:01:44 +0800 Message-ID: <20240814030151.2380280-3-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) LANDLOCK_ACCESS_NET_BIND_TCP is useful to limit the scope of "bindable" ports to forbid a malicious sandboxed process to impersonate a legitimate server process. However, bind(2) might be used by (TCP) clients to set the source port to a (legitimate) value. Controlling the ports that can be used for listening would allow (TCP) clients to explicitly bind to ports that are forbidden for listening. Such control is implemented with a new LANDLOCK_ACCESS_NET_LISTEN_TCP access right that restricts listening on undesired ports with listen(2). It's worth noticing that this access right doesn't affect changing backlog value using listen(2) on already listening socket. * Create new LANDLOCK_ACCESS_NET_LISTEN_TCP flag. * Add hook to socket_listen(), which checks whether the socket is allowed to listen on a binded local port. * Add check_tcp_socket_can_listen() helper, which validates socket attributes before the actual access right check. * Update `struct landlock_net_port_attr` documentation with control of binding to ephemeral port with listen(2) description. * Change ABI version to 6. Closes: https://github.com/landlock-lsm/linux/issues/15 Signed-off-by: Mikhail Ivanov --- Changes since v1: * Refactors 'struct landlock_net_port_attr' documentation. * Fixes check_tcp_socket_can_listen() description. * Adds lockdep_assert_held() into check_tcp_socket_can_listen(). * Minor fixes. --- include/uapi/linux/landlock.h | 26 ++++-- security/landlock/limits.h | 2 +- security/landlock/net.c | 98 ++++++++++++++++++++ security/landlock/syscalls.c | 2 +- tools/testing/selftests/landlock/base_test.c | 2 +- 5 files changed, 119 insertions(+), 11 deletions(-) diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index 2c8dbc74b955..f7dd6949c50b 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -111,14 +111,20 @@ struct landlock_net_port_attr { /** * @port: Network port in host endianness. * - * It should be noted that port 0 passed to :manpage:`bind(2)` will bind - * to an available port from the ephemeral port range. This can be - * configured with the ``/proc/sys/net/ipv4/ip_local_port_range`` sysctl - * (also used for IPv6). + * Some socket operations will fall back to using a port from the ephemeral port + * range, if no specific port is requested by the caller. Among others, this + * happens in the following cases: * - * A Landlock rule with port 0 and the ``LANDLOCK_ACCESS_NET_BIND_TCP`` - * right means that requesting to bind on port 0 is allowed and it will - * automatically translate to binding on the related port range. + * - :manpage:`bind(2)` is invoked with a socket address that uses port 0. + * - :manpage:`listen(2)` is invoked on a socket without previously calling + * :manpage:`bind(2)`. + * + * These two actions, which implicitly use an ephemeral port, can be allowed with + * a Landlock rule with port 0 and the ``LANDLOCK_ACCESS_NET_BIND_TCP`` / + * ``LANDLOCK_ACCESS_NET_LISTEN_TCP`` right. + * + * The ephemeral port range is configured in the + * ``/proc/sys/net/ipv4/ip_local_port_range`` sysctl (also used for IPv6). */ __u64 port; }; @@ -259,7 +265,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. @@ -269,9 +275,13 @@ struct landlock_net_port_attr { * - %LANDLOCK_ACCESS_NET_BIND_TCP: Bind a TCP socket to a local port. * - %LANDLOCK_ACCESS_NET_CONNECT_TCP: Connect an active TCP socket to * a remote port. + * - %LANDLOCK_ACCESS_NET_LISTEN_TCP: Listen for TCP socket connections on + * a local port. This access right is available since the sixth version + * of the Landlock ABI. */ /* clang-format off */ #define LANDLOCK_ACCESS_NET_BIND_TCP (1ULL << 0) #define LANDLOCK_ACCESS_NET_CONNECT_TCP (1ULL << 1) +#define LANDLOCK_ACCESS_NET_LISTEN_TCP (1ULL << 2) /* clang-format on */ #endif /* _UAPI_LINUX_LANDLOCK_H */ diff --git a/security/landlock/limits.h b/security/landlock/limits.h index 4eb643077a2a..2ef147389474 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -22,7 +22,7 @@ #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) -#define LANDLOCK_LAST_ACCESS_NET LANDLOCK_ACCESS_NET_CONNECT_TCP +#define LANDLOCK_LAST_ACCESS_NET LANDLOCK_ACCESS_NET_LISTEN_TCP #define LANDLOCK_MASK_ACCESS_NET ((LANDLOCK_LAST_ACCESS_NET << 1) - 1) #define LANDLOCK_NUM_ACCESS_NET __const_hweight64(LANDLOCK_MASK_ACCESS_NET) diff --git a/security/landlock/net.c b/security/landlock/net.c index 669ba260342f..0e494b46d086 100644 --- a/security/landlock/net.c +++ b/security/landlock/net.c @@ -6,10 +6,12 @@ * Copyright © 2022-2023 Microsoft Corporation */ +#include #include #include #include #include +#include #include "common.h" #include "cred.h" @@ -194,9 +196,105 @@ static int hook_socket_connect(struct socket *const sock, LANDLOCK_ACCESS_NET_CONNECT_TCP); } +/* + * Checks that socket state and attributes are correct for listen. + * Returns 0 on success and -EINVAL otherwise. + * + * This checker requires sock->sk to be locked. + */ +static int check_tcp_socket_can_listen(struct socket *const sock) +{ + struct sock *sk = sock->sk; + unsigned char cur_sk_state; + const struct tcp_ulp_ops *icsk_ulp_ops; + + lockdep_assert_held(&sk->sk_lock.slock); + + /* Allows only unconnected TCP socket to listen (cf. inet_listen). */ + if (sock->state != SS_UNCONNECTED) + return -EINVAL; + + cur_sk_state = sk->sk_state; + /* + * Checks sock state. This is needed to ensure consistency with inet stack + * error handling (cf. __inet_listen_sk). + */ + if (WARN_ON_ONCE(!((1 << cur_sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))) + return -EINVAL; + + icsk_ulp_ops = inet_csk(sk)->icsk_ulp_ops; + + /* + * ULP (Upper Layer Protocol) stands for protocols which are higher than + * transport protocol in OSI model. Linux has an infrastructure that + * allows TCP sockets to support logic of some ULP (e.g. TLS ULP). + * + * Sockets can listen only if ULP control hook has clone method + * (cf. inet_csk_listen_start) + */ + if (icsk_ulp_ops && !icsk_ulp_ops->clone) + return -EINVAL; + return 0; +} + +static int hook_socket_listen(struct socket *const sock, const int backlog) +{ + int err = 0; + int family; + __be16 port; + struct sock *sk; + const struct landlock_ruleset *const dom = get_current_net_domain(); + + if (!dom) + return 0; + if (WARN_ON_ONCE(dom->num_layers < 1)) + return -EACCES; + + /* Checks if it's a (potential) TCP socket. */ + if (sock->type != SOCK_STREAM) + return 0; + + sk = sock->sk; + family = sk->__sk_common.skc_family; + /* + * Socket cannot be assigned AF_UNSPEC because this type is used only + * in the context of addresses. + * + * Doesn't restrict listening for non-TCP sockets. + */ + if (family != AF_INET && family != AF_INET6) + return 0; + + lock_sock(sk); + /* + * Calling listen(2) for a listening socket does nothing with its state and + * only changes backlog value (cf. __inet_listen_sk). Checking of listen + * access right is not required. + */ + if (sk->sk_state == TCP_LISTEN) + goto release_nocheck; + + /* + * Checks socket state to not wrongfully return -EACCES instead + * of -EINVAL. + */ + err = check_tcp_socket_can_listen(sock); + if (unlikely(err)) + goto release_nocheck; + + port = htons(inet_sk(sk)->inet_num); + release_sock(sk); + return check_access_socket(dom, port, LANDLOCK_ACCESS_NET_LISTEN_TCP); + +release_nocheck: + release_sock(sk); + return err; +} + static struct security_hook_list landlock_hooks[] __ro_after_init = { LSM_HOOK_INIT(socket_bind, hook_socket_bind), LSM_HOOK_INIT(socket_connect, hook_socket_connect), + LSM_HOOK_INIT(socket_listen, hook_socket_listen), }; __init void landlock_add_net_hooks(void) diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index ccc8bc6c1584..328198e8a9f5 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -149,7 +149,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 diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c index 3b26bf3cf5b9..1bc16fde2e8a 100644 --- a/tools/testing/selftests/landlock/base_test.c +++ b/tools/testing/selftests/landlock/base_test.c @@ -76,7 +76,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 Wed Aug 14 03:01:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762785 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 E16E2B679; Wed, 14 Aug 2024 03:02:09 +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=1723604533; cv=none; b=G9rbjr+XAhuMymxSReLYuokzKDIsVRzCvO8Zhvo5Gwbs/DJQSemEUyIoM53qiwrJ8ngjP2KCHt4bRcCHPmoAsIU2Qt16FyhiAltM1t9GIYTqcCKKeXUr3COBu2NXKjw2Nge+gGgGf5xL4XpSJl17gGGcZm1jlKgg8kM9Wr1GUEM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604533; c=relaxed/simple; bh=LN9sJF1ELuFamW2XwjLNaIq9pF5WelaQTpeGs6NP4RA=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Nm+D0Wm7YW1k8VjzUZRWf+lZYtS3w07GUUVVrNaBTxEYyxM0I/Z5VbnGs7gtbnwCSTlseqmP7bcKTppTjLMilvt65CbhYiz4i+/g63X6RQLEviyOxW2JxiN8bR0MSiveyaOjWCFN54TTyg6ebIWn2qHIfv6HN02Jp7sd3q3r8co= 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.17]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4WkCbc6BNZz20lcW; Wed, 14 Aug 2024 10:57:32 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 7858F1A0188; Wed, 14 Aug 2024 11:02:06 +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.39; Wed, 14 Aug 2024 11:02:04 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 3/9] selftests/landlock: Support LANDLOCK_ACCESS_NET_LISTEN_TCP Date: Wed, 14 Aug 2024 11:01:45 +0800 Message-ID: <20240814030151.2380280-4-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) * Add listen_variant() to simplify listen(2) return code checking. * Rename test_bind_and_connect() to test_restricted_net_fixture(). * Extend current net rules with LANDLOCK_ACCESS_NET_LISTEN_TCP access. * Rename test port_specific.bind_connect_1023 to port_specific.port_1023. * Check little endian port restriction for listen in ipv4_tcp.port_endianness. * Some local renames and comment changes. Signed-off-by: Mikhail Ivanov --- tools/testing/selftests/landlock/net_test.c | 198 +++++++++++--------- 1 file changed, 107 insertions(+), 91 deletions(-) diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index f21cfbbc3638..8126f5c0160f 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -2,7 +2,7 @@ /* * Landlock tests - Network * - * Copyright © 2022-2023 Huawei Tech. Co., Ltd. + * Copyright © 2022-2024 Huawei Tech. Co., Ltd. * Copyright © 2023 Microsoft Corporation */ @@ -22,6 +22,17 @@ #include "common.h" +/* clang-format off */ + +#define ACCESS_LAST LANDLOCK_ACCESS_NET_LISTEN_TCP + +#define ACCESS_ALL ( \ + LANDLOCK_ACCESS_NET_BIND_TCP | \ + LANDLOCK_ACCESS_NET_CONNECT_TCP | \ + LANDLOCK_ACCESS_NET_LISTEN_TCP) + +/* clang-format on */ + const short sock_port_start = (1 << 10); static const char loopback_ipv4[] = "127.0.0.1"; @@ -282,6 +293,16 @@ static int connect_variant(const int sock_fd, return connect_variant_addrlen(sock_fd, srv, get_addrlen(srv, false)); } +static int listen_variant(const int sock_fd, const int backlog) +{ + int ret; + + ret = listen(sock_fd, backlog); + if (ret < 0) + return -errno; + return ret; +} + FIXTURE(protocol) { struct service_fixture srv0, srv1, srv2, unspec_any0, unspec_srv0; @@ -438,9 +459,11 @@ FIXTURE_VARIANT_ADD(protocol, tcp_sandbox_with_unix_datagram) { }, }; -static void test_bind_and_connect(struct __test_metadata *const _metadata, - const struct service_fixture *const srv, - const bool deny_bind, const bool deny_connect) +static void test_restricted_net_fixture(struct __test_metadata *const _metadata, + const struct service_fixture *const srv, + const bool deny_bind, + const bool deny_connect, + const bool deny_listen) { char buf = '\0'; int inval_fd, bind_fd, client_fd, status, ret; @@ -512,8 +535,14 @@ static void test_bind_and_connect(struct __test_metadata *const _metadata, EXPECT_EQ(0, ret); /* Creates a listening socket. */ - if (srv->protocol.type == SOCK_STREAM) - EXPECT_EQ(0, listen(bind_fd, backlog)); + if (srv->protocol.type == SOCK_STREAM) { + ret = listen_variant(bind_fd, backlog); + if (deny_listen) { + EXPECT_EQ(-EACCES, ret); + } else { + EXPECT_EQ(0, ret); + } + } } child = fork(); @@ -530,7 +559,7 @@ static void test_bind_and_connect(struct __test_metadata *const _metadata, ret = connect_variant(connect_fd, srv); if (deny_connect) { EXPECT_EQ(-EACCES, ret); - } else if (deny_bind) { + } else if (deny_bind || deny_listen) { /* No listening server. */ EXPECT_EQ(-ECONNREFUSED, ret); } else { @@ -545,7 +574,7 @@ static void test_bind_and_connect(struct __test_metadata *const _metadata, /* Accepts connection from the child. */ client_fd = bind_fd; - if (!deny_bind && !deny_connect) { + if (!deny_bind && !deny_connect && !deny_listen) { if (srv->protocol.type == SOCK_STREAM) { client_fd = accept(bind_fd, NULL, 0); ASSERT_LE(0, client_fd); @@ -571,16 +600,15 @@ TEST_F(protocol, bind) { if (variant->sandbox == TCP_SANDBOX) { const struct landlock_ruleset_attr ruleset_attr = { - .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + .handled_access_net = ACCESS_ALL, }; - const struct landlock_net_port_attr tcp_bind_connect_p0 = { - .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + const struct landlock_net_port_attr tcp_not_restricted_p0 = { + .allowed_access = ACCESS_ALL, .port = self->srv0.port, }; - const struct landlock_net_port_attr tcp_connect_p1 = { - .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP, + const struct landlock_net_port_attr tcp_denied_bind_p1 = { + .allowed_access = ACCESS_ALL & + ~LANDLOCK_ACCESS_NET_BIND_TCP, .port = self->srv1.port, }; int ruleset_fd; @@ -589,48 +617,47 @@ TEST_F(protocol, bind) sizeof(ruleset_attr), 0); ASSERT_LE(0, ruleset_fd); - /* Allows connect and bind for the first port. */ + /* Allows all actions for the first port. */ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &tcp_bind_connect_p0, 0)); + &tcp_not_restricted_p0, 0)); - /* Allows connect and denies bind for the second port. */ + /* Allows all actions despite bind. */ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &tcp_connect_p1, 0)); + &tcp_denied_bind_p1, 0)); enforce_ruleset(_metadata, ruleset_fd); EXPECT_EQ(0, close(ruleset_fd)); } + bool restricted = is_restricted(&variant->prot, variant->sandbox); /* Binds a socket to the first port. */ - test_bind_and_connect(_metadata, &self->srv0, false, false); + test_restricted_net_fixture(_metadata, &self->srv0, false, false, + false); /* Binds a socket to the second port. */ - test_bind_and_connect(_metadata, &self->srv1, - is_restricted(&variant->prot, variant->sandbox), - false); + test_restricted_net_fixture(_metadata, &self->srv1, restricted, false, + false); /* Binds a socket to the third port. */ - test_bind_and_connect(_metadata, &self->srv2, - is_restricted(&variant->prot, variant->sandbox), - is_restricted(&variant->prot, variant->sandbox)); + test_restricted_net_fixture(_metadata, &self->srv2, restricted, + restricted, restricted); } TEST_F(protocol, connect) { if (variant->sandbox == TCP_SANDBOX) { const struct landlock_ruleset_attr ruleset_attr = { - .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + .handled_access_net = ACCESS_ALL, }; - const struct landlock_net_port_attr tcp_bind_connect_p0 = { - .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + const struct landlock_net_port_attr tcp_not_restricted_p0 = { + .allowed_access = ACCESS_ALL, .port = self->srv0.port, }; - const struct landlock_net_port_attr tcp_bind_p1 = { - .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, + const struct landlock_net_port_attr tcp_denied_connect_p1 = { + .allowed_access = ACCESS_ALL & + ~LANDLOCK_ACCESS_NET_CONNECT_TCP, .port = self->srv1.port, }; int ruleset_fd; @@ -639,28 +666,27 @@ TEST_F(protocol, connect) sizeof(ruleset_attr), 0); ASSERT_LE(0, ruleset_fd); - /* Allows connect and bind for the first port. */ + /* Allows all actions for the first port. */ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &tcp_bind_connect_p0, 0)); + &tcp_not_restricted_p0, 0)); - /* Allows bind and denies connect for the second port. */ + /* Allows all actions despite connect. */ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &tcp_bind_p1, 0)); + &tcp_denied_connect_p1, 0)); enforce_ruleset(_metadata, ruleset_fd); EXPECT_EQ(0, close(ruleset_fd)); } - - test_bind_and_connect(_metadata, &self->srv0, false, false); - - test_bind_and_connect(_metadata, &self->srv1, false, - is_restricted(&variant->prot, variant->sandbox)); - - test_bind_and_connect(_metadata, &self->srv2, - is_restricted(&variant->prot, variant->sandbox), - is_restricted(&variant->prot, variant->sandbox)); + bool restricted = is_restricted(&variant->prot, variant->sandbox); + + test_restricted_net_fixture(_metadata, &self->srv0, false, false, + false); + test_restricted_net_fixture(_metadata, &self->srv1, false, restricted, + false); + test_restricted_net_fixture(_metadata, &self->srv2, restricted, + restricted, restricted); } TEST_F(protocol, bind_unspec) @@ -761,7 +787,7 @@ TEST_F(protocol, connect_unspec) ASSERT_LE(0, bind_fd); EXPECT_EQ(0, bind_variant(bind_fd, &self->srv0)); if (self->srv0.protocol.type == SOCK_STREAM) - EXPECT_EQ(0, listen(bind_fd, backlog)); + EXPECT_EQ(0, listen_variant(bind_fd, backlog)); child = fork(); ASSERT_LE(0, child); @@ -1127,8 +1153,8 @@ TEST_F(tcp_layers, ruleset_overlap) * Forbids to connect to the socket because only one ruleset layer * allows connect. */ - test_bind_and_connect(_metadata, &self->srv0, false, - variant->num_layers >= 2); + test_restricted_net_fixture(_metadata, &self->srv0, false, + variant->num_layers >= 2, false); } TEST_F(tcp_layers, ruleset_expand) @@ -1208,11 +1234,12 @@ TEST_F(tcp_layers, ruleset_expand) EXPECT_EQ(0, close(ruleset_fd)); } - test_bind_and_connect(_metadata, &self->srv0, false, - variant->num_layers >= 3); + test_restricted_net_fixture(_metadata, &self->srv0, false, + variant->num_layers >= 3, false); - test_bind_and_connect(_metadata, &self->srv1, variant->num_layers >= 1, - variant->num_layers >= 2); + test_restricted_net_fixture(_metadata, &self->srv1, + variant->num_layers >= 1, + variant->num_layers >= 2, false); } /* clang-format off */ @@ -1230,16 +1257,6 @@ FIXTURE_TEARDOWN(mini) { } -/* clang-format off */ - -#define ACCESS_LAST LANDLOCK_ACCESS_NET_CONNECT_TCP - -#define ACCESS_ALL ( \ - LANDLOCK_ACCESS_NET_BIND_TCP | \ - LANDLOCK_ACCESS_NET_CONNECT_TCP) - -/* clang-format on */ - TEST_F(mini, network_access_rights) { const struct landlock_ruleset_attr ruleset_attr = { @@ -1454,8 +1471,9 @@ TEST_F(mini, tcp_port_overflow) enforce_ruleset(_metadata, ruleset_fd); - test_bind_and_connect(_metadata, &srv_denied, true, true); - test_bind_and_connect(_metadata, &srv_max_allowed, false, false); + test_restricted_net_fixture(_metadata, &srv_denied, true, true, false); + test_restricted_net_fixture(_metadata, &srv_max_allowed, false, false, + false); } FIXTURE(ipv4_tcp) @@ -1485,22 +1503,21 @@ FIXTURE_TEARDOWN(ipv4_tcp) TEST_F(ipv4_tcp, port_endianness) { const struct landlock_ruleset_attr ruleset_attr = { - .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + .handled_access_net = ACCESS_ALL, }; const struct landlock_net_port_attr bind_host_endian_p0 = { .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP, /* Host port format. */ .port = self->srv0.port, }; - const struct landlock_net_port_attr connect_big_endian_p0 = { - .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP, + const struct landlock_net_port_attr connect_listen_big_endian_p0 = { + .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP | + LANDLOCK_ACCESS_NET_LISTEN_TCP, /* Big endian port format. */ .port = htons(self->srv0.port), }; - const struct landlock_net_port_attr bind_connect_host_endian_p1 = { - .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + const struct landlock_net_port_attr not_restricted_host_endian_p1 = { + .allowed_access = ACCESS_ALL, /* Host port format. */ .port = self->srv1.port, }; @@ -1514,16 +1531,18 @@ TEST_F(ipv4_tcp, port_endianness) ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, &bind_host_endian_p0, 0)); ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &connect_big_endian_p0, 0)); + &connect_listen_big_endian_p0, 0)); ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &bind_connect_host_endian_p1, 0)); + ¬_restricted_host_endian_p1, 0)); enforce_ruleset(_metadata, ruleset_fd); /* No restriction for big endinan CPU. */ - test_bind_and_connect(_metadata, &self->srv0, false, little_endian); + test_restricted_net_fixture(_metadata, &self->srv0, false, + little_endian, little_endian); /* No restriction for any CPU. */ - test_bind_and_connect(_metadata, &self->srv1, false, false); + test_restricted_net_fixture(_metadata, &self->srv1, false, false, + false); } TEST_F(ipv4_tcp, with_fs) @@ -1691,7 +1710,7 @@ TEST_F(port_specific, bind_connect_zero) ret = bind_variant(bind_fd, &self->srv0); EXPECT_EQ(0, ret); - EXPECT_EQ(0, listen(bind_fd, backlog)); + EXPECT_EQ(0, listen_variant(bind_fd, backlog)); /* Connects on port 0. */ ret = connect_variant(connect_fd, &self->srv0); @@ -1714,26 +1733,23 @@ TEST_F(port_specific, bind_connect_zero) EXPECT_EQ(0, close(bind_fd)); } -TEST_F(port_specific, bind_connect_1023) +TEST_F(port_specific, port_1023) { int bind_fd, connect_fd, ret; - /* Adds a rule layer with bind and connect actions. */ + /* Adds a rule layer with all actions. */ if (variant->sandbox == TCP_SANDBOX) { const struct landlock_ruleset_attr ruleset_attr = { - .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP + .handled_access_net = ACCESS_ALL }; /* A rule with port value less than 1024. */ - const struct landlock_net_port_attr tcp_bind_connect_low_range = { - .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + const struct landlock_net_port_attr tcp_low_range_port = { + .allowed_access = ACCESS_ALL, .port = 1023, }; /* A rule with 1024 port. */ - const struct landlock_net_port_attr tcp_bind_connect = { - .allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + const struct landlock_net_port_attr tcp_port_1024 = { + .allowed_access = ACCESS_ALL, .port = 1024, }; int ruleset_fd; @@ -1744,10 +1760,10 @@ TEST_F(port_specific, bind_connect_1023) ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &tcp_bind_connect_low_range, 0)); + &tcp_low_range_port, 0)); ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, - &tcp_bind_connect, 0)); + &tcp_port_1024, 0)); enforce_ruleset(_metadata, ruleset_fd); EXPECT_EQ(0, close(ruleset_fd)); @@ -1771,7 +1787,7 @@ TEST_F(port_specific, bind_connect_1023) ret = bind_variant(bind_fd, &self->srv0); clear_cap(_metadata, CAP_NET_BIND_SERVICE); EXPECT_EQ(0, ret); - EXPECT_EQ(0, listen(bind_fd, backlog)); + EXPECT_EQ(0, listen_variant(bind_fd, backlog)); /* Connects on the binded port 1023. */ ret = connect_variant(connect_fd, &self->srv0); @@ -1791,7 +1807,7 @@ TEST_F(port_specific, bind_connect_1023) /* Binds on port 1024. */ ret = bind_variant(bind_fd, &self->srv0); EXPECT_EQ(0, ret); - EXPECT_EQ(0, listen(bind_fd, backlog)); + EXPECT_EQ(0, listen_variant(bind_fd, backlog)); /* Connects on the binded port 1024. */ ret = connect_variant(connect_fd, &self->srv0); From patchwork Wed Aug 14 03:01:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762784 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 DFF598485; Wed, 14 Aug 2024 03:02:09 +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=1723604532; cv=none; b=jaILJno+Hd82RsMs2o+X/zGgSw7fBA4BxHd/n/Y70daGcFg4RWAqpBKyi+Jcn5qntZSUC2GJG04sS+rQYcTFzgLhWeJwiUT7Wj6in+uA7EETMLFdlnPVh35wX0BGPC5zw8fvNACIwbEJ1Oon3qp22UO1wYVd2ukqJLK0rSoS0Tw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604532; c=relaxed/simple; bh=T1d68LYJQ5PF2V9H1ruSPor7SPuyYu1pjOYSMUxNP3E=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=aleYE/U4Y1zTs9v0x8meB5zydh5TFASX+9oV2OxwaypRDQ9IUhkXqemLkNj8pPVJLaE4O5y3l+IesJYJfHf2moShiD18cGkuG1HYO0bYT3/4c6feuetfZKmjH1fI8/SiG6cg7tBIO+dRVGcrkHRqsRpxGNkJ4ctnO3dx+ksDGVU= 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 4WkCbf3v9xz20l6c; Wed, 14 Aug 2024 10:57:34 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 2A5531402CF; Wed, 14 Aug 2024 11:02: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.39; Wed, 14 Aug 2024 11:02:06 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 4/9] selftests/landlock: Test listening restriction Date: Wed, 14 Aug 2024 11:01:46 +0800 Message-ID: <20240814030151.2380280-5-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) Add a test for listening restriction. It's similar to protocol.bind and protocol.connect tests. Signed-off-by: Mikhail Ivanov --- tools/testing/selftests/landlock/net_test.c | 44 +++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 8126f5c0160f..b6fe9bde205f 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -689,6 +689,50 @@ TEST_F(protocol, connect) restricted, restricted); } +TEST_F(protocol, listen) +{ + if (variant->sandbox == TCP_SANDBOX) { + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = ACCESS_ALL, + }; + const struct landlock_net_port_attr tcp_not_restricted_p0 = { + .allowed_access = ACCESS_ALL, + .port = self->srv0.port, + }; + const struct landlock_net_port_attr tcp_denied_listen_p1 = { + .allowed_access = ACCESS_ALL & + ~LANDLOCK_ACCESS_NET_LISTEN_TCP, + .port = self->srv1.port, + }; + int ruleset_fd; + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Allows all actions for the first port. */ + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, + &tcp_not_restricted_p0, 0)); + + /* Allows all actions despite listen. */ + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, + &tcp_denied_listen_p1, 0)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + bool restricted = is_restricted(&variant->prot, variant->sandbox); + + test_restricted_net_fixture(_metadata, &self->srv0, false, false, + false); + test_restricted_net_fixture(_metadata, &self->srv1, false, false, + restricted); + test_restricted_net_fixture(_metadata, &self->srv2, restricted, + restricted, restricted); +} + TEST_F(protocol, bind_unspec) { const struct landlock_ruleset_attr ruleset_attr = { From patchwork Wed Aug 14 03:01:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762788 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 BECD61CAA2; Wed, 14 Aug 2024 03:02:11 +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=1723604533; cv=none; b=Qqdpf+dKClUqToE1DVWuFVNovmbRypk2/rZtJPVOjecDHREUZGD9Hvs0uVf80dfJT5BaemnhaiF0z/3W1u1UazCzuGBaFpE3k6MAw/wLsrD6pyA8W2HWFEFjfh3ttfnAciRAU2lMyVJMSd1L3rim0QHp1Puyp23sFufHO+Rj7Ec= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604533; c=relaxed/simple; bh=wtB0l5FobLp8sTKRHYLuJrJAFDakL8hq6JSqlFDJAMo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Y5QhUIxmfAY+ngWSlM+pGs2h85kPfrg+mGOsFliuT6ZE0iHDVl9ZT60YAPiKPnnIRTHQuevWeGpyt9a9zmEwQ/t155EzOKA/7dpKX3Mr9hpsdkHqGRbTO8x92QW4hAFL8wPia/lHxp29VXh5r237fSkiyYwVGqC8N880lPqxx74= 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.88.214]) by szxga06-in.huawei.com (SkyGuard) with ESMTP id 4WkCfp3tVZz1xtxV; Wed, 14 Aug 2024 11:00:18 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id CB5C21A016C; Wed, 14 Aug 2024 11:02:09 +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.39; Wed, 14 Aug 2024 11:02:08 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 5/9] selftests/landlock: Test listen on connected socket Date: Wed, 14 Aug 2024 11:01:47 +0800 Message-ID: <20240814030151.2380280-6-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) Test checks that listen(2) doesn't wrongfully return -EACCES instead of -EINVAL when trying to listen for an incorrect socket state. Signed-off-by: Mikhail Ivanov --- Changes since v1: * Uses 'protocol' fixture instead of 'ipv4_tcp'. * Minor fixes. --- tools/testing/selftests/landlock/net_test.c | 74 +++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index b6fe9bde205f..551891b18b7a 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -926,6 +926,80 @@ TEST_F(protocol, connect_unspec) EXPECT_EQ(0, close(bind_fd)); } +TEST_F(protocol, listen_on_connected) +{ + int bind_fd, status; + pid_t child; + + if (variant->sandbox == TCP_SANDBOX) { + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = ACCESS_ALL, + }; + const struct landlock_net_port_attr tcp_not_restricted_p0 = { + .allowed_access = ACCESS_ALL, + .port = self->srv0.port, + }; + const struct landlock_net_port_attr tcp_denied_listen_p1 = { + .allowed_access = ACCESS_ALL & + ~LANDLOCK_ACCESS_NET_LISTEN_TCP, + .port = self->srv1.port, + }; + int ruleset_fd; + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Allows all actions for the first port. */ + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, + &tcp_not_restricted_p0, 0)); + + /* Denies listening for the second port. */ + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, + &tcp_denied_listen_p1, 0)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + + if (variant->prot.type != SOCK_STREAM) + SKIP(return, "listen(2) is supported only on stream sockets"); + + /* Initializes listening socket. */ + bind_fd = socket_variant(&self->srv0); + ASSERT_LE(0, bind_fd); + EXPECT_EQ(0, bind_variant(bind_fd, &self->srv0)); + EXPECT_EQ(0, listen_variant(bind_fd, backlog)); + + child = fork(); + ASSERT_LE(0, child); + if (child == 0) { + int connect_fd; + + /* Closes listening socket for the child. */ + EXPECT_EQ(0, close(bind_fd)); + + connect_fd = socket_variant(&self->srv1); + ASSERT_LE(0, connect_fd); + EXPECT_EQ(0, connect_variant(connect_fd, &self->srv0)); + + /* Tries to listen on connected socket. */ + EXPECT_EQ(-EINVAL, listen_variant(connect_fd, backlog)); + + EXPECT_EQ(0, close(connect_fd)); + _exit(_metadata->exit_code); + return; + } + + EXPECT_EQ(child, waitpid(child, &status, 0)); + EXPECT_EQ(1, WIFEXITED(status)); + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + EXPECT_EQ(0, close(bind_fd)); +} + FIXTURE(ipv4) { struct service_fixture srv0, srv1; From patchwork Wed Aug 14 03:01:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762789 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 B4EE040BE3; Wed, 14 Aug 2024 03:02:13 +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=1723604536; cv=none; b=GSxnw9V/UUuXeRceLmaF+3pRVbMTquzjPKRxHdnlfPq7YZrKgCWHRl0+ko9nbu2fLKHt1Boo1zueLQ/TrEyK/xdQ1vt0WqoO1hnNIT7X48GkxJegBnFXSEIplQGTJB5ZXHJXWz0kKGQTLkgmNUTzRvVZxjz9+e3g1O36xs2UkOU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604536; c=relaxed/simple; bh=GrhKCdnJINFmspjPP/fFpu1cJ1YsXlM3RtcOjdhPYm4=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=jrlxDNScDb9CFfqc9kfT4nUb44Eo8YsDh+Kg2aZP3L6Q1L/K/TQjjQYMR0sPv0RvT7aIdbp1jry+HG6iVdKrh1H4rrcc12CnpIjVOTl3agM4Ueia8KR+GSGZcAX93Ten1eDEpZiZrVcbdAzNAEgMM3+60lvhxBmPc9P1m4+Ahq0= 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.163.252]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4WkCgR2PJbzndvm; Wed, 14 Aug 2024 11:00:51 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 969201800A0; Wed, 14 Aug 2024 11:02:11 +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.39; Wed, 14 Aug 2024 11:02:09 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 6/9] selftests/landlock: Test listening without explicit bind restriction Date: Wed, 14 Aug 2024 11:01:48 +0800 Message-ID: <20240814030151.2380280-7-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) Test scenarios where listen(2) call without explicit bind(2) is allowed and forbidden. Signed-off-by: Mikhail Ivanov --- tools/testing/selftests/landlock/net_test.c | 83 +++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 551891b18b7a..92c042349596 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -1851,6 +1851,89 @@ TEST_F(port_specific, bind_connect_zero) EXPECT_EQ(0, close(bind_fd)); } +TEST_F(port_specific, listen_without_bind_allowed) +{ + if (variant->sandbox == TCP_SANDBOX) { + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | + LANDLOCK_ACCESS_NET_LISTEN_TCP + }; + const struct landlock_net_port_attr tcp_listen_zero = { + .allowed_access = LANDLOCK_ACCESS_NET_LISTEN_TCP, + .port = 0, + }; + int ruleset_fd; + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* + * Allow listening without explicit bind + * (cf. landlock_net_port_attr). + */ + EXPECT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, + &tcp_listen_zero, 0)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + int listen_fd, connect_fd; + __u64 port; + + listen_fd = socket_variant(&self->srv0); + ASSERT_LE(0, listen_fd); + + connect_fd = socket_variant(&self->srv0); + ASSERT_LE(0, connect_fd); + /* + * Allow listen(2) to select a random port for the socket, + * since bind(2) wasn't called. + */ + EXPECT_EQ(0, listen_variant(listen_fd, backlog)); + + /* Connects on the binded port. */ + port = get_binded_port(listen_fd, &variant->prot); + EXPECT_NE(0, port); + set_port(&self->srv0, port); + EXPECT_EQ(0, connect_variant(connect_fd, &self->srv0)); + + EXPECT_EQ(0, close(connect_fd)); + EXPECT_EQ(0, close(listen_fd)); +} + +TEST_F(port_specific, listen_without_bind_denied) +{ + if (variant->sandbox == TCP_SANDBOX) { + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = LANDLOCK_ACCESS_NET_LISTEN_TCP + }; + int ruleset_fd; + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Deny listening. */ + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + int listen_fd, ret; + + listen_fd = socket_variant(&self->srv0); + ASSERT_LE(0, listen_fd); + + /* Checks that listening without explicit binding is prohibited. */ + ret = listen_variant(listen_fd, backlog); + if (is_restricted(&variant->prot, variant->sandbox)) { + /* Denied by Landlock. */ + EXPECT_EQ(-EACCES, ret); + } else { + EXPECT_EQ(0, ret); + } +} + TEST_F(port_specific, port_1023) { int bind_fd, connect_fd, ret; From patchwork Wed Aug 14 03:01:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762790 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 4C2401CAA2; Wed, 14 Aug 2024 03:02:15 +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=1723604537; cv=none; b=mOCLiJ7FnTgYQAODe8vkdB3RlNG8iym8Y1RiaFELnpbVM74KPwvuWcniUOwRGHbkyTRSRrj/7BkpLVNj0fqKb85ho2GUIq8+9biW6zCxjKAka+6sjSRD0DUBuGaiiOr4chZdf4DRfYPVgyzj++9jrz946rOo/yeooKiLzYFE4Ns= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604537; c=relaxed/simple; bh=Uq4vzzgadJB20TaRLv6mrGvs5NXdbdW6AOn2E7X585s=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=l0wa9+Sj0tWzIppBNaAunUH5XbYSOBFfvbBUZe+jZpV7fr+7ReBIs0X9hMqyeCId2oGWjOfPJH9BooL4gDVnzgBk5f41umDBN+tdopmjvXAtFUDARJkNAmiu+PsblYbb7UQ37QEoaQuBF1PPiWypwpHCUi1DLtHF3e5IFL06VRY= 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.163.252]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4WkCgT0P8YzndvW; Wed, 14 Aug 2024 11:00:53 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id 502EB1800A0; Wed, 14 Aug 2024 11:02: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.39; Wed, 14 Aug 2024 11:02:11 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 7/9] selftests/landlock: Test listen on ULP socket without clone method Date: Wed, 14 Aug 2024 11:01:49 +0800 Message-ID: <20240814030151.2380280-8-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) Test checks that listen(2) doesn't wrongfully return -EACCES instead of -EINVAL when trying to listen on a socket which is set to ULP that doesn't have clone method in inet_csk(sk)->icsk_ulp_ops (espintcp). Signed-off-by: Mikhail Ivanov --- Changes since v1: * Uses 'protocol' fixture instead of 'ipv4_tcp'. * Adds missing CONFIG_INET_ESP dependency in config. --- tools/testing/selftests/landlock/config | 4 ++ tools/testing/selftests/landlock/net_test.c | 50 +++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/tools/testing/selftests/landlock/config b/tools/testing/selftests/landlock/config index 29af19c4e9f9..72de73d1ee4c 100644 --- a/tools/testing/selftests/landlock/config +++ b/tools/testing/selftests/landlock/config @@ -1,7 +1,11 @@ CONFIG_CGROUPS=y CONFIG_CGROUP_SCHED=y CONFIG_INET=y +CONFIG_INET_ESPINTCP=y +CONFIG_INET_ESP=y CONFIG_IPV6=y +CONFIG_INET6_ESPINTCP=y +CONFIG_INET6_ESP=y CONFIG_KEYS=y CONFIG_NET=y CONFIG_NET_NS=y diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 92c042349596..6831d8a2e9aa 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1000,6 +1001,55 @@ TEST_F(protocol, listen_on_connected) EXPECT_EQ(0, close(bind_fd)); } +TEST_F(protocol, espintcp_listen) +{ + int listen_fd; + int domain, type; + + if (variant->sandbox == TCP_SANDBOX) { + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = ACCESS_ALL, + }; + const struct landlock_net_port_attr tcp_denied_listen_p0 = { + .allowed_access = ACCESS_ALL & + ~LANDLOCK_ACCESS_NET_LISTEN_TCP, + .port = self->srv0.port, + }; + int ruleset_fd; + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Deny listen. */ + ASSERT_EQ(0, + landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT, + &tcp_denied_listen_p0, 0)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + + domain = variant->prot.domain; + type = variant->prot.type; + + if (!((domain == AF_INET || domain == AF_INET6) && type == SOCK_STREAM)) + SKIP(return, "espintcp is available only for TCP socket"); + + listen_fd = socket_variant(&self->srv0); + ASSERT_LE(0, listen_fd); + + /* Set espintcp ULP. */ + EXPECT_EQ(0, setsockopt(listen_fd, IPPROTO_TCP, TCP_ULP, "espintcp", + sizeof("espintcp"))); + + EXPECT_EQ(0, bind_variant(listen_fd, &self->srv0)); + + /* Espintcp ULP doesn't have clone method, so listen is denied. */ + EXPECT_EQ(-EINVAL, listen_variant(listen_fd, backlog)); + EXPECT_EQ(0, close(listen_fd)); +} + FIXTURE(ipv4) { struct service_fixture srv0, srv1; From patchwork Wed Aug 14 03:01:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762791 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 0490D40BE3; Wed, 14 Aug 2024 03:02:16 +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=1723604538; cv=none; b=U0aezoDBNLwHx3QMgwqI0ZjiPRspfmIWlQvoyLt1OTuxJiCKUVdN4Fm/ZWwi7XexVzEKv0inkNM9guAlw5/ysVclj64uaSLruxOsL3TBOZebnkzo1PntVf8jkkupaNUDm++dVUypRonAU8gX11ghNavQy2XU/ylTn4u5yZ43kcE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604538; c=relaxed/simple; bh=QJX08E9MiyUp0svpjG6vnvcvpVK6qgbDgGd3UgCoiS0=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=UuyRJTvz0SMjyxpioEsSm29kzgvhFGpGHWZybOMqoWlTf5mP/1Gpbx+LogaYrDKo6BdibUDzhqHEoU64G5oAI7f89vIjZ1te/JFGfCJFnERbwffMrSqEWbC/2jQQY6emuI7al7COa1HEnzp1kxNiJ/y51wojIEPYHBXwZUw3OQ0= 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.163]) by szxga07-in.huawei.com (SkyGuard) with ESMTP id 4WkCbR05ySz1S7r5; Wed, 14 Aug 2024 10:57:23 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id E9970180019; Wed, 14 Aug 2024 11:02: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.39; Wed, 14 Aug 2024 11:02:13 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 8/9] selftests/landlock: Test changing socket backlog with listen(2) Date: Wed, 14 Aug 2024 11:01:50 +0800 Message-ID: <20240814030151.2380280-9-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) listen(2) can be used to change length of the pending connections queue of the listening socket. Such scenario shouldn't be restricted by Landlock since socket doesn't change its state. * Implement test that validates this case. Signed-off-by: Mikhail Ivanov --- tools/testing/selftests/landlock/net_test.c | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 6831d8a2e9aa..dafc433a0068 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -1768,6 +1768,32 @@ TEST_F(ipv4_tcp, with_fs) EXPECT_EQ(-EACCES, bind_variant(bind_fd, &self->srv1)); } +TEST_F(ipv4_tcp, double_listen) +{ + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = LANDLOCK_ACCESS_NET_LISTEN_TCP, + }; + int ruleset_fd; + int listen_fd; + + listen_fd = socket_variant(&self->srv0); + ASSERT_LE(0, listen_fd); + + EXPECT_EQ(0, bind_variant(listen_fd, &self->srv0)); + EXPECT_EQ(0, listen_variant(listen_fd, backlog)); + + ruleset_fd = + landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + /* Denies listen. */ + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + /* Tries to change backlog value of listening socket. */ + EXPECT_EQ(0, listen_variant(listen_fd, backlog + 1)); +} + FIXTURE(port_specific) { struct service_fixture srv0; From patchwork Wed Aug 14 03:01:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mikhail Ivanov X-Patchwork-Id: 13762792 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 618A9757F3; Wed, 14 Aug 2024 03:02:19 +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=1723604541; cv=none; b=pw5jb+zN4GbWyUZ0sdnFLg4NCdFEs8IUpLMMsWo9/2sRMpXQ522K0c6bz4z0huKKosl35uUcR2blQ/nH7EfGUA47YDeN+PRW+qgWJ/y3P5bxhavMfXu8gHNaFl/8HMn6onyOysAjCXkepxvm8Ze+R+GrkGSSYpIbl2WrQm6ChdY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1723604541; c=relaxed/simple; bh=rSiJD6CB325ZcboYhNJAZRZM+QHB/FdTNMAAaT83eAE=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LNmfNkBwGwmdSbvvBwZrjNYJzFULFvzAeE3E4u0+wmO9kbgoANry6iEtMeJr1760PDNcKSNzzsw1gFCR3ltl5w3YmdzWDUYb4HnuzAGjRA9LwbXValfHGSyTf2BRt55l8ylHJfaoVOZsmSS3q5D2DqYItW+tZd2lfvnyJDcs0XI= 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 4WkCbS5grKz1S7k1; Wed, 14 Aug 2024 10:57:24 +0800 (CST) Received: from dggpemm500020.china.huawei.com (unknown [7.185.36.49]) by mail.maildlp.com (Postfix) with ESMTPS id B461C1402CF; Wed, 14 Aug 2024 11:02: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.39; Wed, 14 Aug 2024 11:02:14 +0800 From: Mikhail Ivanov To: CC: , , , , , , , Subject: [RFC PATCH v2 9/9] samples/landlock: Support LANDLOCK_ACCESS_NET_LISTEN Date: Wed, 14 Aug 2024 11:01:51 +0800 Message-ID: <20240814030151.2380280-10-ivanov.mikhail1@huawei-partners.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240814030151.2380280-1-ivanov.mikhail1@huawei-partners.com> References: <20240814030151.2380280-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: mscpeml500004.china.huawei.com (7.188.26.250) To dggpemm500020.china.huawei.com (7.185.36.49) Extend sample with TCP listen control logic. Signed-off-by: Mikhail Ivanov --- samples/landlock/sandboxer.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c index e8223c3e781a..3f50cb3f8039 100644 --- a/samples/landlock/sandboxer.c +++ b/samples/landlock/sandboxer.c @@ -55,6 +55,7 @@ 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_TCP_LISTEN_NAME "LL_TCP_LISTEN" #define ENV_DELIMITER ":" static int parse_path(char *env_path, const char ***const path_list) @@ -208,7 +209,7 @@ 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) { @@ -222,15 +223,16 @@ int main(const int argc, char *const argv[], char *const *const envp) struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs = access_fs_rw, .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | - LANDLOCK_ACCESS_NET_CONNECT_TCP, + LANDLOCK_ACCESS_NET_CONNECT_TCP | + LANDLOCK_ACCESS_NET_LISTEN_TCP, }; 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_TCP_LISTEN_NAME, argv[0]); fprintf(stderr, "Execute a command in a restricted environment.\n\n"); fprintf(stderr, @@ -251,15 +253,19 @@ 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 ports allowed to listen (server).\n", + ENV_TCP_LISTEN_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=\"9418\" " "%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_TCP_LISTEN_NAME, argv[0]); fprintf(stderr, "This sandboxer can use Landlock features " "up to ABI version %d.\n", @@ -326,6 +332,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 LANDLOCK_ACCESS_NET_LISTEN support for ABI < 6 */ + ruleset_attr.handled_access_net &= + ~(LANDLOCK_ACCESS_NET_LISTEN_TCP); fprintf(stderr, "Hint: You should update the running kernel " @@ -357,6 +368,12 @@ int main(const int argc, char *const argv[], char *const *const envp) ruleset_attr.handled_access_net &= ~LANDLOCK_ACCESS_NET_CONNECT_TCP; } + /* Removes listen access attribute if not supported by a user. */ + env_port_name = getenv(ENV_TCP_LISTEN_NAME); + if (!env_port_name) { + ruleset_attr.handled_access_net &= + ~LANDLOCK_ACCESS_NET_LISTEN_TCP; + } ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); @@ -380,6 +397,10 @@ int main(const int argc, char *const argv[], char *const *const envp) LANDLOCK_ACCESS_NET_CONNECT_TCP)) { goto err_close_ruleset; } + if (populate_ruleset_net(ENV_TCP_LISTEN_NAME, ruleset_fd, + LANDLOCK_ACCESS_NET_LISTEN_TCP)) { + goto err_close_ruleset; + } if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("Failed to restrict privileges");