| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/01 22:43 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": [
"MPTCP",
"MPTCP_IPV6"
],
"FocusSymbols": [
"mptcp_incoming_options",
"mptcp_data_ready",
"mptcp_recvmsg",
"mptcp_worker",
"mptcp_release_cb"
],
"Reasoning": "The patch modifies the MPTCP protocol implementation to handle memory limits by pruning the out-of-order queue and dropping packets from the backlog when limits are exceeded. It also fixes the retransmission logic to properly push retransmissions. These are functional changes to reachable core networking code and should be fuzzed to ensure they don't introduce memory leaks, use-after-free, or logic bugs under memory pressure.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/01 22:43 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit d3226f6fc1d406d3cf14f6f7d69ac8ed78b161c7\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Sat Aug 1 22:43:29 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/net/mptcp/mib.c b/net/mptcp/mib.c\nindex f23fda0c55a72..2569385bab7ca 100644\n--- a/net/mptcp/mib.c\n+++ b/net/mptcp/mib.c\n@@ -85,6 +85,9 @@ static const struct snmp_mib mptcp_snmp_list[] = {\n \tSNMP_MIB_ITEM(\"SimultConnectFallback\", MPTCP_MIB_SIMULTCONNFALLBACK),\n \tSNMP_MIB_ITEM(\"FallbackFailed\", MPTCP_MIB_FALLBACKFAILED),\n \tSNMP_MIB_ITEM(\"WinProbe\", MPTCP_MIB_WINPROBE),\n+\tSNMP_MIB_ITEM(\"BacklogDrop\", MPTCP_MIB_BACKLOGDROP),\n+\tSNMP_MIB_ITEM(\"RcvPruned\", MPTCP_MIB_RCVPRUNED),\n+\tSNMP_MIB_ITEM(\"OFOPruned\", MPTCP_MIB_OFOPRUNED),\n };\n \n /* mptcp_mib_alloc - allocate percpu mib counters\ndiff --git a/net/mptcp/mib.h b/net/mptcp/mib.h\nindex 812218b5ed2bf..3a3425e258a76 100644\n--- a/net/mptcp/mib.h\n+++ b/net/mptcp/mib.h\n@@ -88,6 +88,9 @@ enum linux_mptcp_mib_field {\n \tMPTCP_MIB_SIMULTCONNFALLBACK,\t/* Simultaneous connect */\n \tMPTCP_MIB_FALLBACKFAILED,\t/* Can't fallback due to msk status */\n \tMPTCP_MIB_WINPROBE,\t\t/* MPTCP-level zero window probe */\n+\tMPTCP_MIB_BACKLOGDROP,\t\t/* Backlog over memory limit */\n+\tMPTCP_MIB_RCVPRUNED,\t\t/* Dropped due to memory constraints */\n+\tMPTCP_MIB_OFOPRUNED,\t\t/* MPTCP-level OoO queue pruned */\n \t__MPTCP_MIB_MAX\n };\n \ndiff --git a/net/mptcp/options.c b/net/mptcp/options.c\nindex c664023d37ba8..5642277c8b3d0 100644\n--- a/net/mptcp/options.c\n+++ b/net/mptcp/options.c\n@@ -1127,8 +1127,34 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk,\n \treturn hmac == mp_opt-\u003eahmac;\n }\n \n-/* Return false in case of error (or subflow has been reset),\n- * else return true.\n+static bool mptcp_over_limit(struct sock *sk, struct sock *ssk,\n+\t\t\t const struct sk_buff *skb)\n+{\n+\tstruct mptcp_sock *msk = mptcp_sk(sk);\n+\tu64 mem = sk_rmem_alloc_get(sk);\n+\n+\tmem += READ_ONCE(msk-\u003ebacklog_len);\n+\tif (likely(mem \u003c= READ_ONCE(sk-\u003esk_rcvbuf)))\n+\t\treturn false;\n+\n+\t/* Avoid silently dropping pure acks, fin or already-acked segments. */\n+\tif (TCP_SKB_CB(skb)-\u003eseq == TCP_SKB_CB(skb)-\u003eend_seq ||\n+\t TCP_SKB_CB(skb)-\u003etcp_flags \u0026 TCPHDR_FIN ||\n+\t !after(TCP_SKB_CB(skb)-\u003eend_seq, tcp_sk(ssk)-\u003ercv_nxt))\n+\t\treturn false;\n+\n+\t/* Dropped due to memory constraints, schedule an ack. */\n+\tinet_csk(ssk)-\u003eicsk_ack.pending |= ICSK_ACK_NOMEM | ICSK_ACK_NOW;\n+\tinet_csk_schedule_ack(ssk);\n+\n+\t/* Plain TCP (fallback) and skb is dropped before the TCP recv queue. */\n+\tNET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVQDROP);\n+\n+\treturn true;\n+}\n+\n+/* Return false when the caller must drop the packet, i.e. in case of error,\n+ * subflow has been reset, or over memory limits.\n */\n bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)\n {\n@@ -1154,7 +1180,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)\n \n \t\t__mptcp_data_acked(subflow-\u003econn);\n \t\tmptcp_data_unlock(subflow-\u003econn);\n-\t\treturn true;\n+\t\treturn !mptcp_over_limit(subflow-\u003econn, sk, skb);\n \t}\n \n \tmptcp_get_options(skb, \u0026mp_opt);\ndiff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c\nindex ca644ec53eedb..68c9d952d1d3d 100644\n--- a/net/mptcp/protocol.c\n+++ b/net/mptcp/protocol.c\n@@ -373,6 +373,49 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offset,\n \tskb_dst_drop(skb);\n }\n \n+/* \"Inspired\" from the TCP version; main difference: stop as soon as the MPTCP\n+ * socket is under memory limit.\n+ */\n+static bool mptcp_prune_ofo_queue(struct sock *sk, u64 seq)\n+{\n+\tstruct mptcp_sock *msk = mptcp_sk(sk);\n+\tstruct rb_node *node, *prev;\n+\tbool pruned = false;\n+\tu64 mem;\n+\n+\tif (RB_EMPTY_ROOT(\u0026msk-\u003eout_of_order_queue))\n+\t\tgoto out;\n+\n+\tnode = \u0026msk-\u003eooo_last_skb-\u003erbnode;\n+\n+\tdo {\n+\t\tstruct sk_buff *skb = rb_to_skb(node);\n+\n+\t\t/* Stop pruning if the incoming skb would land in OoO tail. */\n+\t\tif (after64(seq, MPTCP_SKB_CB(skb)-\u003emap_seq))\n+\t\t\tbreak;\n+\n+\t\tpruned = true;\n+\t\tprev = rb_prev(node);\n+\t\trb_erase(node, \u0026msk-\u003eout_of_order_queue);\n+\t\tmptcp_drop(sk, skb);\n+\t\tmsk-\u003eooo_last_skb = rb_to_skb(prev);\n+\n+\t\tmem = (unsigned int)sk_rmem_alloc_get(sk);\n+\t\tif (mem \u003c= sk-\u003esk_rcvbuf)\n+\t\t\tbreak;\n+\n+\t\tnode = prev;\n+\t} while (node);\n+\n+\tif (pruned)\n+\t\tMPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOPRUNED);\n+\n+out:\n+\tmem = (unsigned int)sk_rmem_alloc_get(sk);\n+\treturn mem \u003c= sk-\u003esk_rcvbuf;\n+}\n+\n static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)\n {\n \tu64 copy_len = MPTCP_SKB_CB(skb)-\u003eend_seq - MPTCP_SKB_CB(skb)-\u003emap_seq;\n@@ -381,6 +424,17 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)\n \n \tmptcp_borrow_fwdmem(sk, skb);\n \n+\t/* Can't drop packets for fallback socket this late, or the stream\n+\t * will break.\n+\t */\n+\tif (unlikely(sk_rmem_alloc_get(sk) \u003e READ_ONCE(sk-\u003esk_rcvbuf)) \u0026\u0026\n+\t !__mptcp_check_fallback(msk) \u0026\u0026\n+\t !mptcp_prune_ofo_queue(sk, MPTCP_SKB_CB(skb)-\u003emap_seq)) {\n+\t\tMPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED);\n+\t\tmptcp_drop(sk, skb);\n+\t\treturn false;\n+\t}\n+\n \tif (MPTCP_SKB_CB(skb)-\u003emap_seq == msk-\u003eack_seq) {\n \t\t/* in sequence */\n \t\tmsk-\u003ebytes_received += copy_len;\n@@ -675,6 +729,7 @@ static void __mptcp_add_backlog(struct sock *sk,\n \tstruct sk_buff *tail = NULL;\n \tstruct sock *ssk = skb-\u003esk;\n \tbool fragstolen;\n+\tu64 limit;\n \tint delta;\n \n \tif (unlikely(sk-\u003esk_state == TCP_CLOSE)) {\n@@ -682,6 +737,16 @@ static void __mptcp_add_backlog(struct sock *sk,\n \t\treturn;\n \t}\n \n+\t/* Similar additional allowance as plain TCP. */\n+\tlimit = READ_ONCE(sk-\u003esk_rcvbuf);\n+\tlimit += (limit \u003e\u003e 1) + 64 * 1024;\n+\tlimit = min_t(u64, limit, UINT_MAX);\n+\tif (msk-\u003ebacklog_len \u003e limit \u0026\u0026 !__mptcp_check_fallback(msk)) {\n+\t\t__MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_BACKLOGDROP);\n+\t\tkfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_BACKLOG);\n+\t\treturn;\n+\t}\n+\n \t/* Try to coalesce with the last skb in our backlog */\n \tif (!list_empty(\u0026msk-\u003ebacklog_list))\n \t\ttail = list_last_entry(\u0026msk-\u003ebacklog_list, struct sk_buff, list);\n@@ -753,7 +818,7 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,\n \n \t\t\tmptcp_init_skb(ssk, skb, offset, len);\n \n-\t\t\tif (own_msk \u0026\u0026 sk_rmem_alloc_get(sk) \u003c sk-\u003esk_rcvbuf) {\n+\t\t\tif (own_msk) {\n \t\t\t\tmptcp_subflow_lend_fwdmem(subflow, skb);\n \t\t\t\tret |= __mptcp_move_skb(sk, skb);\n \t\t\t} else {\n@@ -1136,13 +1201,6 @@ static void __mptcp_clean_una_wakeup(struct sock *sk)\n \tmptcp_write_space(sk);\n }\n \n-static void mptcp_clean_una_wakeup(struct sock *sk)\n-{\n-\tmptcp_data_lock(sk);\n-\t__mptcp_clean_una_wakeup(sk);\n-\tmptcp_data_unlock(sk);\n-}\n-\n static void mptcp_enter_memory_pressure(struct sock *sk)\n {\n \tstruct mptcp_subflow_context *subflow;\n@@ -2209,12 +2267,7 @@ static bool __mptcp_move_skbs(struct sock *sk, struct list_head *skbs, u32 *delt\n \tstruct mptcp_sock *msk = mptcp_sk(sk);\n \tbool moved = false;\n \n-\t*delta = 0;\n \twhile (1) {\n-\t\t/* If the msk recvbuf is full stop, don't drop */\n-\t\tif (sk_rmem_alloc_get(sk) \u003e sk-\u003esk_rcvbuf)\n-\t\t\tbreak;\n-\n \t\tprefetch(skb-\u003enext);\n \t\tlist_del(\u0026skb-\u003elist);\n \t\t*delta += skb-\u003etruesize;\n@@ -2242,9 +2295,7 @@ static bool mptcp_can_spool_backlog(struct sock *sk, struct list_head *skbs)\n \tDEBUG_NET_WARN_ON_ONCE(msk-\u003ebacklog_unaccounted \u0026\u0026 sk-\u003esk_socket \u0026\u0026\n \t\t\t mem_cgroup_from_sk(sk));\n \n-\t/* Don't spool the backlog if the rcvbuf is full. */\n-\tif (list_empty(\u0026msk-\u003ebacklog_list) ||\n-\t sk_rmem_alloc_get(sk) \u003e sk-\u003esk_rcvbuf)\n+\tif (list_empty(\u0026msk-\u003ebacklog_list))\n \t\treturn false;\n \n \tINIT_LIST_HEAD(skbs);\n@@ -2252,20 +2303,12 @@ static bool mptcp_can_spool_backlog(struct sock *sk, struct list_head *skbs)\n \treturn true;\n }\n \n-static void mptcp_backlog_spooled(struct sock *sk, u32 moved,\n-\t\t\t\t struct list_head *skbs)\n-{\n-\tstruct mptcp_sock *msk = mptcp_sk(sk);\n-\n-\tWRITE_ONCE(msk-\u003ebacklog_len, msk-\u003ebacklog_len - moved);\n-\tlist_splice(skbs, \u0026msk-\u003ebacklog_list);\n-}\n-\n static bool mptcp_move_skbs(struct sock *sk)\n {\n+\tstruct mptcp_sock *msk = mptcp_sk(sk);\n \tstruct list_head skbs;\n \tbool enqueued = false;\n-\tu32 moved;\n+\tu32 moved = 0;\n \n \tmptcp_data_lock(sk);\n \twhile (mptcp_can_spool_backlog(sk, \u0026skbs)) {\n@@ -2273,8 +2316,8 @@ static bool mptcp_move_skbs(struct sock *sk)\n \t\tenqueued |= __mptcp_move_skbs(sk, \u0026skbs, \u0026moved);\n \n \t\tmptcp_data_lock(sk);\n-\t\tmptcp_backlog_spooled(sk, moved, \u0026skbs);\n \t}\n+\tWRITE_ONCE(msk-\u003ebacklog_len, msk-\u003ebacklog_len - moved);\n \tmptcp_data_unlock(sk);\n \n \tif (enqueued \u0026\u0026 mptcp_epollin_ready(sk))\n@@ -2785,44 +2828,22 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)\n \tsk_error_report(sk);\n }\n \n-static void __mptcp_retrans(struct sock *sk)\n+/*\n+ * Retransmit the specified data fragment on all the selected subflows,\n+ * starting from the specified sequence\n+ */\n+static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *dfrag,\n+\t\t\t\tu64 sent_seq)\n {\n \tstruct mptcp_sendmsg_info info = { .data_lock_held = true, };\n \tstruct mptcp_sock *msk = mptcp_sk(sk);\n \tstruct mptcp_subflow_context *subflow;\n-\tstruct mptcp_data_frag *dfrag;\n \tstruct sock *ssk;\n-\tint ret, err;\n-\tu16 len = 0;\n-\n-\tmptcp_clean_una_wakeup(sk);\n-\n-\t/* first check ssk: need to kick \"stale\" logic */\n-\terr = mptcp_sched_get_retrans(msk);\n-\tdfrag = mptcp_rtx_head(sk);\n-\tif (!dfrag) {\n-\t\tif (mptcp_data_fin_enabled(msk)) {\n-\t\t\tstruct inet_connection_sock *icsk = inet_csk(sk);\n-\n-\t\t\tWRITE_ONCE(icsk-\u003eicsk_retransmits,\n-\t\t\t\t icsk-\u003eicsk_retransmits + 1);\n-\t\t\tmptcp_set_datafin_timeout(sk);\n-\t\t\tmptcp_send_ack(msk);\n-\n-\t\t\tgoto reset_timer;\n-\t\t}\n-\n-\t\tif (!mptcp_send_head(sk))\n-\t\t\tgoto clear_scheduled;\n-\n-\t\tgoto reset_timer;\n-\t}\n-\n-\tif (err)\n-\t\tgoto reset_timer;\n+\tint ret, len = 0;\n \n \tmptcp_for_each_subflow(msk, subflow) {\n \t\tif (READ_ONCE(subflow-\u003escheduled)) {\n+\t\t\tu16 offset = sent_seq - dfrag-\u003edata_seq;\n \t\t\tu16 copied = 0;\n \n \t\t\tmptcp_subflow_set_scheduled(subflow, false);\n@@ -2832,7 +2853,7 @@ static void __mptcp_retrans(struct sock *sk)\n \t\t\tlock_sock(ssk);\n \n \t\t\t/* limit retransmission to the bytes already sent on some subflows */\n-\t\t\tinfo.sent = 0;\n+\t\t\tinfo.sent = offset;\n \t\t\tinfo.limit = READ_ONCE(msk-\u003ecsum_enabled) ? dfrag-\u003edata_len :\n \t\t\t\t\t\t\t\t dfrag-\u003ealready_sent;\n \n@@ -2847,7 +2868,7 @@ static void __mptcp_retrans(struct sock *sk)\n \t\t\t !msk-\u003eallow_subflows) {\n \t\t\t\tspin_unlock_bh(\u0026msk-\u003efallback_lock);\n \t\t\t\trelease_sock(ssk);\n-\t\t\t\tgoto clear_scheduled;\n+\t\t\t\treturn -1;\n \t\t\t}\n \n \t\t\twhile (info.sent \u003c info.limit) {\n@@ -2870,13 +2891,109 @@ static void __mptcp_retrans(struct sock *sk)\n \t\t\trelease_sock(ssk);\n \t\t}\n \t}\n+\treturn len;\n+}\n+\n+static void __mptcp_retrans(struct sock *sk)\n+{\n+\tstruct mptcp_sock *msk = mptcp_sk(sk);\n+\tstruct mptcp_subflow_context *subflow;\n+\tstruct mptcp_data_frag *dfrag;\n+\tbool need_retrans;\n+\tu64 retrans_seq;\n+\tint err, len;\n \n-\tmsk-\u003ebytes_retrans += len;\n-\tdfrag-\u003ealready_sent = max(dfrag-\u003ealready_sent, len);\n+\tmptcp_data_lock(sk);\n+\t__mptcp_clean_una_wakeup(sk);\n+\tretrans_seq = msk-\u003esnd_una;\n+\tdfrag = mptcp_rtx_head(sk);\n+\tneed_retrans = !!dfrag;\n+\tmptcp_data_unlock(sk);\n+\tif (!dfrag)\n+\t\tgoto check_data_fin;\n \n-\t/* With csum enabled retransmission can send new data. */\n-\tif (after64(dfrag-\u003ealready_sent + dfrag-\u003edata_seq, msk-\u003esnd_nxt))\n-\t\tWRITE_ONCE(msk-\u003esnd_nxt, dfrag-\u003ealready_sent + dfrag-\u003edata_seq);\n+\tfor (;;) {\n+\t\tbool already_retrans;\n+\t\tu64 sent_seq;\n+\n+\t\t/* The default scheduler will kick \"stale\" logic, that in\n+\t\t * turn can process incoming acks and clean the RTX queue;\n+\t\t * ensure that the current dfrag will still be around\n+\t\t * afterwards.\n+\t\t */\n+\t\tget_page(dfrag-\u003epage);\n+\t\terr = mptcp_sched_get_retrans(msk);\n+\t\tif (err) {\n+\t\t\tput_page(dfrag-\u003epage);\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* Incoming acks can have moved retrans sequence after\n+\t\t * the current dfrag, if so try to start again from RTX head.\n+\t\t */\n+\t\tmptcp_data_lock(sk);\n+\t\talready_retrans = !before64(msk-\u003esnd_una, dfrag-\u003edata_seq +\n+\t\t\t\t\t dfrag-\u003ealready_sent);\n+\t\tput_page(dfrag-\u003epage);\n+\t\tif (already_retrans) {\n+\t\t\t__mptcp_clean_una_wakeup(sk);\n+\t\t\tretrans_seq = msk-\u003esnd_una;\n+\t\t\tdfrag = mptcp_rtx_head(sk);\n+\t\t\tneed_retrans = !!dfrag;\n+\t\t} else if (after64(msk-\u003esnd_una, retrans_seq)) {\n+\t\t\tretrans_seq = msk-\u003esnd_una;\n+\t\t}\n+\t\tmptcp_data_unlock(sk);\n+\n+\t\t/* `already_sent` can be 0 for `dfrag` belonging to the RTX\n+\t\t * queue due to __mptcp_retransmit_pending_data().\n+\t\t */\n+\t\tif (!dfrag || !dfrag-\u003ealready_sent)\n+\t\t\tbreak;\n+\n+\t\t/* Can fail only in case of fallback. */\n+\t\tlen = __mptcp_push_retrans(sk, dfrag, retrans_seq);\n+\t\tif (len \u003c 0)\n+\t\t\tgoto clear_scheduled;\n+\n+\t\tretrans_seq += len;\n+\t\tmsk-\u003ebytes_retrans += len;\n+\t\tdfrag-\u003ealready_sent = max_t(u16, dfrag-\u003ealready_sent,\n+\t\t\t\t\t retrans_seq - dfrag-\u003edata_seq);\n+\n+\t\t/* With csum enabled retransmission can send new data. */\n+\t\tsent_seq = dfrag-\u003ealready_sent + dfrag-\u003edata_seq;\n+\t\tif (after64(sent_seq, msk-\u003esnd_nxt))\n+\t\t\tWRITE_ONCE(msk-\u003esnd_nxt, sent_seq);\n+\n+\t\t/* Attempt the next fragment only if the current one is\n+\t\t * completely retransmitted.\n+\t\t */\n+\t\tif (before64(retrans_seq, dfrag-\u003edata_seq + dfrag-\u003edata_len))\n+\t\t\tbreak;\n+\n+\t\tdfrag = list_is_last(\u0026dfrag-\u003elist, \u0026msk-\u003ertx_queue) ?\n+\t\t\t\tNULL : list_next_entry(dfrag, list);\n+\t\tif (!dfrag)\n+\t\t\tbreak;\n+\t}\n+\n+\t/* Attempt data-fin retransmission only when the RTX queue is empty. */\n+\tif (!need_retrans) {\n+check_data_fin:\n+\t\tif (mptcp_data_fin_enabled(msk)) {\n+\t\t\tstruct inet_connection_sock *icsk = inet_csk(sk);\n+\n+\t\t\tWRITE_ONCE(icsk-\u003eicsk_retransmits,\n+\t\t\t\t icsk-\u003eicsk_retransmits + 1);\n+\t\t\tmptcp_set_datafin_timeout(sk);\n+\t\t\tmptcp_send_ack(msk);\n+\t\t\tgoto reset_timer;\n+\t\t}\n+\n+\t\tif (!mptcp_send_head(sk))\n+\t\t\tgoto clear_scheduled;\n+\t}\n \n reset_timer:\n \tmptcp_check_and_set_pending(sk);\n@@ -3670,12 +3787,12 @@ static void mptcp_release_cb(struct sock *sk)\n \t__must_hold(\u0026sk-\u003esk_lock.slock)\n {\n \tstruct mptcp_sock *msk = mptcp_sk(sk);\n+\tu32 moved = 0;\n \n \tfor (;;) {\n \t\tunsigned long flags = (msk-\u003ecb_flags \u0026 MPTCP_FLAGS_PROCESS_CTX_NEED);\n \t\tstruct list_head join_list, skbs;\n \t\tbool spool_bl;\n-\t\tu32 moved;\n \n \t\tspool_bl = mptcp_can_spool_backlog(sk, \u0026skbs);\n \t\tif (!flags \u0026\u0026 !spool_bl)\n@@ -3708,9 +3825,9 @@ static void mptcp_release_cb(struct sock *sk)\n \n \t\tcond_resched();\n \t\tspin_lock_bh(\u0026sk-\u003esk_lock.slock);\n-\t\tif (spool_bl)\n-\t\t\tmptcp_backlog_spooled(sk, moved, \u0026skbs);\n \t}\n+\tif (moved)\n+\t\tWRITE_ONCE(msk-\u003ebacklog_len, msk-\u003ebacklog_len - moved);\n \n \tif (__test_and_clear_bit(MPTCP_CLEAN_UNA, \u0026msk-\u003ecb_flags))\n \t\t__mptcp_clean_una_wakeup(sk);\n"
} |
| 2/1 | 2026/08/01 22:43 | agent | patch-evaluator |
0mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"MPTCP",
"MPTCP_IPV6"
],
"FocusSymbols": [
"mptcp_incoming_options",
"mptcp_data_ready",
"mptcp_recvmsg",
"mptcp_worker",
"mptcp_release_cb"
],
"Reasoning": "The patch modifies the MPTCP protocol implementation to handle memory limits by pruning the out-of-order queue and dropping packets from the backlog when limits are exceeded. It also fixes the retransmission logic to properly push retransmissions. These are functional changes to reachable core networking code and should be fuzzed to ensure they don't introduce memory leaks, use-after-free, or logic bugs under memory pressure.",
"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 d3226f6fc1d406d3cf14f6f7d69ac8ed78b161c7
Author: syz-cluster <triage@syzkaller.com>
Date: Sat Aug 1 22:43:29 2026 +0000
syz-cluster: applied patch under review
diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c
index f23fda0c55a72..2569385bab7ca 100644
--- a/net/mptcp/mib.c
+++ b/net/mptcp/mib.c
@@ -85,6 +85,9 @@ static const struct snmp_mib mptcp_snmp_list[] = {
SNMP_MIB_ITEM("SimultConnectFallback", MPTCP_MIB_SIMULTCONNFALLBACK),
SNMP_MIB_ITEM("FallbackFailed", MPTCP_MIB_FALLBACKFAILED),
SNMP_MIB_ITEM("WinProbe", MPTCP_MIB_WINPROBE),
+ SNMP_MIB_ITEM("BacklogDrop", MPTCP_MIB_BACKLOGDROP),
+ SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED),
+ SNMP_MIB_ITEM("OFOPruned", MPTCP_MIB_OFOPRUNED),
};
/* mptcp_mib_alloc - allocate percpu mib counters
diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h
index 812218b5ed2bf..3a3425e258a76 100644
--- a/net/mptcp/mib.h
+++ b/net/mptcp/mib.h
@@ -88,6 +88,9 @@ enum linux_mptcp_mib_field {
MPTCP_MIB_SIMULTCONNFALLBACK, /* Simultaneous connect */
MPTCP_MIB_FALLBACKFAILED, /* Can't fallback due to msk status */
MPTCP_MIB_WINPROBE, /* MPTCP-level zero window probe */
+ MPTCP_MIB_BACKLOGDROP, /* Backlog over memory limit */
+ MPTCP_MIB_RCVPRUNED, /* Dropped due to memory constraints */
+ MPTCP_MIB_OFOPRUNED, /* MPTCP-level OoO queue pruned */
__MPTCP_MIB_MAX
};
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index c664023d37ba8..5642277c8b3d0 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -1127,8 +1127,34 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk,
return hmac == mp_opt->ahmac;
}
-/* Return false in case of error (or subflow has been reset),
- * else return true.
+static bool mptcp_over_limit(struct sock *sk, struct sock *ssk,
+ const struct sk_buff *skb)
+{
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ u64 mem = sk_rmem_alloc_get(sk);
+
+ mem += READ_ONCE(msk->backlog_len);
+ if (likely(mem <= READ_ONCE(sk->sk_rcvbuf)))
+ return false;
+
+ /* Avoid silently dropping pure acks, fin or already-acked segments. */
+ if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq ||
+ TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN ||
+ !after(TCP_SKB_CB(skb)->end_seq, tcp_sk(ssk)->rcv_nxt))
+ return false;
+
+ /* Dropped due to memory constraints, schedule an ack. */
+ inet_csk(ssk)->icsk_ack.pending |= ICSK_ACK_NOMEM | ICSK_ACK_NOW;
+ inet_csk_schedule_ack(ssk);
+
+ /* Plain TCP (fallback) and skb is dropped before the TCP recv queue. */
+ NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVQDROP);
+
+ return true;
+}
+
+/* Return false when the caller must drop the packet, i.e. in case of error,
+ * subflow has been reset, or over memory limits.
*/
bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
{
@@ -1154,7 +1180,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
__mptcp_data_acked(subflow->conn);
mptcp_data_unlock(subflow->conn);
- return true;
+ return !mptcp_over_limit(subflow->conn, sk, skb);
}
mptcp_get_options(skb, &mp_opt);
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index ca644ec53eedb..68c9d952d1d3d 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -373,6 +373,49 @@ static void mptcp_init_skb(struct sock *ssk, struct sk_buff *skb, int offset,
skb_dst_drop(skb);
}
+/* "Inspired" from the TCP version; main difference: stop as soon as the MPTCP
+ * socket is under memory limit.
+ */
+static bool mptcp_prune_ofo_queue(struct sock *sk, u64 seq)
+{
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ struct rb_node *node, *prev;
+ bool pruned = false;
+ u64 mem;
+
+ if (RB_EMPTY_ROOT(&msk->out_of_order_queue))
+ goto out;
+
+ node = &msk->ooo_last_skb->rbnode;
+
+ do {
+ struct sk_buff *skb = rb_to_skb(node);
+
+ /* Stop pruning if the incoming skb would land in OoO tail. */
+ if (after64(seq, MPTCP_SKB_CB(skb)->map_seq))
+ break;
+
+ pruned = true;
+ prev = rb_prev(node);
+ rb_erase(node, &msk->out_of_order_queue);
+ mptcp_drop(sk, skb);
+ msk->ooo_last_skb = rb_to_skb(prev);
+
+ mem = (unsigned int)sk_rmem_alloc_get(sk);
+ if (mem <= sk->sk_rcvbuf)
+ break;
+
+ node = prev;
+ } while (node);
+
+ if (pruned)
+ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OFOPRUNED);
+
+out:
+ mem = (unsigned int)sk_rmem_alloc_get(sk);
+ return mem <= sk->sk_rcvbuf;
+}
+
static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
{
u64 copy_len = MPTCP_SKB_CB(skb)->end_seq - MPTCP_SKB_CB(skb)->map_seq;
@@ -381,6 +424,17 @@ static bool __mptcp_move_skb(struct sock *sk, struct sk_buff *skb)
mptcp_borrow_fwdmem(sk, skb);
+ /* Can't drop packets for fallback socket this late, or the stream
+ * will break.
+ */
+ if (unlikely(sk_rmem_alloc_get(sk) > READ_ONCE(sk->sk_rcvbuf)) &&
+ !__mptcp_check_fallback(msk) &&
+ !mptcp_prune_ofo_queue(sk, MPTCP_SKB_CB(skb)->map_seq)) {
+ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RCVPRUNED);
+ mptcp_drop(sk, skb);
+ return false;
+ }
+
if (MPTCP_SKB_CB(skb)->map_seq == msk->ack_seq) {
/* in sequence */
msk->bytes_received += copy_len;
@@ -675,6 +729,7 @@ static void __mptcp_add_backlog(struct sock *sk,
struct sk_buff *tail = NULL;
struct sock *ssk = skb->sk;
bool fragstolen;
+ u64 limit;
int delta;
if (unlikely(sk->sk_state == TCP_CLOSE)) {
@@ -682,6 +737,16 @@ static void __mptcp_add_backlog(struct sock *sk,
return;
}
+ /* Similar additional allowance as plain TCP. */
+ limit = READ_ONCE(sk->sk_rcvbuf);
+ limit += (limit >> 1) + 64 * 1024;
+ limit = min_t(u64, limit, UINT_MAX);
+ if (msk->backlog_len > limit && !__mptcp_check_fallback(msk)) {
+ __MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_BACKLOGDROP);
+ kfree_skb_reason(skb, SKB_DROP_REASON_SOCKET_BACKLOG);
+ return;
+ }
+
/* Try to coalesce with the last skb in our backlog */
if (!list_empty(&msk->backlog_list))
tail = list_last_entry(&msk->backlog_list, struct sk_buff, list);
@@ -753,7 +818,7 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
mptcp_init_skb(ssk, skb, offset, len);
- if (own_msk && sk_rmem_alloc_get(sk) < sk->sk_rcvbuf) {
+ if (own_msk) {
mptcp_subflow_lend_fwdmem(subflow, skb);
ret |= __mptcp_move_skb(sk, skb);
} else {
@@ -1136,13 +1201,6 @@ static void __mptcp_clean_una_wakeup(struct sock *sk)
mptcp_write_space(sk);
}
-static void mptcp_clean_una_wakeup(struct sock *sk)
-{
- mptcp_data_lock(sk);
- __mptcp_clean_una_wakeup(sk);
- mptcp_data_unlock(sk);
-}
-
static void mptcp_enter_memory_pressure(struct sock *sk)
{
struct mptcp_subflow_context *subflow;
@@ -2209,12 +2267,7 @@ static bool __mptcp_move_skbs(struct sock *sk, struct list_head *skbs, u32 *delt
struct mptcp_sock *msk = mptcp_sk(sk);
bool moved = false;
- *delta = 0;
while (1) {
- /* If the msk recvbuf is full stop, don't drop */
- if (sk_rmem_alloc_get(sk) > sk->sk_rcvbuf)
- break;
-
prefetch(skb->next);
list_del(&skb->list);
*delta += skb->truesize;
@@ -2242,9 +2295,7 @@ static bool mptcp_can_spool_backlog(struct sock *sk, struct list_head *skbs)
DEBUG_NET_WARN_ON_ONCE(msk->backlog_unaccounted && sk->sk_socket &&
mem_cgroup_from_sk(sk));
- /* Don't spool the backlog if the rcvbuf is full. */
- if (list_empty(&msk->backlog_list) ||
- sk_rmem_alloc_get(sk) > sk->sk_rcvbuf)
+ if (list_empty(&msk->backlog_list))
return false;
INIT_LIST_HEAD(skbs);
@@ -2252,20 +2303,12 @@ static bool mptcp_can_spool_backlog(struct sock *sk, struct list_head *skbs)
return true;
}
-static void mptcp_backlog_spooled(struct sock *sk, u32 moved,
- struct list_head *skbs)
-{
- struct mptcp_sock *msk = mptcp_sk(sk);
-
- WRITE_ONCE(msk->backlog_len, msk->backlog_len - moved);
- list_splice(skbs, &msk->backlog_list);
-}
-
static bool mptcp_move_skbs(struct sock *sk)
{
+ struct mptcp_sock *msk = mptcp_sk(sk);
struct list_head skbs;
bool enqueued = false;
- u32 moved;
+ u32 moved = 0;
mptcp_data_lock(sk);
while (mptcp_can_spool_backlog(sk, &skbs)) {
@@ -2273,8 +2316,8 @@ static bool mptcp_move_skbs(struct sock *sk)
enqueued |= __mptcp_move_skbs(sk, &skbs, &moved);
mptcp_data_lock(sk);
- mptcp_backlog_spooled(sk, moved, &skbs);
}
+ WRITE_ONCE(msk->backlog_len, msk->backlog_len - moved);
mptcp_data_unlock(sk);
if (enqueued && mptcp_epollin_ready(sk))
@@ -2785,44 +2828,22 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
sk_error_report(sk);
}
-static void __mptcp_retrans(struct sock *sk)
+/*
+ * Retransmit the specified data fragment on all the selected subflows,
+ * starting from the specified sequence
+ */
+static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *dfrag,
+ u64 sent_seq)
{
struct mptcp_sendmsg_info info = { .data_lock_held = true, };
struct mptcp_sock *msk = mptcp_sk(sk);
struct mptcp_subflow_context *subflow;
- struct mptcp_data_frag *dfrag;
struct sock *ssk;
- int ret, err;
- u16 len = 0;
-
- mptcp_clean_una_wakeup(sk);
-
- /* first check ssk: need to kick "stale" logic */
- err = mptcp_sched_get_retrans(msk);
- dfrag = mptcp_rtx_head(sk);
- if (!dfrag) {
- if (mptcp_data_fin_enabled(msk)) {
- struct inet_connection_sock *icsk = inet_csk(sk);
-
- WRITE_ONCE(icsk->icsk_retransmits,
- icsk->icsk_retransmits + 1);
- mptcp_set_datafin_timeout(sk);
- mptcp_send_ack(msk);
-
- goto reset_timer;
- }
-
- if (!mptcp_send_head(sk))
- goto clear_scheduled;
-
- goto reset_timer;
- }
-
- if (err)
- goto reset_timer;
+ int ret, len = 0;
mptcp_for_each_subflow(msk, subflow) {
if (READ_ONCE(subflow->scheduled)) {
+ u16 offset = sent_seq - dfrag->data_seq;
u16 copied = 0;
mptcp_subflow_set_scheduled(subflow, false);
@@ -2832,7 +2853,7 @@ static void __mptcp_retrans(struct sock *sk)
lock_sock(ssk);
/* limit retransmission to the bytes already sent on some subflows */
- info.sent = 0;
+ info.sent = offset;
info.limit = READ_ONCE(msk->csum_enabled) ? dfrag->data_len :
dfrag->already_sent;
@@ -2847,7 +2868,7 @@ static void __mptcp_retrans(struct sock *sk)
!msk->allow_subflows) {
spin_unlock_bh(&msk->fallback_lock);
release_sock(ssk);
- goto clear_scheduled;
+ return -1;
}
while (info.sent < info.limit) {
@@ -2870,13 +2891,109 @@ static void __mptcp_retrans(struct sock *sk)
release_sock(ssk);
}
}
+ return len;
+}
+
+static void __mptcp_retrans(struct sock *sk)
+{
+ struct mptcp_sock *msk = mptcp_sk(sk);
+ struct mptcp_subflow_context *subflow;
+ struct mptcp_data_frag *dfrag;
+ bool need_retrans;
+ u64 retrans_seq;
+ int err, len;
- msk->bytes_retrans += len;
- dfrag->already_sent = max(dfrag->already_sent, len);
+ mptcp_data_lock(sk);
+ __mptcp_clean_una_wakeup(sk);
+ retrans_seq = msk->snd_una;
+ dfrag = mptcp_rtx_head(sk);
+ need_retrans = !!dfrag;
+ mptcp_data_unlock(sk);
+ if (!dfrag)
+ goto check_data_fin;
- /* With csum enabled retransmission can send new data. */
- if (after64(dfrag->already_sent + dfrag->data_seq, msk->snd_nxt))
- WRITE_ONCE(msk->snd_nxt, dfrag->already_sent + dfrag->data_seq);
+ for (;;) {
+ bool already_retrans;
+ u64 sent_seq;
+
+ /* The default scheduler will kick "stale" logic, that in
+ * turn can process incoming acks and clean the RTX queue;
+ * ensure that the current dfrag will still be around
+ * afterwards.
+ */
+ get_page(dfrag->page);
+ err = mptcp_sched_get_retrans(msk);
+ if (err) {
+ put_page(dfrag->page);
+ break;
+ }
+
+ /* Incoming acks can have moved retrans sequence after
+ * the current dfrag, if so try to start again from RTX head.
+ */
+ mptcp_data_lock(sk);
+ already_retrans = !before64(msk->snd_una, dfrag->data_seq +
+ dfrag->already_sent);
+ put_page(dfrag->page);
+ if (already_retrans) {
+ __mptcp_clean_una_wakeup(sk);
+ retrans_seq = msk->snd_una;
+ dfrag = mptcp_rtx_head(sk);
+ need_retrans = !!dfrag;
+ } else if (after64(msk->snd_una, retrans_seq)) {
+ retrans_seq = msk->snd_una;
+ }
+ mptcp_data_unlock(sk);
+
+ /* `already_sent` can be 0 for `dfrag` belonging to the RTX
+ * queue due to __mptcp_retransmit_pending_data().
+ */
+ if (!dfrag || !dfrag->already_sent)
+ break;
+
+ /* Can fail only in case of fallback. */
+ len = __mptcp_push_retrans(sk, dfrag, retrans_seq);
+ if (len < 0)
+ goto clear_scheduled;
+
+ retrans_seq += len;
+ msk->bytes_retrans += len;
+ dfrag->already_sent = max_t(u16, dfrag->already_sent,
+ retrans_seq - dfrag->data_seq);
+
+ /* With csum enabled retransmission can send new data. */
+ sent_seq = dfrag->already_sent + dfrag->data_seq;
+ if (after64(sent_seq, msk->snd_nxt))
+ WRITE_ONCE(msk->snd_nxt, sent_seq);
+
+ /* Attempt the next fragment only if the current one is
+ * completely retransmitted.
+ */
+ if (before64(retrans_seq, dfrag->data_seq + dfrag->data_len))
+ break;
+
+ dfrag = list_is_last(&dfrag->list, &msk->rtx_queue) ?
+ NULL : list_next_entry(dfrag, list);
+ if (!dfrag)
+ break;
+ }
+
+ /* Attempt data-fin retransmission only when the RTX queue is empty. */
+ if (!need_retrans) {
+check_data_fin:
+ if (mptcp_data_fin_enabled(msk)) {
+ struct inet_connection_sock *icsk = inet_csk(sk);
+
+ WRITE_ONCE(icsk->icsk_retransmits,
+ icsk->icsk_retransmits + 1);
+ mptcp_set_datafin_timeout(sk);
+ mptcp_send_ack(msk);
+ goto reset_timer;
+ }
+
+ if (!mptcp_send_head(sk))
+ goto clear_scheduled;
+ }
reset_timer:
mptcp_check_and_set_pending(sk);
@@ -3670,12 +3787,12 @@ static void mptcp_release_cb(struct sock *sk)
__must_hold(&sk->sk_lock.slock)
{
struct mptcp_sock *msk = mptcp_sk(sk);
+ u32 moved = 0;
for (;;) {
unsigned long flags = (msk->cb_flags & MPTCP_FLAGS_PROCESS_CTX_NEED);
struct list_head join_list, skbs;
bool spool_bl;
- u32 moved;
spool_bl = mptcp_can_spool_backlog(sk, &skbs);
if (!flags && !spool_bl)
@@ -3708,9 +3825,9 @@ static void mptcp_release_cb(struct sock *sk)
cond_resched();
spin_lock_bh(&sk->sk_lock.slock);
- if (spool_bl)
- mptcp_backlog_spooled(sk, moved, &skbs);
}
+ if (moved)
+ WRITE_ONCE(msk->backlog_len, msk->backlog_len - moved);
if (__test_and_clear_bit(MPTCP_CLEAN_UNA, &msk->cb_flags))
__mptcp_clean_una_wakeup(sk);
|
| 3/2 | 2026/08/01 22:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 8070 output: 33 thoughts: 533 Thoughts: **MPTCP Memory Management and Retransmission Improvements** Okay, so I've got this patch series that's been applied to the kernel, specifically hitting the MPTCP implementation. It's touching `net/mptcp/mib.c`, `mib.h`, `options.c`, and `protocol.c`. Looks like they've added some SNMP MIB counters for MPTCP - BacklogDrop, RcvPruned, and OFOPruned, which is good for monitoring. The core of this seems to be about managing memory limits and improving retransmission. They've made some key modifications. The `mptcp_incoming_options` function is modified to check `mptcp_over_limit`. Also added are `mptcp_prune_ofo_queue` and the `__mptcp_move_skb` functions to handle pruning the out-of-order queue when memory goes over the defined limit. The `__mptcp_add_backlog` is updated to drop packets when the backlog exceeds the limit. Importantly, `__mptcp_retrans` has been changed to push retransmissions correctly. It seems like a clean-up of some important memory management bugs in MPTCP. This is a functional change, a pretty significant one at that. It handles the memory limits, both pruning and dropping, and looks like it fixes some retransmission issues. Given the changes to critical logic, this is *definitely* worth a solid fuzzing effort to identify the side effects of memory limit handling. Alright, let's zero in on the relevant symbols. The changed/added functions are the place to start. I see `mptcp_over_limit` (static), `mptcp_incoming_options` (non-static), `mptcp_prune_ofo_queue` (static), `__mptcp_move_skb` (static), `__mptcp_add_backlog` (static), `__mptcp_move_skbs_from_subflow` (static), `__mptcp_clean_una_wakeup` (static), `mptcp_can_spool_backlog` (static), `mptcp_move_skbs` (static), `__mptcp_push_retrans` (static), `__mptcp_retrans` (static) and `mptcp_release_cb` (static). Wait, hang on... `mptcp_incoming_options` is non-static? Okay, that's potentially an entry point. The static ones are where the core changes are, but that non-static one is crucial to see how it's invoked. We can't immediately see the impact. Let's check `net/mptcp/protocol.c` for any non-static functions that are calling the modified static functions. We need to see how these limit checks are being triggered. If there is a non-static entry point, we have a candidate for focused testing. `__mptcp_retrans`, is called by `mptcp_worker` or similar? Let's verify that. This needs some dedicated attention. |
| 4/2 | 2026/08/01 22:43 | tool | grepper |
0mArgs:{
"Expression": "__mptcp_retrans",
"PathPrefix": "net/mptcp/"
}Results: {
"Output": "net/mptcp/pm.c=1063=static void mptcp_pm_subflows_chk_stale(const struct mptcp_sock *msk, struct sock *ssk)\n--\nnet/mptcp/pm.c-1084-\t\t\t\tsubflow-\u003estale = 1;\nnet/mptcp/pm.c:1085:\t\t\t\t__mptcp_retransmit_pending_data(sk);\nnet/mptcp/pm.c-1086-\t\t\t\tMPTCP_INC_STATS(net, MPTCP_MIB_SUBFLOWSTALE);\n--\nnet/mptcp/protocol.c=2495=struct sock *mptcp_subflow_get_retrans(struct mptcp_sock *msk)\n--\nnet/mptcp/protocol.c-2530-\nnet/mptcp/protocol.c:2531:bool __mptcp_retransmit_pending_data(struct sock *sk)\nnet/mptcp/protocol.c-2532-{\n--\nnet/mptcp/protocol.c=2615=static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,\n--\nnet/mptcp/protocol.c-2664-\nnet/mptcp/protocol.c:2665:\tneed_push = (flags \u0026 MPTCP_CF_PUSH) \u0026\u0026 __mptcp_retransmit_pending_data(sk);\nnet/mptcp/protocol.c-2666-\tif (!dispose_it) {\n--\nnet/mptcp/protocol.c=2835=static int __mptcp_push_retrans(struct sock *sk, struct mptcp_data_frag *dfrag,\n--\nnet/mptcp/protocol.c-2896-\nnet/mptcp/protocol.c:2897:static void __mptcp_retrans(struct sock *sk)\nnet/mptcp/protocol.c-2898-{\n--\nnet/mptcp/protocol.c-2948-\t\t/* `already_sent` can be 0 for `dfrag` belonging to the RTX\nnet/mptcp/protocol.c:2949:\t\t * queue due to __mptcp_retransmit_pending_data().\nnet/mptcp/protocol.c-2950-\t\t */\n--\nnet/mptcp/protocol.c=3106=static void mptcp_worker(struct work_struct *work)\n--\nnet/mptcp/protocol.c-3143-\tif (test_and_clear_bit(MPTCP_WORK_RTX, \u0026msk-\u003eflags))\nnet/mptcp/protocol.c:3144:\t\t__mptcp_retrans(sk);\nnet/mptcp/protocol.c-3145-\n--\nnet/mptcp/protocol.c=3786=static void mptcp_release_cb(struct sock *sk)\n--\nnet/mptcp/protocol.c-3818-\t\tif (flags \u0026 BIT(MPTCP_RETRANSMIT))\nnet/mptcp/protocol.c:3819:\t\t\t__mptcp_retrans(sk);\nnet/mptcp/protocol.c-3820-\t\tif (spool_bl \u0026\u0026 __mptcp_move_skbs(sk, \u0026skbs, \u0026moved)) {\n--\nnet/mptcp/protocol.h=808=void __mptcp_subflow_fully_established(struct mptcp_sock *msk,\n--\nnet/mptcp/protocol.h-810-\t\t\t\t const struct mptcp_options_received *mp_opt);\nnet/mptcp/protocol.h:811:bool __mptcp_retransmit_pending_data(struct sock *sk);\nnet/mptcp/protocol.h-812-void mptcp_check_and_set_pending(struct sock *sk);\n"
} |
| 5/2 | 2026/08/01 22:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10311 output: 35 thoughts: 62 Thoughts: **Analyzing MPTCP Retransmission and Backlog Management** Okay, so I'm looking into the Multipath TCP (MPTCP) code again, specifically around retransmissions and backlog management. I've noticed that `mptcp_worker` and `mptcp_release_cb` both call the internal function `__mptcp_retrans`, which is where the core retransmission logic seems to reside. That makes sense, those are worker threads dealing with retransmissions. Then, there's `mptcp_incoming_options`, which is exported, meaning it's visible outside the MPTCP module itself, and not a static function. That's a point of interest, could be used by other parts of the kernel. I'll need to check how it's being used later. My main focus right now is on the backlog, and how it's handled, so I need to check the callers of `__mptcp_add_backlog`. I'll need to trace the flow from there and figure out if there's anything unusual or potentially problematic happening. Specifically, I'm interested in how these backlog additions interact with the retransmission process I was looking at earlier. There might be some interesting interactions there that need to be examined carefully. |
| 6/2 | 2026/08/01 22:43 | tool | grepper |
0mArgs:{
"Expression": "__mptcp_add_backlog",
"PathPrefix": "net/mptcp/"
}Results: {
"Output": "net/mptcp/protocol.c=716=static void mptcp_dss_corruption(struct mptcp_sock *msk, struct sock *ssk)\n--\nnet/mptcp/protocol.c-723-\nnet/mptcp/protocol.c:724:static void __mptcp_add_backlog(struct sock *sk,\nnet/mptcp/protocol.c-725-\t\t\t\tstruct mptcp_subflow_context *subflow,\n--\nnet/mptcp/protocol.c=777=static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,\n--\nnet/mptcp/protocol.c-824-\t\t\t} else {\nnet/mptcp/protocol.c:825:\t\t\t\t__mptcp_add_backlog(sk, subflow, skb);\nnet/mptcp/protocol.c-826-\t\t\t}\n"
} |
| 7/2 | 2026/08/01 22:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 10926 output: 40 thoughts: 48 Thoughts: Okay, here's my interpretation of this flow, presented as my own thought process, as requested: **Deconstructing the MPTCP SKB Movement** Alright, let's break this down. I see `__mptcp_move_skbs_from_subflow` calling `__mptcp_add_backlog`. That's the core relationship here. I understand the general intent of moving SKBs (Socket Buffer) between subflows, and adding them to a backlog makes perfect sense in that context. But my immediate question is: *what triggers this whole sequence?* Who's actually *calling* `__mptcp_move_skbs_from_subflow`? Knowing the caller is critical for understanding the context. Is this a congestion control mechanism, a failover procedure, a re-establishment of a subflow, or something else entirely? Without that upstream context, this is just a single link in a much larger chain. I need to trace back from that function to get a handle on what’s actually happening. Time to dig into the call stacks. |
| 8/2 | 2026/08/01 22:43 | tool | grepper |
0mArgs:{
"Expression": "__mptcp_move_skbs_from_subflow",
"PathPrefix": "net/mptcp/"
}Results: {
"Output": "net/mptcp/protocol.c=724=static void __mptcp_add_backlog(struct sock *sk,\n--\nnet/mptcp/protocol.c-776-\nnet/mptcp/protocol.c:777:static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,\nnet/mptcp/protocol.c-778-\t\t\t\t\t struct sock *ssk, bool own_msk)\n--\nnet/mptcp/protocol.c=941=static bool move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)\n--\nnet/mptcp/protocol.c-945-\nnet/mptcp/protocol.c:946:\tmoved = __mptcp_move_skbs_from_subflow(msk, ssk, true);\nnet/mptcp/protocol.c-947-\t__mptcp_ofo_queue(msk);\n--\nnet/mptcp/protocol.c=987=void mptcp_data_ready(struct sock *sk, struct sock *ssk)\n--\nnet/mptcp/protocol.c-1005-\t} else {\nnet/mptcp/protocol.c:1006:\t\t__mptcp_move_skbs_from_subflow(msk, ssk, false);\nnet/mptcp/protocol.c-1007-\t}\n"
} |
| 9/2 | 2026/08/01 22:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11614 output: 34 thoughts: 102 Thoughts: Okay, let's break this down. **MPTCP Code Review Considerations** Right, so I'm looking at this MPTCP code, specifically focusing on function scope and how it's used. The `mptcp_data_ready` function isn't static, and it calls `__mptcp_move_skbs_from_subflow`, which I'll have to investigate further for potential scope implications. `mptcp_incoming_options` is also non-static, which is worth noting. Now, the `mptcp_worker` function *is* static, but it's a workqueue callback, so the static keyword is probably less critical there, but I'll make sure it's used correctly within its context. Similarly, `mptcp_release_cb` is static, but it's a socket release callback. Its usage is contained. The question that jumps out is, what's the deal with `mptcp_move_skbs`? I'll need to check the function's declaration to see if it's static or not and understand its scope and usage within the overall MPTCP structure. This is something I'll need to investigate further. |
| 10/2 | 2026/08/01 22:43 | tool | grepper |
0mArgs:{
"Expression": "mptcp_move_skbs",
"PathPrefix": "net/mptcp/"
}Results: {
"Output": "net/mptcp/protocol.c=724=static void __mptcp_add_backlog(struct sock *sk,\n--\nnet/mptcp/protocol.c-776-\nnet/mptcp/protocol.c:777:static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,\nnet/mptcp/protocol.c-778-\t\t\t\t\t struct sock *ssk, bool own_msk)\n--\nnet/mptcp/protocol.c=941=static bool move_skbs_to_msk(struct mptcp_sock *msk, struct sock *ssk)\n--\nnet/mptcp/protocol.c-945-\nnet/mptcp/protocol.c:946:\tmoved = __mptcp_move_skbs_from_subflow(msk, ssk, true);\nnet/mptcp/protocol.c-947-\t__mptcp_ofo_queue(msk);\n--\nnet/mptcp/protocol.c=987=void mptcp_data_ready(struct sock *sk, struct sock *ssk)\n--\nnet/mptcp/protocol.c-1005-\t} else {\nnet/mptcp/protocol.c:1006:\t\t__mptcp_move_skbs_from_subflow(msk, ssk, false);\nnet/mptcp/protocol.c-1007-\t}\n--\nnet/mptcp/protocol.c=2210=static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)\n--\nnet/mptcp/protocol.c-2263-\nnet/mptcp/protocol.c:2264:static bool __mptcp_move_skbs(struct sock *sk, struct list_head *skbs, u32 *delta)\nnet/mptcp/protocol.c-2265-{\n--\nnet/mptcp/protocol.c=2288=static bool mptcp_can_spool_backlog(struct sock *sk, struct list_head *skbs)\n--\nnet/mptcp/protocol.c-2305-\nnet/mptcp/protocol.c:2306:static bool mptcp_move_skbs(struct sock *sk)\nnet/mptcp/protocol.c-2307-{\n--\nnet/mptcp/protocol.c-2315-\t\tmptcp_data_unlock(sk);\nnet/mptcp/protocol.c:2316:\t\tenqueued |= __mptcp_move_skbs(sk, \u0026skbs, \u0026moved);\nnet/mptcp/protocol.c-2317-\n--\nnet/mptcp/protocol.c=2350=static int mptcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,\n--\nnet/mptcp/protocol.c-2393-\nnet/mptcp/protocol.c:2394:\t\tif (!list_empty(\u0026msk-\u003ebacklog_list) \u0026\u0026 mptcp_move_skbs(sk))\nnet/mptcp/protocol.c-2395-\t\t\tcontinue;\n--\nnet/mptcp/protocol.c=3786=static void mptcp_release_cb(struct sock *sk)\n--\nnet/mptcp/protocol.c-3819-\t\t\t__mptcp_retrans(sk);\nnet/mptcp/protocol.c:3820:\t\tif (spool_bl \u0026\u0026 __mptcp_move_skbs(sk, \u0026skbs, \u0026moved)) {\nnet/mptcp/protocol.c-3821-\t\t\t/* notify ack seq update */\n--\nnet/mptcp/protocol.c=4078=static int mptcp_ioctl(struct sock *sk, int cmd, int *karg)\n--\nnet/mptcp/protocol.c-4088-\t\tlock_sock(sk);\nnet/mptcp/protocol.c:4089:\t\tif (mptcp_move_skbs(sk))\nnet/mptcp/protocol.c-4090-\t\t\tmptcp_cleanup_rbuf(msk, 0);\n--\nnet/mptcp/protocol.c=4495=static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off)\n--\nnet/mptcp/protocol.c-4501-\tif (!list_empty(\u0026msk-\u003ebacklog_list))\nnet/mptcp/protocol.c:4502:\t\tmptcp_move_skbs(sk);\nnet/mptcp/protocol.c-4503-\n"
} |
| 11/2 | 2026/08/01 22:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13195 output: 30 thoughts: 317 Thoughts: **Analyzing MPTCP Data Flow** Okay, so I'm diving into this MPTCP code, trying to get a handle on the data flow, specifically where the core processing happens. It's clear that `mptcp_move_skbs` is a critical function, as it's called from several places: `mptcp_recvmsg`, `mptcp_ioctl`, and `mptcp_recv_skb`. Therefore, those three functions are definitely candidates for key focus points in my analysis. Beyond those, I need to figure out the other main entry points. I initially considered `mptcp_incoming_options`, and `mptcp_data_ready` as likely candidates, but I have a few other potential points to look at. I'm also thinking about `__mptcp_retrans`. It's called by `mptcp_worker` and `mptcp_release_cb`. Ah, `mptcp_worker` is a workqueue callback and `mptcp_release_cb` is a socket release callback. I initially dismissed them, but now I'm reconsidering. I'll start with focusing on `mptcp_incoming_options`, `mptcp_data_ready` and `mptcp_recvmsg`. Wait, wait... hang on. `mptcp_worker` is *static*, but it's the main worker for MPTCP, right? I need to understand that. Is there a non-static function that *triggers* retransmissions? I need to trace this back. So, `mptcp_worker` is registered as a workqueue item, and `mptcp_release_cb` is registered as the `sk->sk_prot->release_cb`. Right. Okay. Time to check the Kconfig options for MPTCP and see if those offer any insights. |
| 12/2 | 2026/08/01 22:43 | tool | grepper |
0mArgs:{
"Expression": "config MPTCP",
"PathPrefix": "net/mptcp/"
}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"
} |
| 13/2 | 2026/08/01 22:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14171 output: 34 thoughts: 21 Thoughts: Here's my thought process, summarized as you requested: **Assessing the Configuration** Alright, so we're dealing with `MPTCP` configuration here. My immediate thought is, let's establish that as the primary area of focus. Now, the next logical step, before diving into details, is to quickly rule out other potentially relevant configurations. We need to ascertain if this is the *only* configuration involved or if there are others that might interact with, or influence, the `MPTCP` setup. The priority is a comprehensive understanding, so let's start with a preliminary sweep to check for any adjacent settings. |
| 14/2 | 2026/08/01 22:43 | tool | read-file |
0mArgs:{
"File": "net/mptcp/Kconfig",
"FirstLine": 1,
"LineCount": 20
}Results: {
"Contents": " 1:\t\n 2:\tconfig MPTCP\n 3:\t\tbool \"MPTCP: Multipath TCP\"\n 4:\t\tdepends on INET\n 5:\t\tselect SKB_EXTENSIONS\n 6:\t\tselect CRYPTO_LIB_SHA256\n 7:\t\tselect CRYPTO_LIB_UTILS\n 8:\t\thelp\n 9:\t\t Multipath TCP (MPTCP) connections send and receive data over multiple\n 10:\t\t subflows in order to utilize multiple network paths. Each subflow\n 11:\t\t uses the TCP protocol, and TCP options carry header information for\n 12:\t\t MPTCP.\n 13:\t\n 14:\tif MPTCP\n 15:\t\n 16:\tconfig INET_MPTCP_DIAG\n 17:\t\tdepends on INET_DIAG\n 18:\t\tdef_tristate INET_DIAG\n 19:\t\n 20:\tconfig MPTCP_IPV6\n"
} |
| 15/2 | 2026/08/01 22:43 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14605 output: 33 thoughts: 790 Thoughts: **MPTCP Changes: Fuzzing Focus** Okay, so I'm looking at this MPTCP patch. The configs that are relevant are `MPTCP` and `MPTCP_IPV6`. My focus needs to be on the parts of the code that are now handling memory limits and retransmission improvements, to ensure they're robust and don't introduce vulnerabilities. Initially, I was going to avoid `mptcp_worker` and `mptcp_release_cb` because they're static, but then I remembered the guidance to prefer non-static entry points *unless* they are not inlined. In this case, `mptcp_worker` is passed as a function pointer to `INIT_WORK`, and `mptcp_release_cb` is assigned to `sk->sk_prot->release_cb`, so the compiler won't inline them. So I *will* include them. So, here's the breakdown of where I need to concentrate my fuzzing efforts. The changes touch upon these critical areas: * `mptcp_incoming_options`: This handles incoming options and, crucially, checks if we're over the memory limit, then calls `mptcp_over_limit`. This is a clear point where memory limits are enforced. * `mptcp_data_ready`: Deals with subflow data ready events. Within this function, `__mptcp_move_skbs_from_subflow` is called which in turns call `__mptcp_add_backlog` which can drop packets if the backlog is exceeded, and `__mptcp_move_skb` * `mptcp_recvmsg`: This function is involved in moving SKBs. * `mptcp_worker`: It handles retransmissions by calling `__mptcp_retrans`, which is now part of the memory limit handling logic, and a critical area. * `mptcp_release_cb`: Also handles retransmissions by calling `__mptcp_retrans` and potentially `__mptcp_move_skbs`. The reasoning is straightforward. This patch makes functional changes, dealing with memory limits and retransmissions. These modifications could introduce all sorts of memory-related issues. I need to specifically target those sections, because memory pressure can expose subtle bugs like leaks, use-after-free conditions, or logic errors in the code. I will include these in the fuzzing configurations. |
| 16/2 | 2026/08/01 22:44 | tool | grepper |
0mArgs:{
"Expression": "mptcp_data_ready",
"PathPrefix": "net/mptcp/"
}Results: {
"Output": "net/mptcp/protocol.c=961=static void mptcp_rcv_rtt_update(struct mptcp_sock *msk,\n--\nnet/mptcp/protocol.c-986-\nnet/mptcp/protocol.c:987:void mptcp_data_ready(struct sock *sk, struct sock *ssk)\nnet/mptcp/protocol.c-988-{\n--\nnet/mptcp/protocol.h=956=static inline u64 mptcp_stamp(void)\n--\nnet/mptcp/protocol.h-960-\nnet/mptcp/protocol.h:961:void mptcp_data_ready(struct sock *sk, struct sock *ssk);\nnet/mptcp/protocol.h-962-bool mptcp_finish_join(struct sock *sk);\n--\nnet/mptcp/subflow.c=1506=static void subflow_data_ready(struct sock *sk)\n--\nnet/mptcp/subflow.c-1530-\tif (mptcp_subflow_data_available(sk)) {\nnet/mptcp/subflow.c:1531:\t\tmptcp_data_ready(parent, sk);\nnet/mptcp/subflow.c-1532-\n--\nnet/mptcp/subflow.c=1874=static void subflow_state_change(struct sock *sk)\n--\nnet/mptcp/subflow.c-1885-\tif (mptcp_subflow_data_available(sk))\nnet/mptcp/subflow.c:1886:\t\tmptcp_data_ready(parent, sk);\nnet/mptcp/subflow.c-1887-\telse if (unlikely(sk-\u003esk_err))\n"
} |
| 17/2 | 2026/08/01 22:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16430 output: 33 thoughts: 49 Thoughts: Okay, here's my interpretation of those thoughts, summarized from my perspective as an expert in the field: **Internal Audit of MPTCP Data Handling** Alright, so I'm mentally tracing the data flow here. The key is that `mptcp_data_ready` *isn't* a static function, which is exactly what I expected, given how it needs to interact with the broader multi-path TCP context. I've noted that it's being invoked from both `subflow_data_ready` and `subflow_state_change`, which makes perfect sense. I can now be sure about this, I need to investigate the circumstances of these calls. With that confirmed, I'm shifting my focus to `mptcp_incoming_options`. That's where I need to look to see what options might be causing this, and how the multi-path TCP header is parsed. |
| 18/2 | 2026/08/01 22:44 | tool | grepper |
0mArgs:{
"Expression": "mptcp_incoming_options",
"PathPrefix": "net/mptcp/"
}Results: {
"Output": "net/mptcp/options.c=1053=static void ack_update_msk(struct mptcp_sock *msk,\n--\nnet/mptcp/options.c-1078-\nnet/mptcp/options.c:1079:\t/* this assumes mptcp_incoming_options() is invoked after tcp_ack() */\nnet/mptcp/options.c-1080-\tif (after64(msk-\u003ewnd_end, snd_nxt))\n--\nnet/mptcp/options.c=1130=static bool mptcp_over_limit(struct sock *sk, struct sock *ssk,\n--\nnet/mptcp/options.c-1158- */\nnet/mptcp/options.c:1159:bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)\nnet/mptcp/options.c-1160-{\n"
} |
| 19/2 | 2026/08/01 22:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16949 output: 29 thoughts: 14 Thoughts: Okay, let's break this down. **Investigating the Caller of `mptcp_incoming_options`** Alright, so the question immediately that pops into my head is, "Who's actually responsible for calling this `mptcp_incoming_options` function?" I need to figure out the upstream code path, the chain of events that leads to this function being invoked. Understanding the context will give me clues about its purpose and the data it's supposed to handle. Is it called during connection setup, data transmission, or something else entirely? Knowing the caller is the key to understanding the function. I need to trace the execution flow. |
| 20/2 | 2026/08/01 22:44 | tool | grepper |
0mArgs:{
"Expression": "mptcp_incoming_options",
"PathPrefix": "net/"
}Results: {
"Output": "net/ipv4/tcp_input.c=4884=void tcp_reset(struct sock *sk, struct sk_buff *skb)\n--\nnet/ipv4/tcp_input.c-4890-\t/* mptcp can't tell us to ignore reset pkts,\nnet/ipv4/tcp_input.c:4891:\t * so just ignore the return value of mptcp_incoming_options().\nnet/ipv4/tcp_input.c-4892-\t */\nnet/ipv4/tcp_input.c-4893-\tif (sk_is_mptcp(sk))\nnet/ipv4/tcp_input.c:4894:\t\tmptcp_incoming_options(sk, skb);\nnet/ipv4/tcp_input.c-4895-\n--\nnet/ipv4/tcp_input.c=5607=static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)\n--\nnet/ipv4/tcp_input.c-5616-\t */\nnet/ipv4/tcp_input.c:5617:\tif (sk_is_mptcp(sk) \u0026\u0026 !mptcp_incoming_options(sk, skb)) {\nnet/ipv4/tcp_input.c-5618-\t\t__kfree_skb(skb);\n--\nnet/ipv4/tcp_input.c=7152=tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)\n--\nnet/ipv4/tcp_input.c-7379-\t\t\t */\nnet/ipv4/tcp_input.c:7380:\t\t\tif (sk_is_mptcp(sk) \u0026\u0026 !mptcp_incoming_options(sk, skb))\nnet/ipv4/tcp_input.c-7381-\t\t\t\tgoto discard;\n--\nnet/mptcp/options.c=1053=static void ack_update_msk(struct mptcp_sock *msk,\n--\nnet/mptcp/options.c-1078-\nnet/mptcp/options.c:1079:\t/* this assumes mptcp_incoming_options() is invoked after tcp_ack() */\nnet/mptcp/options.c-1080-\tif (after64(msk-\u003ewnd_end, snd_nxt))\n--\nnet/mptcp/options.c=1130=static bool mptcp_over_limit(struct sock *sk, struct sock *ssk,\n--\nnet/mptcp/options.c-1158- */\nnet/mptcp/options.c:1159:bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)\nnet/mptcp/options.c-1160-{\n"
} |
| 21/2 | 2026/08/01 22:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 17839 output: 31 thoughts: 98 Thoughts: Okay, here's my take on those thoughts, framed as my own mental processing: **MPTCP Code Exploration: Initial Focus** Right, so I see `mptcp_incoming_options` is called within `tcp_input.c`. That's the entry point. Alright, let's zero in on the key players here. I need to understand how the Multipath TCP options are handled when incoming. The immediate focus symbols are: * `mptcp_incoming_options` (obviously, that's where we started) * `mptcp_data_ready` (critical, how's data signalled?) * `mptcp_recvmsg` (how are messages processed on the receiving end?) * `mptcp_worker` (seems like a worker function or thread) * `mptcp_release_cb` (callback for releasing resources, maybe?). Hmm, I should quickly verify `mptcp_worker`. I wonder if that's the canonical name used in the code or perhaps it uses another name for its work function. Time to check. |
| 22/2 | 2026/08/01 22:44 | tool | grepper |
0mArgs:{
"Expression": "mptcp_worker",
"PathPrefix": "net/mptcp/"
}Results: {
"Output": "net/mptcp/protocol.c=1073=bool mptcp_schedule_work(struct sock *sk)\n--\nnet/mptcp/protocol.c-1077-\nnet/mptcp/protocol.c:1078:\t/* Get a reference on this socket, mptcp_worker() will release it.\nnet/mptcp/protocol.c:1079:\t * As mptcp_worker() might complete before us, we can not avoid\nnet/mptcp/protocol.c-1080-\t * a sock_hold()/sock_put() if schedule_work() returns false.\n--\nnet/mptcp/protocol.c=2615=static void __mptcp_close_ssk(struct sock *sk, struct sock *ssk,\n--\nnet/mptcp/protocol.c-2650-\t (sock_flag(sk, SOCK_DEAD) || sock_flag(ssk, SOCK_DEAD))) {\nnet/mptcp/protocol.c:2651:\t\t/* ensure later check in mptcp_worker() will dispose the msk */\nnet/mptcp/protocol.c-2652-\t\tsock_set_flag(sk, SOCK_DEAD);\n--\nnet/mptcp/protocol.c=2782=static void mptcp_check_fastclose(struct mptcp_sock *msk)\n--\nnet/mptcp/protocol.c-2822-\nnet/mptcp/protocol.c:2823:\t/* the calling mptcp_worker will properly destroy the socket */\nnet/mptcp/protocol.c-2824-\tif (sock_flag(sk, SOCK_DEAD))\n--\nnet/mptcp/protocol.c=3070=static void mptcp_do_fastclose(struct sock *sk)\n--\nnet/mptcp/protocol.c-3105-\nnet/mptcp/protocol.c:3106:static void mptcp_worker(struct work_struct *work)\nnet/mptcp/protocol.c-3107-{\n--\nnet/mptcp/protocol.c=3155=static void __mptcp_init_sock(struct sock *sk)\n--\nnet/mptcp/protocol.c-3162-\tINIT_LIST_HEAD(\u0026msk-\u003ebacklog_list);\nnet/mptcp/protocol.c:3163:\tINIT_WORK(\u0026msk-\u003ework, mptcp_worker);\nnet/mptcp/protocol.c-3164-\tmsk-\u003eout_of_order_queue = RB_ROOT;\n"
} |
| 23/2 | 2026/08/01 22:44 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 18860 output: 174 thoughts: 191 Thoughts: **My Assessment of the MPTCP Memory Pressure Patch** Okay, so I've pinned down `mptcp_worker` as the key workqueue function here. Excellent. Now, I need to focus my fuzzing efforts on these core symbols: `mptcp_incoming_options`, `mptcp_data_ready`, `mptcp_recvmsg`, `mptcp_worker`, and `mptcp_release_cb`. These are clearly the critical entry points and data processing functions related to this memory management change within MPTCP. The system configs I need to be concerned with are `MPTCP` and `MPTCP_IPV6`. Makes sense, particularly the latter, as IPv6 can introduce its own unique memory pressure scenarios. The patch's core modification is handling memory limits; specifically, pruning the out-of-order queue and dropping backlog packets when memory limits are exceeded. And there is a fix for the retransmission logic which will now properly push retransmissions. This is definitely a significant functional change to core networking code and requires rigorous testing. The goal here is to identify potential memory leaks, use-after-free conditions, or logic errors that could manifest under high memory pressure. I need to design fuzzing tests that aggressively explore these potential failure modes. Right, time to call set-results. |
| 24/2 | 2026/08/01 22:44 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"MPTCP",
"MPTCP_IPV6"
],
"FocusSymbols": [
"mptcp_incoming_options",
"mptcp_data_ready",
"mptcp_recvmsg",
"mptcp_worker",
"mptcp_release_cb"
],
"Reasoning": "The patch modifies the MPTCP protocol implementation to handle memory limits by pruning the out-of-order queue and dropping packets from the backlog when limits are exceeded. It also fixes the retransmission logic to properly push retransmissions. These are functional changes to reachable core networking code and should be fuzzed to ensure they don't introduce memory leaks, use-after-free, or logic bugs under memory pressure.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"MPTCP",
"MPTCP_IPV6"
],
"FocusSymbols": [
"mptcp_incoming_options",
"mptcp_data_ready",
"mptcp_recvmsg",
"mptcp_worker",
"mptcp_release_cb"
],
"Reasoning": "The patch modifies the MPTCP protocol implementation to handle memory limits by pruning the out-of-order queue and dropping packets from the backlog when limits are exceeded. It also fixes the retransmission logic to properly push retransmissions. These are functional changes to reachable core networking code and should be fuzzed to ensure they don't introduce memory leaks, use-after-free, or logic bugs under memory pressure.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|