selftests/bpf: Mask socket type flags in mptcpify prog
Subsystems (6)
PATCH v2 1/1 selftests/bpf: Mask socket type flags in mptcpify prog
The mptcpify BPF prog upgrades eligible TCP sockets to MPTCP, but only when the socket type is exactly SOCK_STREAM. Its update_socket_protocol() hook runs on the raw type from userspace, before the socket core masks it with SOCK_TYPE_MASK, so the type may still carry SOCK_CLOEXEC or SOCK_NONBLOCK in its upper bits and the equality check fails.
As a result, a socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0) -- what common libraries do by default -- is silently left as plain TCP. This was hit in practice with curl. Since mptcpify.c is referenced as example code for enabling MPTCP transparently, the same mistake is likely to be copied into real deployments where it fails the same way and is hard to diagnose.
Mask the type before comparing, mirroring the socket core. Extend the test to also create the server with SOCK_CLOEXEC set; the same masking is applied to start_server_addr() so a flagged type still listens.
---
Changes in v2:
- Use my real name in the Signed-off-by (the "@" broke git am).
- Add "bpf-next" to the subject prefix so the CI tests it.
- Simplify the test: drop the type[] array and loop, keep two explicit run_mptcpify() calls (plain and SOCK_CLOEXEC).
- Tighten the commit message.
tools/testing/selftests/bpf/network_helpers.c | 4 ++-- tools/testing/selftests/bpf/network_helpers.h | 5 +++++ tools/testing/selftests/bpf/prog_tests/mptcp.c | 13 ++++++++++--- tools/testing/selftests/bpf/progs/bpf_tracing_net.h | 3 +++ tools/testing/selftests/bpf/progs/mptcpify.c | 2 +- 5 files changed, 21 insertions(+), 6 deletions(-)
tools/testing/selftests/bpf/network_helpers.c +2 -2
@@ -111,7 +111,7 @@ int start_server_addr(int type, const struct sockaddr_storage *addr, socklen_t aif (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;
tools/testing/selftests/bpf/network_helpers.h +5 -0
@@ -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;
tools/testing/selftests/bpf/prog_tests/mptcp.c +10 -3
@@ -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;
@@ -317,7 +317,14 @@ static void test_mptcpify(void)if (!ASSERT_OK_PTR (netns,"netns_new" )) goto fail; -ASSERT_OK (run_mptcpify (cgroup_fd),"run_mptcpify" ); +ASSERT_OK (run_mptcpify (cgroup_fd,SOCK_STREAM ),"run_mptcpify" ); +/* userspace sets flags such as SOCK_CLOEXEC together with the type; +* 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. +*/ +ASSERT_OK (run_mptcpify (cgroup_fd,SOCK_STREAM |SOCK_CLOEXEC ), +"run_mptcpify_cloexec" ); fail:netns_free (netns);
tools/testing/selftests/bpf/progs/bpf_tracing_net.h +3 -0
@@ -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
tools/testing/selftests/bpf/progs/mptcpify.c +1 -1
@@ -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 ; }
Signature · 1 line
2.54.0
Hi Guillaume,
Thank you for sharing this fix!
Quoted 6 lines
The mptcpify BPF prog upgrades eligible TCP sockets to MPTCP, but only when the socket type is exactly
SOCK_STREAM. Itsupdate_socket_protocol()hook runs on the raw type from userspace, before the socket core masks it withSOCK_TYPE_MASK, so the type may still carrySOCK_CLOEXECorSOCK_NONBLOCKin its upper bits and the equality check fails.
Quoted 6 lines
As a result, a
socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)-- what common libraries do by default -- is silently left as plain TCP. This was hit in practice with curl. Sincemptcpify.cis referenced as example code for enabling MPTCP transparently, the same mistake is likely to be copied into real deployments where it fails the same way and is hard to diagnose.
Good idea to fix this code in mptcpify.c, which is indeed used as a reference, and ends up in real deployments.
The modifications look good to me:
Signature · 1 line
Matthieu Baerts (NGI0) <[email protected]>
This patch was applied to bpf/bpf-next.git (master) by Andrii Nakryiko <[email protected]>:
Hello:
This patch was applied to bpf/bpf-next.git (master) by Andrii Nakryiko <[email protected]>:
Quoted 6 lines · On Tue, 30 Jun 2026 11:57:23 +0200 you wrote:
The mptcpify BPF prog upgrades eligible TCP sockets to MPTCP, but only when the socket type is exactly
SOCK_STREAM. Itsupdate_socket_protocol()hook runs on the raw type from userspace, before the socket core masks it withSOCK_TYPE_MASK, so the type may still carrySOCK_CLOEXECorSOCK_NONBLOCKin its upper bits and the equality check fails.
Quoted 8 lines
As a result, a
socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0)-- what common libraries do by default -- is silently left as plain TCP. This was hit in practice with curl. Sincemptcpify.cis referenced as example code for enabling MPTCP transparently, the same mistake is likely to be copied into real deployments where it fails the same way and is hard to diagnose.[...]
Here is the summary with links:
- [bpf-next,v2] selftests/bpf: Mask socket type flags in mptcpify prog
https://git.kernel.org/bpf/bpf-next/c/b4b8b334f6b5
You are awesome, thank you!
Signature · 2 lines
Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html