Netdev List
 help / color / mirror / Atom feed
From: "Guillaume @layus Maudoux" <layus.on@gmail.com>
To: Alexei Starovoitov <ast@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	Martin KaFai Lau <martin.lau@linux.dev>
Cc: Eduard Zingerman <eddyz87@gmail.com>,
	Matthieu Baerts <matttbe@kernel.org>,
	Mat Martineau <martineau@kernel.org>,
	Geliang Tang <geliang@kernel.org>, Shuah Khan <shuah@kernel.org>,
	bpf@vger.kernel.org, mptcp@lists.linux.dev,
	netdev@vger.kernel.org, linux-kselftest@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	"Guillaume @layus Maudoux" <layus.on@gmail.com>
Subject: [PATCH] selftests/bpf: Mask socket type flags in mptcpify prog
Date: Mon, 29 Jun 2026 14:56:37 +0200	[thread overview]
Message-ID: <20260629125637.384923-1-layus.on@gmail.com> (raw)

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


             reply	other threads:[~2026-06-29 12:57 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-29 12:56 Guillaume @layus Maudoux [this message]
2026-06-29 18:12 ` [PATCH] selftests/bpf: Mask socket type flags in mptcpify prog Amery Hung

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=20260629125637.384923-1-layus.on@gmail.com \
    --to=layus.on@gmail.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=geliang@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=martineau@kernel.org \
    --cc=matttbe@kernel.org \
    --cc=mptcp@lists.linux.dev \
    --cc=netdev@vger.kernel.org \
    --cc=shuah@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