From: Matthieu Buffet <matthieu@buffet.re>
To: "Mickaël Salaün" <mic@digikod.net>
Cc: "Günther Noack" <gnoack@google.com>,
"Konstantin Meskhidze" <konstantin.meskhidze@huawei.com>,
"Ivanov Mikhail" <ivanov.mikhail1@huawei-partners.com>,
linux-security-module@vger.kernel.org,
linux-kernel@vger.kernel.org,
"Matthieu Buffet" <matthieu@buffet.re>
Subject: [PATCH v2 1/3] samples/landlock: Fix port parsing in sandboxer
Date: Thu, 3 Oct 2024 02:50:40 +0200 [thread overview]
Message-ID: <20241003005042.258991-1-matthieu@buffet.re> (raw)
If you want to specify that no port can be bind()ed, you would think
(looking quickly at both help message and code) that setting LL_TCP_BIND=""
would do it.
However the code splits on ":" then applies atoi(), which does not allow
checking for errors. Passing an empty string returns 0, which is
interpreted as "allow bind(0)", which means bind to any ephemeral port.
This bug occurs whenever passing an empty string or when leaving a
trailing/leading colon, making it impossible to completely deny bind().
To reproduce:
export LL_FS_RO="/" LL_FS_RW="" LL_TCP_BIND=""
./sandboxer strace -e bind nc -n -vvv -l -p 0
Executing the sandboxed command...
bind(3, {sa_family=AF_INET, sin_port=htons(0),
sin_addr=inet_addr("0.0.0.0")}, 16) = 0
Listening on 0.0.0.0 37629
Use strtoul() instead, which allows error checking. Check that the entire
string has been parsed correctly without overflows/underflows.
Don't check that the __u64 (the type of struct landlock_net_port_attr.port)
is a valid __u16 port: that is already done by the kernel.
Two places check for an empty string, that is just to make the helper
function safer to use in the future.
Fixes: 5e990dcef12e ("samples/landlock: Support TCP restrictions")
Signed-off-by: Matthieu Buffet <matthieu@buffet.re>
---
samples/landlock/sandboxer.c | 37 ++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index f847e832ba14..aff5ef808e22 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -16,6 +16,7 @@
#include <linux/prctl.h>
#include <linux/socket.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -60,6 +61,29 @@ static inline int landlock_restrict_self(const int ruleset_fd,
#define ENV_SCOPED_NAME "LL_SCOPED"
#define ENV_DELIMITER ":"
+static int str2num(const char *numstr, __u64 *num_dst)
+{
+ char *endptr = NULL;
+ int err = 1;
+ __u64 num;
+
+ if (*numstr == '\0')
+ goto out;
+
+ errno = 0;
+ num = strtoull(numstr, &endptr, 10);
+ if (errno != 0)
+ goto out;
+
+ if (*endptr != '\0')
+ goto out;
+
+ *num_dst = num;
+ err = 0;
+out:
+ return err;
+}
+
static int parse_path(char *env_path, const char ***const path_list)
{
int i, num_paths = 0;
@@ -160,7 +184,6 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
char *env_port_name, *env_port_name_next, *strport;
struct landlock_net_port_attr net_port = {
.allowed_access = allowed_access,
- .port = 0,
};
env_port_name = getenv(env_var);
@@ -171,7 +194,17 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd,
env_port_name_next = env_port_name;
while ((strport = strsep(&env_port_name_next, ENV_DELIMITER))) {
- net_port.port = atoi(strport);
+ __u64 port;
+
+ if (strcmp(strport, "") == 0)
+ continue;
+
+ if (str2num(strport, &port)) {
+ fprintf(stderr,
+ "Failed to parse port at \"%s\"\n", strport);
+ goto out_free_name;
+ }
+ net_port.port = port;
if (landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
&net_port, 0)) {
fprintf(stderr,
--
2.39.2
next reply other threads:[~2024-10-03 0:49 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-03 0:50 Matthieu Buffet [this message]
2024-10-03 0:50 ` [PATCH v2 2/3] samples/landlock: Refactor --help message in function Matthieu Buffet
2024-10-03 15:27 ` Mickaël Salaün
2024-10-03 0:50 ` [PATCH v2 3/3] samples/landlock: Clarify option parsing behaviour Matthieu Buffet
2024-10-03 15:29 ` Mickaël Salaün
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=20241003005042.258991-1-matthieu@buffet.re \
--to=matthieu@buffet.re \
--cc=gnoack@google.com \
--cc=ivanov.mikhail1@huawei-partners.com \
--cc=konstantin.meskhidze@huawei.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=mic@digikod.net \
/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).