| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/12 08:04 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"MPTCP"
],
"FocusSymbols": [
"mptcp_subflow_reqsk_clone",
"mptcp_token_move_request",
"mptcp_token_accept",
"mptcp_sk_clone_init"
],
"KMSANReasoning": "The patch modifies the MPTCP subsystem to properly handle request socket cloning and token lifecycle management. The changes involve reference counting, hash list manipulation (hlist_nulls), and object ownership transfers. There are no new data structures exposed to userspace, nor are there any complex buffer allocations where uninitialized memory could be leaked or used in control flow. Any bugs introduced by these changes would manifest as use-after-free, double free, NULL pointer dereferences, or memory leaks, all of which are effectively detected by KASAN and standard kernel debugging tools. Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies the MPTCP subsystem to handle request socket cloning and token management. It introduces new functions `mptcp_subflow_reqsk_clone` and `mptcp_token_move_request`, and modifies `mptcp_token_accept` and `mptcp_sk_clone_init`. These are functional changes in the core networking stack that are reachable and should be fuzzed.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/12 08:04 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit dfdbc50913f7c8b83115d624e1227d7d5d0918e1\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Aug 12 08:04:28 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/include/net/mptcp.h b/include/net/mptcp.h\nindex 71b9fc5a57963..0a02ac1ed22d9 100644\n--- a/include/net/mptcp.h\n+++ b/include/net/mptcp.h\n@@ -223,6 +223,8 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,\n struct request_sock *mptcp_subflow_reqsk_alloc(const struct request_sock_ops *ops,\n \t\t\t\t\t struct sock *sk_listener,\n \t\t\t\t\t bool attach_listener);\n+void mptcp_subflow_reqsk_clone(struct request_sock *req,\n+\t\t\t struct request_sock *new_req);\n \n __be32 mptcp_get_reset_option(const struct sk_buff *skb);\n \n@@ -309,6 +311,11 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques\n \treturn NULL;\n }\n \n+static inline void mptcp_subflow_reqsk_clone(struct request_sock *req,\n+\t\t\t\t\t struct request_sock *new_req)\n+{\n+}\n+\n static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }\n \n static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { }\ndiff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c\nindex 6257459bcee24..896f472dcba29 100644\n--- a/net/ipv4/inet_connection_sock.c\n+++ b/net/ipv4/inet_connection_sock.c\n@@ -21,6 +21,7 @@\n #include \u003cnet/xfrm.h\u003e\n #include \u003cnet/tcp.h\u003e\n #include \u003cnet/tcp_ecn.h\u003e\n+#include \u003cnet/mptcp.h\u003e\n #include \u003cnet/sock_reuseport.h\u003e\n #include \u003cnet/addrconf.h\u003e\n \n@@ -961,6 +962,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,\n \t\trcu_assign_pointer(tcp_sk(nreq-\u003esk)-\u003efastopen_rsk, nreq);\n \t}\n \n+\tif (rsk_is_mptcp(req))\n+\t\tmptcp_subflow_reqsk_clone(req, nreq);\n+\n \treturn nreq;\n }\n \ndiff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c\nindex 7c8180d8d5eff..b05c8d37a0831 100644\n--- a/net/mptcp/protocol.c\n+++ b/net/mptcp/protocol.c\n@@ -3561,6 +3561,24 @@ static void mptcp_copy_ip_options(struct sock *newsk, const struct sock *sk)\n \trcu_read_unlock();\n }\n \n+static void mptcp_sk_clone_destroy(struct sock *nsk)\n+{\n+\tstruct mptcp_sock *msk = mptcp_sk(nsk);\n+\n+\tmptcp_release_sched(msk);\n+\tmptcp_set_state(nsk, TCP_CLOSE);\n+\t/* inet_csk_prepare_forced_close() clears TCP sock_ops state via\n+\t * tcp_sk(), but nsk is an MPTCP master socket; keep the inet-level\n+\t * destroy preparation here.\n+\t */\n+\tbh_unlock_sock(nsk);\n+\tsock_put(nsk);\n+\tsock_set_flag(nsk, SOCK_DEAD);\n+\ttcp_orphan_count_inc();\n+\tinet_sk(nsk)-\u003einet_num = 0;\n+\tinet_csk_destroy_sock(nsk);\n+}\n+\n struct sock *mptcp_sk_clone_init(const struct sock *sk,\n \t\t\t\t const struct mptcp_options_received *mp_opt,\n \t\t\t\t struct sock *ssk,\n@@ -3620,11 +3638,6 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,\n \tlist_add(\u0026subflow-\u003enode, \u0026msk-\u003econn_list);\n \tsock_hold(ssk);\n \n-\t/* new mpc subflow takes ownership of the newly\n-\t * created mptcp socket\n-\t */\n-\tmptcp_token_accept(subflow_req, msk);\n-\n \t/* set msk addresses early to ensure mptcp_pm_get_local_id()\n \t * uses the correct data\n \t */\n@@ -3633,6 +3646,14 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,\n \tmptcp_rcv_space_init(msk, ssk);\n \tmsk-\u003ercvq_space.time = mptcp_stamp();\n \n+\tif (!mptcp_token_accept(subflow_req, msk)) {\n+\t\tlist_del_init(\u0026subflow-\u003enode);\n+\t\tWRITE_ONCE(msk-\u003efirst, NULL);\n+\t\tsock_put(ssk);\n+\t\tmptcp_sk_clone_destroy(nsk);\n+\t\treturn NULL;\n+\t}\n+\n \tif (mp_opt-\u003esuboptions \u0026 OPTION_MPTCP_MPC_ACK)\n \t\t__mptcp_subflow_fully_established(msk, subflow, mp_opt);\n \tbh_unlock_sock(nsk);\ndiff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h\nindex 1b80f2d6ec5a2..69d531c770c44 100644\n--- a/net/mptcp/protocol.h\n+++ b/net/mptcp/protocol.h\n@@ -1076,9 +1076,11 @@ static inline void mptcp_token_init_request(struct request_sock *req)\n }\n \n int mptcp_token_new_request(struct request_sock *req);\n+void mptcp_token_move_request(struct request_sock *req,\n+\t\t\t struct request_sock *new_req);\n void mptcp_token_destroy_request(struct request_sock *req);\n int mptcp_token_new_connect(struct sock *ssk);\n-void mptcp_token_accept(struct mptcp_subflow_request_sock *r,\n+bool mptcp_token_accept(struct mptcp_subflow_request_sock *r,\n \t\t\tstruct mptcp_sock *msk);\n bool mptcp_token_exists(u32 token);\n struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token);\ndiff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c\nindex e1f20ff8fdb42..d40ab09ab75b5 100644\n--- a/net/mptcp/subflow.c\n+++ b/net/mptcp/subflow.c\n@@ -47,6 +47,19 @@ static void subflow_req_destructor(struct request_sock *req)\n \tmptcp_token_destroy_request(req);\n }\n \n+void mptcp_subflow_reqsk_clone(struct request_sock *req,\n+\t\t\t struct request_sock *new_req)\n+{\n+\tstruct mptcp_subflow_request_sock *subflow_req;\n+\n+\tsubflow_req = mptcp_subflow_rsk(new_req);\n+\n+\tif (subflow_req-\u003emsk)\n+\t\tsock_hold((struct sock *)subflow_req-\u003emsk);\n+\n+\tmptcp_token_move_request(req, new_req);\n+}\n+\n static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2,\n \t\t\t\t void *hmac)\n {\ndiff --git a/net/mptcp/token.c b/net/mptcp/token.c\nindex f1a50f367add8..24877a2c37727 100644\n--- a/net/mptcp/token.c\n+++ b/net/mptcp/token.c\n@@ -180,6 +180,36 @@ int mptcp_token_new_connect(struct sock *ssk)\n \treturn 0;\n }\n \n+void mptcp_token_move_request(struct request_sock *req,\n+\t\t\t struct request_sock *new_req)\n+{\n+\tstruct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);\n+\tstruct mptcp_subflow_request_sock *new_subflow_req;\n+\tstruct mptcp_subflow_request_sock *pos;\n+\tstruct token_bucket *bucket;\n+\n+\tnew_subflow_req = mptcp_subflow_rsk(new_req);\n+\n+\tif (hlist_nulls_unhashed_lockless(\u0026subflow_req-\u003etoken_node)) {\n+\t\tmptcp_token_init_request(new_req);\n+\t\treturn;\n+\t}\n+\n+\tbucket = token_bucket(subflow_req-\u003etoken);\n+\tspin_lock_bh(\u0026bucket-\u003elock);\n+\tif (hlist_nulls_unhashed(\u0026subflow_req-\u003etoken_node)) {\n+\t\tmptcp_token_init_request(new_req);\n+\t} else {\n+\t\tpos = __token_lookup_req(bucket, subflow_req-\u003etoken);\n+\t\tif (pos == subflow_req)\n+\t\t\thlist_nulls_replace_init_rcu(\u0026subflow_req-\u003etoken_node,\n+\t\t\t\t\t\t \u0026new_subflow_req-\u003etoken_node);\n+\t\telse\n+\t\t\tmptcp_token_init_request(new_req);\n+\t}\n+\tspin_unlock_bh(\u0026bucket-\u003elock);\n+}\n+\n /**\n * mptcp_token_accept - replace a req sk with full sock in token hash\n * @req: the request socket to be removed\n@@ -187,24 +217,36 @@ int mptcp_token_new_connect(struct sock *ssk)\n *\n * Called when a SYN packet creates a new logical connection, i.e.\n * is not a join request.\n+ *\n+ * Return: true on success.\n */\n-void mptcp_token_accept(struct mptcp_subflow_request_sock *req,\n+bool mptcp_token_accept(struct mptcp_subflow_request_sock *req,\n \t\t\tstruct mptcp_sock *msk)\n {\n \tstruct mptcp_subflow_request_sock *pos;\n \tstruct sock *sk = (struct sock *)msk;\n \tstruct token_bucket *bucket;\n+\tbool ret = false;\n \n-\tsock_prot_inuse_add(sock_net(sk), sk-\u003esk_prot, 1);\n \tbucket = token_bucket(req-\u003etoken);\n \tspin_lock_bh(\u0026bucket-\u003elock);\n+\tif (hlist_nulls_unhashed(\u0026req-\u003etoken_node))\n+\t\tgoto unlock;\n \n-\t/* pedantic lookup check for the moved token */\n \tpos = __token_lookup_req(bucket, req-\u003etoken);\n-\tif (!WARN_ON_ONCE(pos != req))\n-\t\thlist_nulls_del_init_rcu(\u0026req-\u003etoken_node);\n+\tif (pos != req)\n+\t\tgoto unlock;\n+\n+\thlist_nulls_del_init_rcu(\u0026req-\u003etoken_node);\n \t__sk_nulls_add_node_rcu((struct sock *)msk, \u0026bucket-\u003emsk_chain);\n+\tret = true;\n+\n+unlock:\n \tspin_unlock_bh(\u0026bucket-\u003elock);\n+\tif (ret)\n+\t\tsock_prot_inuse_add(sock_net(sk), sk-\u003esk_prot, 1);\n+\n+\treturn ret;\n }\n \n bool mptcp_token_exists(u32 token)\n@@ -355,16 +397,21 @@ void mptcp_token_destroy_request(struct request_sock *req)\n \tstruct mptcp_subflow_request_sock *pos;\n \tstruct token_bucket *bucket;\n \n-\tif (hlist_nulls_unhashed(\u0026subflow_req-\u003etoken_node))\n+\tif (hlist_nulls_unhashed_lockless(\u0026subflow_req-\u003etoken_node))\n \t\treturn;\n \n \tbucket = token_bucket(subflow_req-\u003etoken);\n \tspin_lock_bh(\u0026bucket-\u003elock);\n+\tif (hlist_nulls_unhashed(\u0026subflow_req-\u003etoken_node))\n+\t\tgoto unlock;\n+\n \tpos = __token_lookup_req(bucket, subflow_req-\u003etoken);\n-\tif (!WARN_ON_ONCE(pos != subflow_req)) {\n+\tif (pos == subflow_req) {\n \t\thlist_nulls_del_init_rcu(\u0026pos-\u003etoken_node);\n \t\tbucket-\u003echain_len--;\n \t}\n+\n+unlock:\n \tspin_unlock_bh(\u0026bucket-\u003elock);\n }\n \ndiff --git a/net/mptcp/token_test.c b/net/mptcp/token_test.c\nindex 4fc39fa2e262d..be9acce8a5673 100644\n--- a/net/mptcp/token_test.c\n+++ b/net/mptcp/token_test.c\n@@ -99,7 +99,7 @@ static void mptcp_token_test_accept(struct kunit *test)\n \tKUNIT_ASSERT_EQ(test, 0,\n \t\t\tmptcp_token_new_request((struct request_sock *)req));\n \tmsk-\u003etoken = req-\u003etoken;\n-\tmptcp_token_accept(req, msk);\n+\tKUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));\n \tKUNIT_EXPECT_PTR_EQ(test, msk, mptcp_token_get_sock(\u0026init_net, msk-\u003etoken));\n \n \t/* this is now a no-op */\n@@ -122,7 +122,7 @@ static void mptcp_token_test_destroyed(struct kunit *test)\n \tKUNIT_ASSERT_EQ(test, 0,\n \t\t\tmptcp_token_new_request((struct request_sock *)req));\n \tmsk-\u003etoken = req-\u003etoken;\n-\tmptcp_token_accept(req, msk);\n+\tKUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));\n \n \t/* simulate race on removal */\n \trefcount_set(\u0026sk-\u003esk_refcnt, 0);\n"
} |
| 2/1 | 2026/08/12 08:04 | agent | patch-evaluator |
0mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"MPTCP"
],
"FocusSymbols": [
"mptcp_subflow_reqsk_clone",
"mptcp_token_move_request",
"mptcp_token_accept",
"mptcp_sk_clone_init"
],
"Reasoning": "The patch modifies the MPTCP subsystem to handle request socket cloning and token management. It introduces new functions `mptcp_subflow_reqsk_clone` and `mptcp_token_move_request`, and modifies `mptcp_token_accept` and `mptcp_sk_clone_init`. These are functional changes in the core networking stack that are reachable and should be fuzzed.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit dfdbc50913f7c8b83115d624e1227d7d5d0918e1
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Aug 12 08:04:28 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 71b9fc5a57963..0a02ac1ed22d9 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -223,6 +223,8 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,
struct request_sock *mptcp_subflow_reqsk_alloc(const struct request_sock_ops *ops,
struct sock *sk_listener,
bool attach_listener);
+void mptcp_subflow_reqsk_clone(struct request_sock *req,
+ struct request_sock *new_req);
__be32 mptcp_get_reset_option(const struct sk_buff *skb);
@@ -309,6 +311,11 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques
return NULL;
}
+static inline void mptcp_subflow_reqsk_clone(struct request_sock *req,
+ struct request_sock *new_req)
+{
+}
+
static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }
static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { }
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 6257459bcee24..896f472dcba29 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -21,6 +21,7 @@
#include <net/xfrm.h>
#include <net/tcp.h>
#include <net/tcp_ecn.h>
+#include <net/mptcp.h>
#include <net/sock_reuseport.h>
#include <net/addrconf.h>
@@ -961,6 +962,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
}
+ if (rsk_is_mptcp(req))
+ mptcp_subflow_reqsk_clone(req, nreq);
+
return nreq;
}
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 7c8180d8d5eff..b05c8d37a0831 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3561,6 +3561,24 @@ static void mptcp_copy_ip_options(struct sock *newsk, const struct sock *sk)
rcu_read_unlock();
}
+static void mptcp_sk_clone_destroy(struct sock *nsk)
+{
+ struct mptcp_sock *msk = mptcp_sk(nsk);
+
+ mptcp_release_sched(msk);
+ mptcp_set_state(nsk, TCP_CLOSE);
+ /* inet_csk_prepare_forced_close() clears TCP sock_ops state via
+ * tcp_sk(), but nsk is an MPTCP master socket; keep the inet-level
+ * destroy preparation here.
+ */
+ bh_unlock_sock(nsk);
+ sock_put(nsk);
+ sock_set_flag(nsk, SOCK_DEAD);
+ tcp_orphan_count_inc();
+ inet_sk(nsk)->inet_num = 0;
+ inet_csk_destroy_sock(nsk);
+}
+
struct sock *mptcp_sk_clone_init(const struct sock *sk,
const struct mptcp_options_received *mp_opt,
struct sock *ssk,
@@ -3620,11 +3638,6 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
list_add(&subflow->node, &msk->conn_list);
sock_hold(ssk);
- /* new mpc subflow takes ownership of the newly
- * created mptcp socket
- */
- mptcp_token_accept(subflow_req, msk);
-
/* set msk addresses early to ensure mptcp_pm_get_local_id()
* uses the correct data
*/
@@ -3633,6 +3646,14 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
mptcp_rcv_space_init(msk, ssk);
msk->rcvq_space.time = mptcp_stamp();
+ if (!mptcp_token_accept(subflow_req, msk)) {
+ list_del_init(&subflow->node);
+ WRITE_ONCE(msk->first, NULL);
+ sock_put(ssk);
+ mptcp_sk_clone_destroy(nsk);
+ return NULL;
+ }
+
if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK)
__mptcp_subflow_fully_established(msk, subflow, mp_opt);
bh_unlock_sock(nsk);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 1b80f2d6ec5a2..69d531c770c44 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -1076,9 +1076,11 @@ static inline void mptcp_token_init_request(struct request_sock *req)
}
int mptcp_token_new_request(struct request_sock *req);
+void mptcp_token_move_request(struct request_sock *req,
+ struct request_sock *new_req);
void mptcp_token_destroy_request(struct request_sock *req);
int mptcp_token_new_connect(struct sock *ssk);
-void mptcp_token_accept(struct mptcp_subflow_request_sock *r,
+bool mptcp_token_accept(struct mptcp_subflow_request_sock *r,
struct mptcp_sock *msk);
bool mptcp_token_exists(u32 token);
struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index e1f20ff8fdb42..d40ab09ab75b5 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -47,6 +47,19 @@ static void subflow_req_destructor(struct request_sock *req)
mptcp_token_destroy_request(req);
}
+void mptcp_subflow_reqsk_clone(struct request_sock *req,
+ struct request_sock *new_req)
+{
+ struct mptcp_subflow_request_sock *subflow_req;
+
+ subflow_req = mptcp_subflow_rsk(new_req);
+
+ if (subflow_req->msk)
+ sock_hold((struct sock *)subflow_req->msk);
+
+ mptcp_token_move_request(req, new_req);
+}
+
static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
void *hmac)
{
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index f1a50f367add8..24877a2c37727 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -180,6 +180,36 @@ int mptcp_token_new_connect(struct sock *ssk)
return 0;
}
+void mptcp_token_move_request(struct request_sock *req,
+ struct request_sock *new_req)
+{
+ struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+ struct mptcp_subflow_request_sock *new_subflow_req;
+ struct mptcp_subflow_request_sock *pos;
+ struct token_bucket *bucket;
+
+ new_subflow_req = mptcp_subflow_rsk(new_req);
+
+ if (hlist_nulls_unhashed_lockless(&subflow_req->token_node)) {
+ mptcp_token_init_request(new_req);
+ return;
+ }
+
+ bucket = token_bucket(subflow_req->token);
+ spin_lock_bh(&bucket->lock);
+ if (hlist_nulls_unhashed(&subflow_req->token_node)) {
+ mptcp_token_init_request(new_req);
+ } else {
+ pos = __token_lookup_req(bucket, subflow_req->token);
+ if (pos == subflow_req)
+ hlist_nulls_replace_init_rcu(&subflow_req->token_node,
+ &new_subflow_req->token_node);
+ else
+ mptcp_token_init_request(new_req);
+ }
+ spin_unlock_bh(&bucket->lock);
+}
+
/**
* mptcp_token_accept - replace a req sk with full sock in token hash
* @req: the request socket to be removed
@@ -187,24 +217,36 @@ int mptcp_token_new_connect(struct sock *ssk)
*
* Called when a SYN packet creates a new logical connection, i.e.
* is not a join request.
+ *
+ * Return: true on success.
*/
-void mptcp_token_accept(struct mptcp_subflow_request_sock *req,
+bool mptcp_token_accept(struct mptcp_subflow_request_sock *req,
struct mptcp_sock *msk)
{
struct mptcp_subflow_request_sock *pos;
struct sock *sk = (struct sock *)msk;
struct token_bucket *bucket;
+ bool ret = false;
- sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
bucket = token_bucket(req->token);
spin_lock_bh(&bucket->lock);
+ if (hlist_nulls_unhashed(&req->token_node))
+ goto unlock;
- /* pedantic lookup check for the moved token */
pos = __token_lookup_req(bucket, req->token);
- if (!WARN_ON_ONCE(pos != req))
- hlist_nulls_del_init_rcu(&req->token_node);
+ if (pos != req)
+ goto unlock;
+
+ hlist_nulls_del_init_rcu(&req->token_node);
__sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
+ ret = true;
+
+unlock:
spin_unlock_bh(&bucket->lock);
+ if (ret)
+ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+
+ return ret;
}
bool mptcp_token_exists(u32 token)
@@ -355,16 +397,21 @@ void mptcp_token_destroy_request(struct request_sock *req)
struct mptcp_subflow_request_sock *pos;
struct token_bucket *bucket;
- if (hlist_nulls_unhashed(&subflow_req->token_node))
+ if (hlist_nulls_unhashed_lockless(&subflow_req->token_node))
return;
bucket = token_bucket(subflow_req->token);
spin_lock_bh(&bucket->lock);
+ if (hlist_nulls_unhashed(&subflow_req->token_node))
+ goto unlock;
+
pos = __token_lookup_req(bucket, subflow_req->token);
- if (!WARN_ON_ONCE(pos != subflow_req)) {
+ if (pos == subflow_req) {
hlist_nulls_del_init_rcu(&pos->token_node);
bucket->chain_len--;
}
+
+unlock:
spin_unlock_bh(&bucket->lock);
}
diff --git a/net/mptcp/token_test.c b/net/mptcp/token_test.c
index 4fc39fa2e262d..be9acce8a5673 100644
--- a/net/mptcp/token_test.c
+++ b/net/mptcp/token_test.c
@@ -99,7 +99,7 @@ static void mptcp_token_test_accept(struct kunit *test)
KUNIT_ASSERT_EQ(test, 0,
mptcp_token_new_request((struct request_sock *)req));
msk->token = req->token;
- mptcp_token_accept(req, msk);
+ KUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));
KUNIT_EXPECT_PTR_EQ(test, msk, mptcp_token_get_sock(&init_net, msk->token));
/* this is now a no-op */
@@ -122,7 +122,7 @@ static void mptcp_token_test_destroyed(struct kunit *test)
KUNIT_ASSERT_EQ(test, 0,
mptcp_token_new_request((struct request_sock *)req));
msk->token = req->token;
- mptcp_token_accept(req, msk);
+ KUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));
/* simulate race on removal */
refcount_set(&sk->sk_refcnt, 0);
|
| 3/2 | 2026/08/12 08:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5629 output: 26 thoughts: 222 Thoughts: **Analyzing a Networking Patch for MPTCP** Okay, so I've got this patch here, and it's touching the MPTCP subsystem. Looks like the core of the change is this new `mptcp_subflow_reqsk_clone` function. The patch hooks it up via `inet_reqsk_clone` in `inet_connection_sock.c`. That's significant. It also seems to refine the token management logic. I see adjustments to `mptcp_sk_clone_init` to manage `mptcp_token_accept` failures, and the introduction of `mptcp_token_move_request`. The way I see it, they're tightening up how these tokens are handled, including a boolean return value for `mptcp_token_accept` to address unhashed token nodes. This is a pretty functional change – right at the heart of the networking stack, specifically MPTCP, dealing with request socket cloning and token management. Given the scope, this is *definitely* something that needs a thorough fuzzing campaign. We want to identify any edge cases or unexpected behavior early. Now, let's see what the CONFIG options are that need to be enabled for this code to be compiled. Since this is in `net/mptcp/`, the Kconfig files in that directory or the root `net/Kconfig` are the obvious places to look. I'll start with `net/mptcp/Kconfig` first. |
| 4/2 | 2026/08/12 08:04 | tool | grepper |
0mArgs:{
"Expression": "config MPTCP",
"PathPrefix": "net/"
}Results: {
"Output": "net/mptcp/Kconfig-1-\nnet/mptcp/Kconfig:2:config MPTCP\nnet/mptcp/Kconfig-3-\tbool \"MPTCP: Multipath TCP\"\n--\nnet/mptcp/Kconfig=16=config INET_MPTCP_DIAG\n--\nnet/mptcp/Kconfig-19-\nnet/mptcp/Kconfig:20:config MPTCP_IPV6\nnet/mptcp/Kconfig-21-\tbool \"MPTCP: IPv6 support for Multipath TCP\"\n--\nnet/mptcp/Kconfig-24-\nnet/mptcp/Kconfig:25:config MPTCP_KUNIT_TEST\nnet/mptcp/Kconfig-26-\ttristate \"This builds the MPTCP KUnit tests\" if !KUNIT_ALL_TESTS\n"
} |
| 5/2 | 2026/08/12 08:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 6417 output: 30 thoughts: 618 Thoughts: **Analyzing MPTCP Function Calls** Okay, so I'm diving into this MPTCP configuration, starting with `CONFIG_MPTCP` as the primary point of reference. I need to zero in on the key functions involved in the subflow process. Let's see... I've identified a few critical functions that warrant closer inspection: `mptcp_subflow_reqsk_clone`, `mptcp_token_move_request`, `mptcp_token_accept`, and `mptcp_sk_clone_init`. These seem to be central to how MPTCP manages its subflows and connection setup, so I should look into how they are being used. Alright, let me confirm if these functions are declared as static or not. Non-static functions are what I am most interested in. Scanning the source code, I've confirmed that `mptcp_subflow_reqsk_clone` (defined in both `include/net/mptcp.h` and `net/mptcp/subflow.c`), `mptcp_token_move_request` (in `net/mptcp/token.c`), `mptcp_token_accept` (also in `net/mptcp/token.c`), and `mptcp_sk_clone_init` (in `net/mptcp/protocol.c`) are all *non-static*. Excellent. This means they are likely core parts of the interface MPTCP presents to the rest of the networking stack. `inet_reqsk_clone` is a good function, but it is *static* in `net/ipv4/inet_connection_sock.c`, which makes it a helper and probably not one to focus on directly. Similarly, `mptcp_sk_clone_destroy` in `net/mptcp/protocol.c` is static as well and I'll ignore it for now. So, to summarize, my focus will be on those four non-static functions: * `mptcp_subflow_reqsk_clone` * `mptcp_token_move_request` * `mptcp_token_accept` * `mptcp_sk_clone_init` Now, let's look at their use and any MPTCP dependencies to fully understand their impact. |
| 6/2 | 2026/08/12 08:04 | tool | grepper |
0mArgs:{
"Expression": "depends on",
"PathPrefix": "net/mptcp/Kconfig"
}Results: {
"Output": "net/mptcp/Kconfig=2=config MPTCP\nnet/mptcp/Kconfig-3-\tbool \"MPTCP: Multipath TCP\"\nnet/mptcp/Kconfig:4:\tdepends on INET\nnet/mptcp/Kconfig-5-\tselect SKB_EXTENSIONS\n--\nnet/mptcp/Kconfig=16=config INET_MPTCP_DIAG\nnet/mptcp/Kconfig:17:\tdepends on INET_DIAG\nnet/mptcp/Kconfig-18-\tdef_tristate INET_DIAG\n--\nnet/mptcp/Kconfig=20=config MPTCP_IPV6\nnet/mptcp/Kconfig-21-\tbool \"MPTCP: IPv6 support for Multipath TCP\"\nnet/mptcp/Kconfig:22:\tdepends on IPV6=y\nnet/mptcp/Kconfig-23-\tdefault y\n--\nnet/mptcp/Kconfig=25=config MPTCP_KUNIT_TEST\nnet/mptcp/Kconfig-26-\ttristate \"This builds the MPTCP KUnit tests\" if !KUNIT_ALL_TESTS\nnet/mptcp/Kconfig:27:\tdepends on KUNIT\nnet/mptcp/Kconfig-28-\tdefault KUNIT_ALL_TESTS\n"
} |
| 7/2 | 2026/08/12 08:04 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 7920 output: 170 thoughts: 26 Thoughts: Okay, here's my interpretation of those thoughts, framed as my own: **Enabling Multipath TCP (MPTCP)** Right, so I see that `CONFIG_MPTCP` is dependent on `INET`. That's standard; no surprises there. And given the advancements in this area and the potential benefits, it seems a logical next step to *enable* `MPTCP`. The advantages in terms of resilience and bandwidth utilization are compelling. Okay, now let's make sure we document this change. Let's call `set-results` to confirm the modification to the configuration has been made. |
| 8/2 | 2026/08/12 08:04 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"MPTCP"
],
"FocusSymbols": [
"mptcp_subflow_reqsk_clone",
"mptcp_token_move_request",
"mptcp_token_accept",
"mptcp_sk_clone_init"
],
"Reasoning": "The patch modifies the MPTCP subsystem to handle request socket cloning and token management. It introduces new functions `mptcp_subflow_reqsk_clone` and `mptcp_token_move_request`, and modifies `mptcp_token_accept` and `mptcp_sk_clone_init`. These are functional changes in the core networking stack that are reachable and should be fuzzed.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"MPTCP"
],
"FocusSymbols": [
"mptcp_subflow_reqsk_clone",
"mptcp_token_move_request",
"mptcp_token_accept",
"mptcp_sk_clone_init"
],
"Reasoning": "The patch modifies the MPTCP subsystem to handle request socket cloning and token management. It introduces new functions `mptcp_subflow_reqsk_clone` and `mptcp_token_move_request`, and modifies `mptcp_token_accept` and `mptcp_sk_clone_init`. These are functional changes in the core networking stack that are reachable and should be fuzzed.",
"WorthFuzzing": true
} |
| 9/1 | 2026/08/12 08:04 | action | If |
0mArgs:{
"WorthFuzzing": true
}Results: null |
| 10/2 | 2026/08/12 08:04 | agent | kmsan-evaluator |
0mModel:best-expensive Args: null Results: {
"KMSANReasoning": "The patch modifies the MPTCP subsystem to properly handle request socket cloning and token lifecycle management. The changes involve reference counting, hash list manipulation (hlist_nulls), and object ownership transfers. There are no new data structures exposed to userspace, nor are there any complex buffer allocations where uninitialized memory could be leaked or used in control flow. Any bugs introduced by these changes would manifest as use-after-free, double free, NULL pointer dereferences, or memory leaks, all of which are effectively detected by KASAN and standard kernel debugging tools. Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: For your convenience, here is the diff of the changes:
commit dfdbc50913f7c8b83115d624e1227d7d5d0918e1
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Aug 12 08:04:28 2026 +0000
syz-cluster: applied patch under review
diff --git a/include/net/mptcp.h b/include/net/mptcp.h
index 71b9fc5a57963..0a02ac1ed22d9 100644
--- a/include/net/mptcp.h
+++ b/include/net/mptcp.h
@@ -223,6 +223,8 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,
struct request_sock *mptcp_subflow_reqsk_alloc(const struct request_sock_ops *ops,
struct sock *sk_listener,
bool attach_listener);
+void mptcp_subflow_reqsk_clone(struct request_sock *req,
+ struct request_sock *new_req);
__be32 mptcp_get_reset_option(const struct sk_buff *skb);
@@ -309,6 +311,11 @@ static inline struct request_sock *mptcp_subflow_reqsk_alloc(const struct reques
return NULL;
}
+static inline void mptcp_subflow_reqsk_clone(struct request_sock *req,
+ struct request_sock *new_req)
+{
+}
+
static inline __be32 mptcp_reset_option(const struct sk_buff *skb) { return htonl(0u); }
static inline void mptcp_active_detect_blackhole(struct sock *sk, bool expired) { }
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 6257459bcee24..896f472dcba29 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -21,6 +21,7 @@
#include <net/xfrm.h>
#include <net/tcp.h>
#include <net/tcp_ecn.h>
+#include <net/mptcp.h>
#include <net/sock_reuseport.h>
#include <net/addrconf.h>
@@ -961,6 +962,9 @@ static struct request_sock *inet_reqsk_clone(struct request_sock *req,
rcu_assign_pointer(tcp_sk(nreq->sk)->fastopen_rsk, nreq);
}
+ if (rsk_is_mptcp(req))
+ mptcp_subflow_reqsk_clone(req, nreq);
+
return nreq;
}
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 7c8180d8d5eff..b05c8d37a0831 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3561,6 +3561,24 @@ static void mptcp_copy_ip_options(struct sock *newsk, const struct sock *sk)
rcu_read_unlock();
}
+static void mptcp_sk_clone_destroy(struct sock *nsk)
+{
+ struct mptcp_sock *msk = mptcp_sk(nsk);
+
+ mptcp_release_sched(msk);
+ mptcp_set_state(nsk, TCP_CLOSE);
+ /* inet_csk_prepare_forced_close() clears TCP sock_ops state via
+ * tcp_sk(), but nsk is an MPTCP master socket; keep the inet-level
+ * destroy preparation here.
+ */
+ bh_unlock_sock(nsk);
+ sock_put(nsk);
+ sock_set_flag(nsk, SOCK_DEAD);
+ tcp_orphan_count_inc();
+ inet_sk(nsk)->inet_num = 0;
+ inet_csk_destroy_sock(nsk);
+}
+
struct sock *mptcp_sk_clone_init(const struct sock *sk,
const struct mptcp_options_received *mp_opt,
struct sock *ssk,
@@ -3620,11 +3638,6 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
list_add(&subflow->node, &msk->conn_list);
sock_hold(ssk);
- /* new mpc subflow takes ownership of the newly
- * created mptcp socket
- */
- mptcp_token_accept(subflow_req, msk);
-
/* set msk addresses early to ensure mptcp_pm_get_local_id()
* uses the correct data
*/
@@ -3633,6 +3646,14 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk,
mptcp_rcv_space_init(msk, ssk);
msk->rcvq_space.time = mptcp_stamp();
+ if (!mptcp_token_accept(subflow_req, msk)) {
+ list_del_init(&subflow->node);
+ WRITE_ONCE(msk->first, NULL);
+ sock_put(ssk);
+ mptcp_sk_clone_destroy(nsk);
+ return NULL;
+ }
+
if (mp_opt->suboptions & OPTION_MPTCP_MPC_ACK)
__mptcp_subflow_fully_established(msk, subflow, mp_opt);
bh_unlock_sock(nsk);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 1b80f2d6ec5a2..69d531c770c44 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -1076,9 +1076,11 @@ static inline void mptcp_token_init_request(struct request_sock *req)
}
int mptcp_token_new_request(struct request_sock *req);
+void mptcp_token_move_request(struct request_sock *req,
+ struct request_sock *new_req);
void mptcp_token_destroy_request(struct request_sock *req);
int mptcp_token_new_connect(struct sock *ssk);
-void mptcp_token_accept(struct mptcp_subflow_request_sock *r,
+bool mptcp_token_accept(struct mptcp_subflow_request_sock *r,
struct mptcp_sock *msk);
bool mptcp_token_exists(u32 token);
struct mptcp_sock *mptcp_token_get_sock(struct net *net, u32 token);
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c
index e1f20ff8fdb42..d40ab09ab75b5 100644
--- a/net/mptcp/subflow.c
+++ b/net/mptcp/subflow.c
@@ -47,6 +47,19 @@ static void subflow_req_destructor(struct request_sock *req)
mptcp_token_destroy_request(req);
}
+void mptcp_subflow_reqsk_clone(struct request_sock *req,
+ struct request_sock *new_req)
+{
+ struct mptcp_subflow_request_sock *subflow_req;
+
+ subflow_req = mptcp_subflow_rsk(new_req);
+
+ if (subflow_req->msk)
+ sock_hold((struct sock *)subflow_req->msk);
+
+ mptcp_token_move_request(req, new_req);
+}
+
static void subflow_generate_hmac(u64 key1, u64 key2, u32 nonce1, u32 nonce2,
void *hmac)
{
diff --git a/net/mptcp/token.c b/net/mptcp/token.c
index f1a50f367add8..24877a2c37727 100644
--- a/net/mptcp/token.c
+++ b/net/mptcp/token.c
@@ -180,6 +180,36 @@ int mptcp_token_new_connect(struct sock *ssk)
return 0;
}
+void mptcp_token_move_request(struct request_sock *req,
+ struct request_sock *new_req)
+{
+ struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
+ struct mptcp_subflow_request_sock *new_subflow_req;
+ struct mptcp_subflow_request_sock *pos;
+ struct token_bucket *bucket;
+
+ new_subflow_req = mptcp_subflow_rsk(new_req);
+
+ if (hlist_nulls_unhashed_lockless(&subflow_req->token_node)) {
+ mptcp_token_init_request(new_req);
+ return;
+ }
+
+ bucket = token_bucket(subflow_req->token);
+ spin_lock_bh(&bucket->lock);
+ if (hlist_nulls_unhashed(&subflow_req->token_node)) {
+ mptcp_token_init_request(new_req);
+ } else {
+ pos = __token_lookup_req(bucket, subflow_req->token);
+ if (pos == subflow_req)
+ hlist_nulls_replace_init_rcu(&subflow_req->token_node,
+ &new_subflow_req->token_node);
+ else
+ mptcp_token_init_request(new_req);
+ }
+ spin_unlock_bh(&bucket->lock);
+}
+
/**
* mptcp_token_accept - replace a req sk with full sock in token hash
* @req: the request socket to be removed
@@ -187,24 +217,36 @@ int mptcp_token_new_connect(struct sock *ssk)
*
* Called when a SYN packet creates a new logical connection, i.e.
* is not a join request.
+ *
+ * Return: true on success.
*/
-void mptcp_token_accept(struct mptcp_subflow_request_sock *req,
+bool mptcp_token_accept(struct mptcp_subflow_request_sock *req,
struct mptcp_sock *msk)
{
struct mptcp_subflow_request_sock *pos;
struct sock *sk = (struct sock *)msk;
struct token_bucket *bucket;
+ bool ret = false;
- sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
bucket = token_bucket(req->token);
spin_lock_bh(&bucket->lock);
+ if (hlist_nulls_unhashed(&req->token_node))
+ goto unlock;
- /* pedantic lookup check for the moved token */
pos = __token_lookup_req(bucket, req->token);
- if (!WARN_ON_ONCE(pos != req))
- hlist_nulls_del_init_rcu(&req->token_node);
+ if (pos != req)
+ goto unlock;
+
+ hlist_nulls_del_init_rcu(&req->token_node);
__sk_nulls_add_node_rcu((struct sock *)msk, &bucket->msk_chain);
+ ret = true;
+
+unlock:
spin_unlock_bh(&bucket->lock);
+ if (ret)
+ sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+
+ return ret;
}
bool mptcp_token_exists(u32 token)
@@ -355,16 +397,21 @@ void mptcp_token_destroy_request(struct request_sock *req)
struct mptcp_subflow_request_sock *pos;
struct token_bucket *bucket;
- if (hlist_nulls_unhashed(&subflow_req->token_node))
+ if (hlist_nulls_unhashed_lockless(&subflow_req->token_node))
return;
bucket = token_bucket(subflow_req->token);
spin_lock_bh(&bucket->lock);
+ if (hlist_nulls_unhashed(&subflow_req->token_node))
+ goto unlock;
+
pos = __token_lookup_req(bucket, subflow_req->token);
- if (!WARN_ON_ONCE(pos != subflow_req)) {
+ if (pos == subflow_req) {
hlist_nulls_del_init_rcu(&pos->token_node);
bucket->chain_len--;
}
+
+unlock:
spin_unlock_bh(&bucket->lock);
}
diff --git a/net/mptcp/token_test.c b/net/mptcp/token_test.c
index 4fc39fa2e262d..be9acce8a5673 100644
--- a/net/mptcp/token_test.c
+++ b/net/mptcp/token_test.c
@@ -99,7 +99,7 @@ static void mptcp_token_test_accept(struct kunit *test)
KUNIT_ASSERT_EQ(test, 0,
mptcp_token_new_request((struct request_sock *)req));
msk->token = req->token;
- mptcp_token_accept(req, msk);
+ KUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));
KUNIT_EXPECT_PTR_EQ(test, msk, mptcp_token_get_sock(&init_net, msk->token));
/* this is now a no-op */
@@ -122,7 +122,7 @@ static void mptcp_token_test_destroyed(struct kunit *test)
KUNIT_ASSERT_EQ(test, 0,
mptcp_token_new_request((struct request_sock *)req));
msk->token = req->token;
- mptcp_token_accept(req, msk);
+ KUNIT_EXPECT_TRUE(test, mptcp_token_accept(req, msk));
/* simulate race on removal */
refcount_set(&sk->sk_refcnt, 0);
|
| 11/3 | 2026/08/12 08:04 | llm | kmsan-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 5626 output: 153 thoughts: 871 Thoughts: **MPTCP Request Socket and Token Lifecycle Management** Okay, so this patch is clearly focused on refining how MPTCP manages request sockets and tokens, specifically during cloning operations, which I'm assuming are similar to SYN cookie mechanisms. The modifications revolve around the lifecycle of these objects within the MPTCP subsystem of the Linux kernel. No new user-space exposed structures or uninitialized fields are introduced, which is good. My immediate assessment is that these changes are primarily about pointer manipulation, reference counting (including `sock_hold`), and the management of hash lists (`hlist_nulls`). This points toward the standard risks in kernel development: use-after-free, double-free, NULL pointer dereferences, or memory leaks. The good news is that these are precisely the kinds of issues KASAN and memory leak detectors are designed to catch. I see no immediate red flags regarding uninitialized memory being either used in control flow or leaked to userspace. Let me quickly re-examine that `mptcp_subflow_reqsk_clone` function. Okay, it looks like it's taking a cloned request socket (`new_req`) and performing some MPTCP-specific initialization, specifically handling the `msk` and moving the token. It's calling `inet_reqsk_clone` which, importantly, copies fields from the original (`req`) to the clone (`nreq`). So, after a quick look, the memory initialization within the cloned object seems sound. Now, let's take a quick look at `mptcp_token_move_request`. Alright, this function appears to be managing the transfer of tokens between the original and the cloned request sockets, with a significant emphasis on handling the hashed state of the tokens, including the lockless calls. So, the changes seem robust. I don't see any need for KMSAN. The core of the changes seem to be in object lifetime, reference count management and managing a hash table. The introduced bugs would be related to UAF, double-free, and null-dereference problems, which KASAN should be able to cover. |
| 12/3 | 2026/08/12 08:05 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch modifies the MPTCP subsystem to properly handle request socket cloning and token lifecycle management. The changes involve reference counting, hash list manipulation (hlist_nulls), and object ownership transfers. There are no new data structures exposed to userspace, nor are there any complex buffer allocations where uninitialized memory could be leaked or used in control flow. Any bugs introduced by these changes would manifest as use-after-free, double free, NULL pointer dereferences, or memory leaks, all of which are effectively detected by KASAN and standard kernel debugging tools. Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch modifies the MPTCP subsystem to properly handle request socket cloning and token lifecycle management. The changes involve reference counting, hash list manipulation (hlist_nulls), and object ownership transfers. There are no new data structures exposed to userspace, nor are there any complex buffer allocations where uninitialized memory could be leaked or used in control flow. Any bugs introduced by these changes would manifest as use-after-free, double free, NULL pointer dereferences, or memory leaks, all of which are effectively detected by KASAN and standard kernel debugging tools. Therefore, a dedicated KMSAN fuzzing session is not required.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|