From: "Günther Noack" <gnoack@google.com>
To: Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com>
Cc: mic@digikod.net, willemdebruijn.kernel@gmail.com,
gnoack3000@gmail.com, linux-security-module@vger.kernel.org,
netdev@vger.kernel.org, netfilter-devel@vger.kernel.org,
yusongping@huawei.com, artem.kuzin@huawei.com,
konstantin.meskhidze@huawei.com
Subject: Re: [RFC PATCH v3 18/19] samples/landlock: Support socket protocol restrictions
Date: Tue, 1 Oct 2024 09:56:52 +0200 [thread overview]
Message-ID: <ZvurRJ4mGsRufmEl@google.com> (raw)
In-Reply-To: <20240904104824.1844082-19-ivanov.mikhail1@huawei-partners.com>
On Wed, Sep 04, 2024 at 06:48:23PM +0800, Mikhail Ivanov wrote:
> 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 and TYPE are integers corresponding to the
> number of address family and socket type.
>
> Add parse_socket_protocol() method to parse socket family and type
> strings into integers.
>
> Change LANDLOCK_ABI_LAST to 6.
>
> Signed-off-by: Mikhail Ivanov <ivanov.mikhail1@huawei-partners.com>
> ---
> Changes since v2:
> * Changes representation of socket protocol in LL_SOCKET_CREATE into
> pair of integer values.
> * Changes commit message.
> * Minor fixes.
>
> 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 | 108 ++++++++++++++++++++++++++++++-----
> 1 file changed, 95 insertions(+), 13 deletions(-)
>
> diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
> index d4dba9e4ce89..1669095f9373 100644
> --- a/samples/landlock/sandboxer.c
> +++ b/samples/landlock/sandboxer.c
> @@ -14,6 +14,7 @@
> #include <fcntl.h>
> #include <linux/landlock.h>
> #include <linux/prctl.h>
> +#include <linux/socket.h>
> #include <stddef.h>
> #include <stdio.h>
> #include <stdlib.h>
> @@ -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;
> @@ -209,6 +213,65 @@ 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;
> + unsigned long long family_ull, type_ull;
> + struct landlock_socket_attr protocol = {
> + .allowed_access = allowed_access,
> + };
> +
> + 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);
This works with strings such as "123:456:foobar", because you are using strsep()
twice on strprotocol; this looks unintentional?
> +
> + if (!strtype) {
> + fprintf(stderr,
> + "Failed to extract socket protocol with "
> + "unspecified type value\n");
> + goto out_free_name;
> + }
> +
> + if (str2num(strfamily, &family_ull)) {
> + fprintf(stderr,
> + "Failed to convert \"%s\" into a number\n",
> + strfamily);
> + goto out_free_name;
> + }
> + if (str2num(strtype, &type_ull)) {
> + fprintf(stderr,
> + "Failed to convert \"%s\" into a number\n",
> + strtype);
> + goto out_free_name;
> + }
> + protocol.family = (int)family_ull;
> + protocol.type = (int)type_ull;
> +
> + 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 ( \
> @@ -233,14 +296,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;
>
> @@ -248,18 +311,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 "
> "<cmd> [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",
> @@ -268,7 +332,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",
> @@ -276,15 +340,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 socket protocols allowed to be created.\n",
> + ENV_SOCKET_CREATE_NAME);
Might be worth listing some example values for this parameter, e.g. for TCP/IP
and UDP/IP? This is also needed to make it clear that these can't be given by
name, but only by number.
> 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=\"10.2:1.1\" "
> "%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",
> @@ -351,7 +419,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 "
> @@ -371,18 +443,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. */
Phrasing nit: I would say "requested by a user"?
(And maybe also in the two cases above)
> + 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) {
> @@ -406,6 +483,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;
> --
> 2.34.1
>
As I also said on the Documentation patch, please remember to double check the
places where the ABI number is mentioned, after rebasing on Tahera's "scoped"
patches.
—Günther
next prev parent reply other threads:[~2024-10-01 7:56 UTC|newest]
Thread overview: 76+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-09-04 10:48 [RFC PATCH v3 00/19] Support socket access-control Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 01/19] landlock: " Mikhail Ivanov
2024-09-06 13:09 ` Günther Noack
2024-09-09 7:23 ` Mikhail Ivanov
2024-11-11 16:29 ` Mikhail Ivanov
2024-11-22 17:45 ` Günther Noack
2024-11-25 11:04 ` Mikhail Ivanov
2024-11-27 18:43 ` Mickaël Salaün
2024-11-28 12:01 ` Mikhail Ivanov
2024-11-28 20:52 ` Mickaël Salaün
2024-12-02 11:32 ` Mikhail Ivanov
2024-12-24 16:55 ` Mikhail Ivanov
2025-01-10 11:12 ` Günther Noack
2025-01-10 13:02 ` Mikhail Ivanov
2025-01-10 16:27 ` Günther Noack
2025-01-10 16:55 ` Mikhail Ivanov
2025-01-14 18:31 ` Mickaël Salaün
2025-01-24 12:28 ` Mikhail Ivanov
2025-01-24 14:02 ` Mickaël Salaün
2024-09-04 10:48 ` [RFC PATCH v3 02/19] landlock: Add hook on socket creation Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 03/19] selftests/landlock: Test basic socket restriction Mikhail Ivanov
2024-09-10 9:53 ` Günther Noack
2024-09-04 10:48 ` [RFC PATCH v3 04/19] selftests/landlock: Test adding a rule with each supported access Mikhail Ivanov
2024-09-10 9:53 ` Günther Noack
2024-09-04 10:48 ` [RFC PATCH v3 05/19] selftests/landlock: Test adding a rule for each unknown access Mikhail Ivanov
2024-09-10 9:53 ` Günther Noack
2024-09-04 10:48 ` [RFC PATCH v3 06/19] selftests/landlock: Test adding a rule for unhandled access Mikhail Ivanov
2024-09-10 9:22 ` Günther Noack
2024-09-11 8:19 ` Mikhail Ivanov
2024-09-13 15:04 ` Günther Noack
2024-09-13 16:15 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 07/19] selftests/landlock: Test adding a rule for empty access Mikhail Ivanov
2024-09-18 12:42 ` Günther Noack
2024-09-18 13:03 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 08/19] selftests/landlock: Test overlapped restriction Mikhail Ivanov
2024-09-18 12:42 ` Günther Noack
2024-09-04 10:48 ` [RFC PATCH v3 09/19] selftests/landlock: Test creating a ruleset with unknown access Mikhail Ivanov
2024-09-18 12:44 ` Günther Noack
2024-09-04 10:48 ` [RFC PATCH v3 10/19] selftests/landlock: Test adding a rule with family and type outside the range Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 11/19] selftests/landlock: Test unsupported protocol restriction Mikhail Ivanov
2024-09-18 12:54 ` Günther Noack
2024-09-18 13:36 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 12/19] selftests/landlock: Test that kernel space sockets are not restricted Mikhail Ivanov
2024-09-04 12:45 ` Mikhail Ivanov
2024-09-18 13:00 ` Günther Noack
2024-09-19 10:53 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 13/19] selftests/landlock: Test packet protocol alias Mikhail Ivanov
2024-09-18 13:33 ` Günther Noack
2024-09-18 14:01 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 14/19] selftests/landlock: Test socketpair(2) restriction Mikhail Ivanov
2024-09-18 13:47 ` Günther Noack
2024-09-23 12:57 ` Mikhail Ivanov
2024-09-25 12:17 ` Mikhail Ivanov
2024-09-27 9:48 ` Günther Noack
2024-09-28 20:06 ` Günther Noack
2024-09-29 17:31 ` Mickaël Salaün
2024-10-03 17:27 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 15/19] selftests/landlock: Test SCTP peeloff restriction Mikhail Ivanov
2024-09-27 14:35 ` Günther Noack
2024-10-03 12:15 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 16/19] selftests/landlock: Test that accept(2) is not restricted Mikhail Ivanov
2024-09-27 14:53 ` Günther Noack
2024-10-03 12:41 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 17/19] samples/landlock: Replace atoi() with strtoull() in populate_ruleset_net() Mikhail Ivanov
2024-09-27 15:12 ` Günther Noack
2024-10-03 12:59 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 18/19] samples/landlock: Support socket protocol restrictions Mikhail Ivanov
2024-10-01 7:56 ` Günther Noack [this message]
2024-10-03 13:15 ` Mikhail Ivanov
2024-09-04 10:48 ` [RFC PATCH v3 19/19] landlock: Document socket rule type support Mikhail Ivanov
2024-10-01 7:09 ` Günther Noack
2024-10-03 14:00 ` Mikhail Ivanov
2024-10-03 16:21 ` Günther Noack
2025-04-22 17:19 ` [RFC PATCH v3 00/19] Support socket access-control Mickaël Salaün
2025-04-25 13:58 ` Günther Noack
2025-04-29 11:59 ` Mikhail Ivanov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ZvurRJ4mGsRufmEl@google.com \
--to=gnoack@google.com \
--cc=artem.kuzin@huawei.com \
--cc=gnoack3000@gmail.com \
--cc=ivanov.mikhail1@huawei-partners.com \
--cc=konstantin.meskhidze@huawei.com \
--cc=linux-security-module@vger.kernel.org \
--cc=mic@digikod.net \
--cc=netdev@vger.kernel.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=willemdebruijn.kernel@gmail.com \
--cc=yusongping@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).