Netdev List
 help / color / mirror / Atom feed
* [PATCH] selftests/bpf: Mask socket type flags in mptcpify prog
@ 2026-06-29 12:56 Guillaume @layus Maudoux
  2026-06-29 18:12 ` Amery Hung
  0 siblings, 1 reply; 2+ messages in thread
From: Guillaume @layus Maudoux @ 2026-06-29 12:56 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Martin KaFai Lau
  Cc: Eduard Zingerman, Matthieu Baerts, Mat Martineau, Geliang Tang,
	Shuah Khan, bpf, mptcp, netdev, linux-kselftest, linux-kernel,
	Guillaume @layus Maudoux

The mptcpify BPF prog hooks update_socket_protocol() to rewrite
eligible TCP socket() calls to IPPROTO_MPTCP. It only does so when the
socket type is exactly SOCK_STREAM:

	type == SOCK_STREAM

The problem is that update_socket_protocol() in __sys_socket() is
called on the raw type argument as passed from userspace, before
__sys_socket_create() strips the flag bits with
"type &= SOCK_TYPE_MASK". The type argument may therefore carry
SOCK_CLOEXEC and/or SOCK_NONBLOCK in its upper bits, and the equality
check above then fails.

As a result, any socket created with e.g.
socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0) -- which is what common
libraries do by default -- is silently left as plain TCP instead of
being upgraded to MPTCP. This was observed in practice with curl,
whose connections were not upgraded to MPTCP despite the prog being
attached.

The impact reaches beyond the test, because mptcpify.c is referenced
as example code for users who want to transparently enable MPTCP. The
same mistake is therefore likely to be copied into real deployments,
where it fails the same way and is hard to diagnose.

The fix is to mask off the flag bits before comparing, mirroring what
the socket core does:

	(type & SOCK_TYPE_MASK) == SOCK_STREAM

Since SOCK_TYPE_MASK is not exposed through vmlinux.h, define it in
bpf_tracing_net.h.

To exercise the regression directly, extend the mptcpify test to also
create the server socket with SOCK_CLOEXEC and SOCK_NONBLOCK set.
Routing a flagged type through start_server() then revealed a second
instance of the same pattern: start_server_addr() compared the type
against SOCK_STREAM for equality to decide whether to set SO_REUSEADDR
and call listen(), and so would skip listening for a flagged type.
Mask the type there as well. As SOCK_TYPE_MASK is not exposed by
glibc's <sys/socket.h> either, define it in network_helpers.h,
mirroring prog_tests/socket_helpers.h.

Fixes: ddba122428a7 ("selftests/bpf: Add mptcpify test")
Signed-off-by: Guillaume @layus Maudoux <layus.on@gmail.com>
---
 tools/testing/selftests/bpf/network_helpers.c |  4 ++--
 tools/testing/selftests/bpf/network_helpers.h |  5 +++++
 .../testing/selftests/bpf/prog_tests/mptcp.c  | 20 +++++++++++++++----
 .../selftests/bpf/progs/bpf_tracing_net.h     |  3 +++
 tools/testing/selftests/bpf/progs/mptcpify.c  |  2 +-
 5 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/bpf/network_helpers.c b/tools/testing/selftests/bpf/network_helpers.c
index b82f572641b7..db935a9d9fc1 100644
--- a/tools/testing/selftests/bpf/network_helpers.c
+++ b/tools/testing/selftests/bpf/network_helpers.c
@@ -111,7 +111,7 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t a
 	if (settimeo(fd, opts->timeout_ms))
 		goto error_close;
 
-	if (type == SOCK_STREAM &&
+	if ((type & SOCK_TYPE_MASK) == SOCK_STREAM &&
 	    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) {
 		log_err("Failed to enable SO_REUSEADDR");
 		goto error_close;
@@ -128,7 +128,7 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t a
 		goto error_close;
 	}
 
-	if (type == SOCK_STREAM) {
+	if ((type & SOCK_TYPE_MASK) == SOCK_STREAM) {
 		if (listen(fd, opts->backlog ? MAX(opts->backlog, 0) : 1) < 0) {
 			log_err("Failed to listed on socket");
 			goto error_close;
diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h
index 79a010c88e11..75133119c04a 100644
--- a/tools/testing/selftests/bpf/network_helpers.h
+++ b/tools/testing/selftests/bpf/network_helpers.h
@@ -25,6 +25,11 @@ typedef __u16 __sum16;
 #define VIP_NUM 5
 #define MAGIC_BYTES 123
 
+/* include/linux/net.h */
+#ifndef SOCK_TYPE_MASK
+#define SOCK_TYPE_MASK 0xf
+#endif
+
 struct network_helper_opts {
 	int timeout_ms;
 	int proto;
diff --git a/tools/testing/selftests/bpf/prog_tests/mptcp.c b/tools/testing/selftests/bpf/prog_tests/mptcp.c
index 8fade8bdc451..faa001ea84ab 100644
--- a/tools/testing/selftests/bpf/prog_tests/mptcp.c
+++ b/tools/testing/selftests/bpf/prog_tests/mptcp.c
@@ -264,7 +264,7 @@ static int verify_mptcpify(int server_fd, int client_fd)
 	return err;
 }
 
-static int run_mptcpify(int cgroup_fd)
+static int run_mptcpify(int cgroup_fd, int type)
 {
 	int server_fd, client_fd, err = 0;
 	struct mptcpify *mptcpify_skel;
@@ -280,7 +280,7 @@ static int run_mptcpify(int cgroup_fd)
 		goto out;
 
 	/* without MPTCP */
-	server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);
+	server_fd = start_server(AF_INET, type, NULL, 0, 0);
 	if (!ASSERT_GE(server_fd, 0, "start_server")) {
 		err = -EIO;
 		goto out;
@@ -307,7 +307,18 @@ static int run_mptcpify(int cgroup_fd)
 static void test_mptcpify(void)
 {
 	struct netns_obj *netns = NULL;
-	int cgroup_fd;
+	int cgroup_fd, i;
+	int types[] = {
+		SOCK_STREAM,
+		/* userspace sets these flags together with the type, and the
+		 * BPF prog must still upgrade the socket to MPTCP. See
+		 * update_socket_protocol() in net/socket.c, which runs before
+		 * the type is masked with SOCK_TYPE_MASK.
+		 */
+		SOCK_STREAM | SOCK_CLOEXEC,
+		SOCK_STREAM | SOCK_NONBLOCK,
+		SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+	};
 
 	cgroup_fd = test__join_cgroup("/mptcpify");
 	if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup"))
@@ -317,7 +328,8 @@ static void test_mptcpify(void)
 	if (!ASSERT_OK_PTR(netns, "netns_new"))
 		goto fail;
 
-	ASSERT_OK(run_mptcpify(cgroup_fd), "run_mptcpify");
+	for (i = 0; i < ARRAY_SIZE(types); i++)
+		ASSERT_OK(run_mptcpify(cgroup_fd, types[i]), "run_mptcpify");
 
 fail:
 	netns_free(netns);
diff --git a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
index d8dacef37c16..c4b438854565 100644
--- a/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
+++ b/tools/testing/selftests/bpf/progs/bpf_tracing_net.h
@@ -8,6 +8,9 @@
 #define AF_INET			2
 #define AF_INET6		10
 
+/* include/linux/net.h */
+#define SOCK_TYPE_MASK		0xf
+
 #define SOL_SOCKET		1
 #define SO_REUSEADDR		2
 #define SO_SNDBUF		7
diff --git a/tools/testing/selftests/bpf/progs/mptcpify.c b/tools/testing/selftests/bpf/progs/mptcpify.c
index cbdc730c3a47..e3f8cb54dbe9 100644
--- a/tools/testing/selftests/bpf/progs/mptcpify.c
+++ b/tools/testing/selftests/bpf/progs/mptcpify.c
@@ -15,7 +15,7 @@ int BPF_PROG(mptcpify, int family, int type, int protocol)
 		return protocol;
 
 	if ((family == AF_INET || family == AF_INET6) &&
-	    type == SOCK_STREAM &&
+	    (type & SOCK_TYPE_MASK) == SOCK_STREAM &&
 	    (!protocol || protocol == IPPROTO_TCP)) {
 		return IPPROTO_MPTCP;
 	}
-- 
2.54.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-06-29 18:13 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-29 12:56 [PATCH] selftests/bpf: Mask socket type flags in mptcpify prog Guillaume @layus Maudoux
2026-06-29 18:12 ` Amery Hung

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox