From: "Mickaël Salaün" <mic@digikod.net>
To: "Günther Noack" <gnoack@google.com>
Cc: "Mickaël Salaün" <mic@digikod.net>,
linux-security-module@vger.kernel.org,
Charles <dmcjisalive@gmail.com>
Subject: [PATCH v1] selftests/landlock: Test abstract socket trace name limits
Date: Fri, 28 Aug 2026 21:00:36 +0200 [thread overview]
Message-ID: <20260828190038.71831-1-mic@digikod.net> (raw)
The landlock_deny_scope_abstract_unix_socket event captures binary
socket names with __string_len(), whose dynamic field reserves an extra
byte for the NUL terminator. The printer subtracts this byte before
escaping the content.
Exercise the minimum accepted address length, which has no name content,
and the maximum sockaddr_un length, which has 107 content bytes. Check
the exact trace output at both boundaries. The existing stream and
datagram variants share this event, so the boundary variants only need
the stream path.
The lower-bound test confirms that the subtraction recovers zero instead
of underflowing.
Cc: Günther Noack <gnoack@google.com>
Link: https://patch.msgid.link/CAL4aGcVcT0VWVFmGi_vLqxxZ9KdOHfGXYZtKjBdvoUyFjbu5=A@mail.gmail.com
Signed-off-by: Mickaël Salaün <mic@digikod.net>
---
.../landlock/scoped_abstract_unix_test.c | 76 +++++++++++++------
1 file changed, 54 insertions(+), 22 deletions(-)
diff --git a/tools/testing/selftests/landlock/scoped_abstract_unix_test.c b/tools/testing/selftests/landlock/scoped_abstract_unix_test.c
index 6dbe863ea571..e62f1a2154c6 100644
--- a/tools/testing/selftests/landlock/scoped_abstract_unix_test.c
+++ b/tools/testing/selftests/landlock/scoped_abstract_unix_test.c
@@ -1252,6 +1252,11 @@ FIXTURE_TEARDOWN(trace_unix)
clear_cap(_metadata, CAP_SYS_ADMIN);
}
+static const char
+ trace_unix_max_name[sizeof(((struct sockaddr_un *)0)->sun_path)] = {
+ [0 ... sizeof(trace_unix_max_name) - 2] = 'x',
+ };
+
/* clang-format off */
FIXTURE_VARIANT(trace_unix) {
/* clang-format on */
@@ -1259,6 +1264,8 @@ FIXTURE_VARIANT(trace_unix) {
bool sandbox;
bool sandbox_target; /* Peer owned by a domain: peer_domain != 0. */
int expect_denied;
+ const char *name; /* NULL generates a PID-based binary name. */
+ size_t name_len;
};
/* clang-format off */
@@ -1281,6 +1288,26 @@ FIXTURE_VARIANT_ADD(trace_unix, stream_allowed) {
.sandbox_target = false, .expect_denied = 0,
};
+/* Stream: lower abstract-name length boundary. */
+FIXTURE_VARIANT_ADD(trace_unix, stream_denied_empty_name) {
+ .sock_type = SOCK_STREAM,
+ .sandbox = true,
+ .sandbox_target = false,
+ .expect_denied = 1,
+ .name = "",
+ .name_len = 0,
+};
+
+/* Stream: upper abstract-name length boundary. */
+FIXTURE_VARIANT_ADD(trace_unix, stream_denied_max_name) {
+ .sock_type = SOCK_STREAM,
+ .sandbox = true,
+ .sandbox_target = false,
+ .expect_denied = 1,
+ .name = trace_unix_max_name,
+ .name_len = sizeof(trace_unix_max_name) - 1,
+};
+
/* Datagram: sandboxed client sendto() an unsandboxed peer (peer_domain=0). */
FIXTURE_VARIANT_ADD(trace_unix, dgram_denied) {
.sock_type = SOCK_DGRAM, .sandbox = true,
@@ -1304,12 +1331,11 @@ FIXTURE_VARIANT_ADD(trace_unix, dgram_allowed) {
/*
* A sandboxed thread reaching an abstract unix socket peer through connect(2)
* (stream) or sendto(2) (datagram) is denied and emits
- * landlock_deny_scope_abstract_unix_socket. The abstract name is crafted with
- * a space and an embedded NUL followed by an "END" marker to check the
- * tracepoint escaping and its length handling (a raw space would break the
- * sun_path field regex; strlen() would truncate at the NUL and drop "END").
- * peer_pid is only meaningful for a stream peer (a datagram peer has no
- * SO_PEERCRED), so it is asserted only there.
+ * landlock_deny_scope_abstract_unix_socket. The default abstract name has a
+ * space and an embedded NUL followed by an "END" marker to check escaping and
+ * binary length handling. Additional stream variants cover the minimum and
+ * maximum abstract-name lengths. peer_pid is only meaningful for a stream peer
+ * (a datagram peer has no SO_PEERCRED), so it is asserted only there.
*/
TEST_F(trace_unix, deny_scope_unix)
{
@@ -1317,7 +1343,7 @@ TEST_F(trace_unix, deny_scope_unix)
.sun_family = AF_UNIX,
};
char *buf, field[128], expected_pid[16];
- int server_fd, count, status, name_len, addr_len;
+ int server_fd, count, status, name_len, addr_len = 0;
pid_t child;
if (!self->tracefs_ok)
@@ -1336,12 +1362,19 @@ TEST_F(trace_unix, deny_scope_unix)
ASSERT_LE(0, server_fd);
addr.sun_path[0] = '\0';
- name_len = snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
- "landlock_trace_test_%d ", getpid());
- addr.sun_path[1 + name_len] = '\0';
- memcpy(addr.sun_path + 1 + name_len + 1, "END", 3);
- addr_len =
- offsetof(struct sockaddr_un, sun_path) + 1 + name_len + 1 + 3;
+ if (variant->name) {
+ ASSERT_LE(variant->name_len, sizeof(addr.sun_path) - 1);
+ memcpy(addr.sun_path + 1, variant->name, variant->name_len);
+ name_len = variant->name_len;
+ } else {
+ name_len = snprintf(addr.sun_path + 1,
+ sizeof(addr.sun_path) - 1,
+ "landlock_trace_test_%d ", getpid());
+ addr.sun_path[1 + name_len] = '\0';
+ memcpy(addr.sun_path + 1 + name_len + 1, "END", 3);
+ name_len += 1 + 3;
+ }
+ addr_len = offsetof(struct sockaddr_un, sun_path) + 1 + name_len;
ASSERT_EQ(0, bind(server_fd, (struct sockaddr *)&addr, addr_len));
if (variant->sock_type == SOCK_STREAM)
@@ -1430,19 +1463,18 @@ TEST_F(trace_unix, deny_scope_unix)
count, buf);
}
- /*
- * sun_path is escaped: a raw space would break this field's [^ ]*$
- * regex, so a successful extract proves the space was escaped, and its
- * full length is honored: the "END" marker after the embedded NUL must
- * survive (strlen() would truncate it at the NUL).
- */
ASSERT_EQ(0, tracefs_extract_field(
buf,
REGEX_DENY_SCOPE_ABSTRACT_UNIX_SOCKET(TRACE_TASK),
"sun_path", field, sizeof(field)));
- EXPECT_NE(NULL, strstr(field, "END"))
- {
- TH_LOG("sun_path truncated or unescaped: %s", field);
+ if (variant->name) {
+ EXPECT_STREQ(variant->name, field);
+ } else {
+ /* An embedded NUL must not truncate the following marker. */
+ EXPECT_NE(NULL, strstr(field, "END"))
+ {
+ TH_LOG("sun_path truncated or unescaped: %s", field);
+ }
}
/* peer_pid is the parent's PID for a stream peer (0 for datagram). */
--
2.55.0
reply other threads:[~2026-08-28 20:00 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260828190038.71831-1-mic@digikod.net \
--to=mic@digikod.net \
--cc=dmcjisalive@gmail.com \
--cc=gnoack@google.com \
--cc=linux-security-module@vger.kernel.org \
/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