From nobody Thu Nov 5 07:32:45 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793307946; b=wocR1plvgVwEeegPfC+x6Wmhp841wrGSvwaH6a1D65QtkWsjcSt4NcbIFtQHAIjU76wz CZXX0qHd5WObw7PptSY1kX/aXm8U8MDh6i6x/gzXCM2c+7rwWkqp7R7UltGelMkmblWo5 ZIUJ5xU9Bqt8k4KJkINGImT9sNevsSdf9iaymuyYJAemNpBOHhQN6skS2Y4/pXXhgrxct QAnAQEN9TN7BffBGCheXNTqvPM4tGE/JfVsG4Ze/r9tBEQfo9Ghs5KpLUcYqcCrCJWUnb Yeuujsv1yNEDZxN4aFQT0fi1j4r5XosvmrJywkdt6+VLqj/PP+1b44NUylIT7Yb9idA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793307946; h=Received:DKIM-Signature:From:Date:Subject:MIME-Version:Content-Type: Content-Transfer-Encoding:Message-Id:References:In-Reply-To:To:Cc: X-Mailer:X-Developer-Signature:X-Developer-Key; bh=c8KAglxNr6wFa/vsZ2lJ1rJT5FGyWu1APEsAAdrXAw4=; b=i8ScrbA8r8OEbbLdIcKuavaOQdl+VcUq0Vd31wFj/v0leEYYJ29F+HJ5APLuvJm7Oxut no1WjHCKQjSTBaufGdnrdYmJ7KhuWm3Op8S1/Q0QqRovMDjKU9Ka2sWcN29LPKUwog4sm ZspmxMS+4xtsByuXJbisZIvTPNOSEDpPQaYAJHy36e4BR+an/EqntsyVGqVaqOi5VcfAO dMSs5z2qRFxuUqY2jIeqP/b9igOitfLYjEi8iGnZwZfrEvkhejmCdwALv8Vhbo0Xv9GhY UgSY5chMebVg/SRl8d41DsFcd1wBFBUin3wquefmwP7whCT0pTilIOG8ORvpeujP51g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=P2PWgELA; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54026606A31A for ; Thu, 29 Oct 2026 21:05:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=P2PWgELA Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9B8831F01824; Thu, 29 Oct 2026 21:05:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793307946; bh=c8KAglxNr6wFa/vsZ2lJ1rJT5FGyWu1APEsAAdrXAw4=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=P2PWgELA+e03xmUPfMxGL1fODpz6CveOuwjP7uKjxnO+c48BsxSbvMuccLQbmZR8Q QOpcEtek85vdzJX759fFJMVG+ycPHuPKBNm9uQmmQ3xlgNXVku1U3w4FtezlZSMlAj Z2Yo+TI+6zUOGrte4zfsdzQUSy6BSib5/MHoiTuhxMGNhjbNR0Joo+a0lDmGLWxEBD 8p+qkPE0cj439tW2TGIjIRSO55hF2WZgKBnLN1EGyM65/VTvqqbquEnlH5zL0t6yl9 dHRGuHn+uT8c7S7hY0IMHVaHluwC3riJKRSVs30UzIowrWrSHVLwPSUp+GmIkSDJJD 4XWtPS5t4N6+w== From: "Matthieu Baerts (NGI0)" Date: Thu, 29 Oct 2026 22:05:31 +0100 Subject: [PATCH mptcp-next v3 1/3] mptcp: options: use a dedicated bit for csum reqd X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20261029-mptcp-mib-inval-opt-v3-1-428f42a35674@kernel.org> References: <20261029-mptcp-mib-inval-opt-v3-0-428f42a35674@kernel.org> In-Reply-To: <20261029-mptcp-mib-inval-opt-v3-0-428f42a35674@kernel.org> To: MPTCP Linux Cc: "Matthieu Baerts (NGI0)" X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=6351; i=matttbe@kernel.org; h=from:subject:message-id; bh=6bP5gSVTTO54VUmV3639fbDRT0ZR8SXDJMd0KpmyRa8=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLIeb1X1XPxI5KKjV4P1mbQnM6LnXzNXlVi7d03NyY3WB a+2iuzZ1VHKwiDGxSArpsgi3RaZP/N5FW+Jl58FzBxWJpAhDFycAjCReymMDHdlfOONv55b1uMv 137F2z7rkcSdpwu4sjhV7Np3pa+2mMPwT8Fgkct60+eelrNFdcXnqRw4PzN8YsHps+rd6rvOn4t cyw0A X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 Instead of mixing that with suboptions: that's the only non-suboptions that is present in the 'suboptions' field. This even cause a workaround with OPTIONS_MPTCP_DSS to exclude this non-suboptions when checking which other ones are set. Move it to a dedicated free bit, and adapt the corresponding code. This is clearer like that. Signed-off-by: Matthieu Baerts (NGI0) --- net/mptcp/options.c | 25 ++++++++++++------------- net/mptcp/protocol.c | 2 +- net/mptcp/protocol.h | 6 ++---- net/mptcp/subflow.c | 2 +- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index adbf8e0773db..cbc105199073 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -93,9 +93,8 @@ static void mptcp_parse_option(const struct sk_buff *skb, * In other words, the only way for checksums not to be used * is if both hosts in their SYNs set A=3D0." */ - if ((flags & MPTCP_CAP_CHECKSUM_REQD) && - opsize < TCPOLEN_MPTCP_MPC_ACK_DATA) - mp_opt->suboptions |=3D OPTION_MPTCP_CSUMREQD; + mp_opt->csum_reqd =3D (flags & MPTCP_CAP_CHECKSUM_REQD) && + opsize < TCPOLEN_MPTCP_MPC_ACK_DATA; =20 mp_opt->deny_join_id0 =3D !!(flags & MPTCP_CAP_DENY_JOIN_ID0); =20 @@ -122,7 +121,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, } if (opsize =3D=3D TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM) { mp_opt->csum =3D get_unaligned((__force __sum16 *)ptr); - mp_opt->suboptions |=3D OPTION_MPTCP_CSUMREQD; + mp_opt->csum_reqd =3D 1; ptr +=3D 2; } pr_debug("MP_CAPABLE version=3D%x, flags=3D%x, optlen=3D%d sndr=3D%llu, = rcvr=3D%llu len=3D%d csum=3D%u\n", @@ -251,22 +250,22 @@ static void mptcp_parse_option(const struct sk_buff *= skb, ptr +=3D 2; =20 if (opsize =3D=3D expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) { - mp_opt->suboptions |=3D OPTION_MPTCP_CSUMREQD; mp_opt->csum =3D get_unaligned((__force __sum16 *)ptr); + mp_opt->csum_reqd =3D 1; ptr +=3D 2; } =20 pr_debug("data_seq=3D%llu subflow_seq=3D%u data_len=3D%u csum=3D%d:%u\n= ", mp_opt->data_seq, mp_opt->subflow_seq, - mp_opt->data_len, !!(mp_opt->suboptions & OPTION_MPTCP_CSUMREQD), - (mp_opt->suboptions & OPTION_MPTCP_CSUMREQD) ? mp_opt->csum : 0); + mp_opt->data_len, mp_opt->csum_reqd, + mp_opt->csum_reqd ? mp_opt->csum : 0); } =20 break; =20 case MPTCPOPT_ADD_ADDR: /* Can be used with a restricted number of other options */ - if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | + if ((mp_opt->suboptions & ~(OPTION_MPTCP_DSS | OPTION_MPTCP_RM_ADDR | OPTION_MPTCP_PRIO)) !=3D 0) break; @@ -333,7 +332,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, /* Can be used with a restricted number of other options */ if ((mp_opt->suboptions & ~(OPTION_MPTCP_MPC_ACK | OPTIONS_MPTCP_MPJ | - OPTIONS_MPTCP_DSS | + OPTION_MPTCP_DSS | OPTION_MPTCP_ADD_ADDR | OPTION_MPTCP_PRIO)) !=3D 0) break; @@ -354,7 +353,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, case MPTCPOPT_MP_PRIO: /* Can be used with a restricted number of other options */ if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_MPJ | - OPTIONS_MPTCP_DSS | + OPTION_MPTCP_DSS | OPTION_MPTCP_ADD_ADDR | OPTION_MPTCP_RM_ADDR)) !=3D 0) break; @@ -369,7 +368,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, =20 case MPTCPOPT_MP_FASTCLOSE: /* Can be used with a restricted number of other options */ - if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | + if ((mp_opt->suboptions & ~(OPTION_MPTCP_DSS | OPTION_MPTCP_RST)) !=3D 0) break; =20 @@ -405,7 +404,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, =20 case MPTCPOPT_MP_FAIL: /* Can be used with a restricted number of other options */ - if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS | + if ((mp_opt->suboptions & ~(OPTION_MPTCP_DSS | OPTION_MPTCP_RST)) !=3D 0) break; =20 @@ -1352,7 +1351,7 @@ bool mptcp_incoming_options(struct sock *sk, struct s= k_buff *skb) } mpext->data_len =3D mp_opt.data_len; mpext->use_map =3D 1; - mpext->csum_reqd =3D !!(mp_opt.suboptions & OPTION_MPTCP_CSUMREQD); + mpext->csum_reqd =3D mp_opt.csum_reqd; =20 if (mpext->csum_reqd) mpext->csum =3D mp_opt.csum; diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 02a4f479d9d8..c85401952bf1 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3798,7 +3798,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *s= k, WRITE_ONCE(msk->token, subflow_req->token); msk->in_accept_queue =3D 1; WRITE_ONCE(msk->fully_established, false); - if (mp_opt->suboptions & OPTION_MPTCP_CSUMREQD) + if (mp_opt->csum_reqd) WRITE_ONCE(msk->csum_enabled, true); =20 WRITE_ONCE(msk->write_seq, subflow_req->idsn + 1); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 3be60da12924..cb1862ca5cb3 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -31,13 +31,10 @@ #define OPTION_MPTCP_DSS BIT(11) #define OPTION_MPTCP_FAIL BIT(12) =20 -#define OPTION_MPTCP_CSUMREQD BIT(13) - #define OPTIONS_MPTCP_MPC (OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_SYNACK = | \ OPTION_MPTCP_MPC_ACK) #define OPTIONS_MPTCP_MPJ (OPTION_MPTCP_MPJ_SYN | OPTION_MPTCP_MPJ_SYNACK = | \ OPTION_MPTCP_MPJ_ACK) -#define OPTIONS_MPTCP_DSS (OPTION_MPTCP_DSS | OPTION_MPTCP_CSUMREQD) =20 /* MPTCP option subtypes */ #define MPTCPOPT_MP_CAPABLE 0 @@ -165,7 +162,8 @@ struct mptcp_options_received { echo:1, backup:1, deny_join_id0:1, - __unused:2; + csum_reqd:1, + __unused:1; ); struct mptcp_rm_list rm_list; /* Options below are mutually exclusive, see mptcp_parse_option() */ diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 78e886b20258..b1aa772a2519 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -592,7 +592,7 @@ static void subflow_finish_connect(struct sock *sk, con= st struct sk_buff *skb) goto fallback; } =20 - if (mp_opt.suboptions & OPTION_MPTCP_CSUMREQD) + if (mp_opt.csum_reqd) WRITE_ONCE(msk->csum_enabled, true); if (mp_opt.deny_join_id0) WRITE_ONCE(msk->pm.remote_deny_join_id0, true); --=20 2.55.0 From nobody Thu Nov 5 07:32:45 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793307947; b=DSKnbnH9G6W+E1jl/6SQST6meO4aisqg1UNrOWcODZ/T4Jd+As6b62LDiYKUeYGWhikM UoQufbfhTnpE2yP8tJHK+tE8DGwgweKca8p1k4VuXnCIAC8e2RmXW/81n+l2xCQuOj43I GXl1ewyHVgJ2MC8eqJp4OueAGmjR9jlT9e9gigzYWJdvH86cD8wvGqerAFBS3zxgeiVdv NvvcFCRARIUlj9Y+ungrgwC1a3OjayEVnOItgc0eg5TH+7D0npLhO/M1baIb0lnQMetND KLrwicfGQmcMPmwUg32j0TnBIpt4Lw3igUozuWk8zlS0jjZcBZ+su7J2UsaUd0koC6g== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793307947; h=Received:DKIM-Signature:From:Date:Subject:MIME-Version:Content-Type: Content-Transfer-Encoding:Message-Id:References:In-Reply-To:To:Cc: X-Mailer:X-Developer-Signature:X-Developer-Key; bh=yXC+PauuNiU9Tu34HXqQyJPBCSGC8KgkNgwtWAShS3M=; b=fzrwdFN4oawbwPNwPKuxvnyG4IXd+9ty0HcB8dKHZf8lHKVPgIbVpOyL77lX9UsEQK5+ NJeGzXF4FWSCeMD3MOcUW2aquhdTbvDPc6cfCTH88a7ag1aTqXn339ToveHV+dmKSQQQV XlTV/qTCYyCYYQ9AZyyj7tRmBrgCKWQqCfLvB44BbbJZYxhKVb/EN6M3R4g3p+zlHYsVH xFM6xRf36LBlPftfZGwl6f11lIen56vSHJdGaS7HPFT9WCYZVa67gNs4EbKvhEyntnfUs anpydjUm+JCx+RYZ+/9cjlDhBHoEGPfJP55cn4Qlm555PL6dxjF84SJbOJvPJMaMx2g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=C1+vRjXy; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D1EA606A31A for ; Thu, 29 Oct 2026 21:05:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=C1+vRjXy Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6E36F1F01825; Thu, 29 Oct 2026 21:05:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793307947; bh=yXC+PauuNiU9Tu34HXqQyJPBCSGC8KgkNgwtWAShS3M=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=C1+vRjXyn9zFT1H8J7u6UiL9p8p5IGWpogIXKRWYOymWHbh8JdiWv4bTg7dmpw7RJ LY9Zn68meIzuZUr5PRbVh4PXZkodTZsWEocAXbYAvFJIAhiNHIKFupYdyuQDSJ4H7m p5e/yT5B4s9bnU2vgxK3vH/kV+SG0UdqwymOFjzLToOhULWRFERZpEz0KwlINH7jjm dk9YqJK8WZlyAbWNgj3lUljLccYyXPDyQLgYjaSCjRcBKPbKiruQW8mpjYpjZEUFzL ACV1gTCUgbaMZXDSM2dxNp1cToBPBE+KWVAo6v46uJyYXqQ5iUv5z96QCRiqMlb2Ch sos9fw7SWYBZA== From: "Matthieu Baerts (NGI0)" Date: Thu, 29 Oct 2026 22:05:32 +0100 Subject: [PATCH mptcp-next v3 2/3] mptcp: options: track invalid suboptions X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20261029-mptcp-mib-inval-opt-v3-2-428f42a35674@kernel.org> References: <20261029-mptcp-mib-inval-opt-v3-0-428f42a35674@kernel.org> In-Reply-To: <20261029-mptcp-mib-inval-opt-v3-0-428f42a35674@kernel.org> To: MPTCP Linux Cc: "Matthieu Baerts (NGI0)" , Gang Yan X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=10433; i=matttbe@kernel.org; h=from:subject:message-id; bh=MRe5jjFzByt4nM9V87TkJsCChSV2bUSeD28Fc/iHT0Q=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLIeb1U3PnbxPQeXyvZWq+dtcitNzzdc+lxsxDD158qwV KsrhTMVO0pZGMS4GGTFFFmk2yLzZz6v4i3x8rOAmcPKBDKEgYtTACYi85eR4YZffcfEAEX3Opm0 S40ekx1qw3qF3golTv/1fcq831fv+DP8M3b8sLv40KkwjqVXvN3bcibdvzYtifVfs2MJI1d52o/ pLAA= X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 Any unexpected suboptions combinations or use of invalid sizes are suspicious: either it is coming from a buggy host, or an attacker. Better to track that with a new MIB counter. Note that receiving unsupported versions or extensions can happen, so this part shouldn't be considered as invalid. Co-developed-by: Gang Yan Signed-off-by: Gang Yan Signed-off-by: Matthieu Baerts (NGI0) --- net/mptcp/mib.c | 1 + net/mptcp/mib.h | 1 + net/mptcp/options.c | 55 ++++++++++++++++++++++++++++++------------------= ---- net/mptcp/protocol.h | 2 +- net/mptcp/subflow.c | 10 +++++----- 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c index 608cb568897c..c54a20f19cf9 100644 --- a/net/mptcp/mib.c +++ b/net/mptcp/mib.c @@ -95,6 +95,7 @@ static const struct snmp_mib mptcp_snmp_list[] =3D { SNMP_MIB_ITEM("BacklogDrop", MPTCP_MIB_BACKLOGDROP), SNMP_MIB_ITEM("RcvPruned", MPTCP_MIB_RCVPRUNED), SNMP_MIB_ITEM("OFOPruned", MPTCP_MIB_OFOPRUNED), + SNMP_MIB_ITEM("OptInvalid", MPTCP_MIB_OPTINVALID), }; =20 /* mptcp_mib_alloc - allocate percpu mib counters diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h index 1ebdb55e9534..d1ce731cb5b7 100644 --- a/net/mptcp/mib.h +++ b/net/mptcp/mib.h @@ -98,6 +98,7 @@ enum linux_mptcp_mib_field { 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_OPTINVALID, /* Invalid MPTCP option */ __MPTCP_MIB_MAX }; =20 diff --git a/net/mptcp/options.c b/net/mptcp/options.c index cbc105199073..10a150e2ad69 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -20,7 +20,7 @@ static bool mptcp_cap_flag_sha256(u8 flags) return (flags & MPTCP_CAP_FLAG_MASK) =3D=3D MPTCP_CAP_HMAC_SHA256; } =20 -static void mptcp_parse_option(const struct sk_buff *skb, +static void mptcp_parse_option(const struct sock *sk, const struct sk_buff= *skb, const unsigned char *ptr, int opsize, struct mptcp_options_received *mp_opt) { @@ -53,9 +53,9 @@ static void mptcp_parse_option(const struct sk_buff *skb, /* Only the MPC + ACK can be used with a RM_ADDR */ if (subopt =3D=3D OPTION_MPTCP_MPC_ACK) { if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR) !=3D 0) - break; + goto invalid; } else if (mp_opt->suboptions !=3D 0) { - break; + goto invalid; } =20 /* Cfr RFC 8684 Section 3.3.0: @@ -71,7 +71,7 @@ static void mptcp_parse_option(const struct sk_buff *skb, if (opsize !=3D expected_opsize && (expected_opsize !=3D TCPOLEN_MPTCP_MPC_ACK_DATA || opsize !=3D TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM)) - break; + goto invalid; =20 /* try to be gentle vs future versions on the initial syn */ version =3D *ptr++ & MPTCP_VERSION_MASK; @@ -136,7 +136,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, /* Can be used with a restricted number of other options */ if ((mp_opt->suboptions & ~(OPTION_MPTCP_RM_ADDR | OPTION_MPTCP_PRIO)) !=3D 0) - break; + goto invalid; =20 if (opsize =3D=3D TCPOLEN_MPTCP_MPJ_SYN) { mp_opt->suboptions |=3D OPTION_MPTCP_MPJ_SYN; @@ -165,6 +165,8 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, ptr +=3D 2; memcpy(mp_opt->hmac, ptr, MPTCPOPT_HMAC_LEN); pr_debug("MP_JOIN hmac\n"); + } else { + goto invalid; } break; =20 @@ -175,7 +177,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, OPTION_MPTCP_PRIO | OPTION_MPTCP_FASTCLOSE | OPTION_MPTCP_FAIL)) !=3D 0) - break; + goto invalid; =20 pr_debug("DSS\n"); ptr++; @@ -218,7 +220,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, mp_opt->ack64 =3D 0; mp_opt->use_ack =3D 0; mp_opt->data_fin =3D 0; - break; + goto invalid; } =20 mp_opt->suboptions |=3D OPTION_MPTCP_DSS; @@ -268,7 +270,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, if ((mp_opt->suboptions & ~(OPTION_MPTCP_DSS | OPTION_MPTCP_RM_ADDR | OPTION_MPTCP_PRIO)) !=3D 0) - break; + goto invalid; =20 mp_opt->echo =3D (*ptr++) & MPTCP_ADDR_ECHO; if (!mp_opt->echo) { @@ -281,7 +283,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, mp_opt->addr.family =3D AF_INET6; #endif else - break; + goto invalid; } else { if (opsize =3D=3D TCPOLEN_MPTCP_ADD_ADDR_BASE || opsize =3D=3D TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT) @@ -292,7 +294,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, mp_opt->addr.family =3D AF_INET6; #endif else - break; + goto invalid; } =20 mp_opt->suboptions |=3D OPTION_MPTCP_ADD_ADDR; @@ -335,11 +337,11 @@ static void mptcp_parse_option(const struct sk_buff *= skb, OPTION_MPTCP_DSS | OPTION_MPTCP_ADD_ADDR | OPTION_MPTCP_PRIO)) !=3D 0) - break; + goto invalid; =20 if (opsize < TCPOLEN_MPTCP_RM_ADDR_BASE + 1 || opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX) - break; + goto invalid; =20 ptr++; =20 @@ -356,10 +358,10 @@ static void mptcp_parse_option(const struct sk_buff *= skb, OPTION_MPTCP_DSS | OPTION_MPTCP_ADD_ADDR | OPTION_MPTCP_RM_ADDR)) !=3D 0) - break; + goto invalid; =20 if (opsize !=3D TCPOLEN_MPTCP_PRIO) - break; + goto invalid; =20 mp_opt->suboptions |=3D OPTION_MPTCP_PRIO; mp_opt->backup =3D *ptr++ & MPTCP_PRIO_BKUP; @@ -370,10 +372,10 @@ static void mptcp_parse_option(const struct sk_buff *= skb, /* Can be used with a restricted number of other options */ if ((mp_opt->suboptions & ~(OPTION_MPTCP_DSS | OPTION_MPTCP_RST)) !=3D 0) - break; + goto invalid; =20 if (opsize !=3D TCPOLEN_MPTCP_FASTCLOSE) - break; + goto invalid; =20 ptr +=3D 2; mp_opt->fc_recv_key =3D get_unaligned_be64(ptr); @@ -386,10 +388,10 @@ static void mptcp_parse_option(const struct sk_buff *= skb, /* Can be used with a restricted number of other options */ if ((mp_opt->suboptions & ~(OPTION_MPTCP_FAIL | OPTION_MPTCP_FASTCLOSE)) !=3D 0) - break; + goto invalid; =20 if (opsize !=3D TCPOLEN_MPTCP_RST) - break; + goto invalid; =20 if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) break; @@ -406,10 +408,10 @@ static void mptcp_parse_option(const struct sk_buff *= skb, /* Can be used with a restricted number of other options */ if ((mp_opt->suboptions & ~(OPTION_MPTCP_DSS | OPTION_MPTCP_RST)) !=3D 0) - break; + goto invalid; =20 if (opsize !=3D TCPOLEN_MPTCP_FAIL) - break; + goto invalid; =20 ptr +=3D 2; mp_opt->suboptions |=3D OPTION_MPTCP_FAIL; @@ -418,11 +420,17 @@ static void mptcp_parse_option(const struct sk_buff *= skb, break; =20 default: + /* Not invalid: maybe used for experimentations */ break; } + + return; + +invalid: + MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OPTINVALID); } =20 -void mptcp_get_options(const struct sk_buff *skb, +void mptcp_get_options(const struct sock *sk, const struct sk_buff *skb, struct mptcp_options_received *mp_opt) { const struct tcphdr *th =3D tcp_hdr(skb); @@ -457,7 +465,8 @@ void mptcp_get_options(const struct sk_buff *skb, if (opsize > length) return; /* don't parse partial options */ if (opcode =3D=3D TCPOPT_MPTCP) - mptcp_parse_option(skb, ptr, opsize, mp_opt); + mptcp_parse_option(sk, skb, ptr, opsize, + mp_opt); ptr +=3D opsize - 2; length -=3D opsize; } @@ -1251,7 +1260,7 @@ bool mptcp_incoming_options(struct sock *sk, struct s= k_buff *skb) return !mptcp_over_limit(subflow->conn, sk, skb); } =20 - mptcp_get_options(skb, &mp_opt); + mptcp_get_options(sk, skb, &mp_opt); =20 /* The subflow can be in close state only if check_fully_established() * just sent a reset. If so, tell the caller to ignore the current packet. diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index cb1862ca5cb3..8f8b4173a566 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -944,7 +944,7 @@ struct sock *mptcp_sk_clone_init(const struct sock *sk, const struct mptcp_options_received *mp_opt, struct sock *ssk, struct request_sock *req); -void mptcp_get_options(const struct sk_buff *skb, +void mptcp_get_options(const struct sock *sk, const struct sk_buff *skb, struct mptcp_options_received *mp_opt); =20 void mptcp_finish_connect(struct sock *sk); diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index b1aa772a2519..d0ff0fb83b29 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -202,7 +202,7 @@ static int subflow_check_req(struct request_sock *req, } #endif =20 - mptcp_get_options(skb, &mp_opt); + mptcp_get_options(sk_listener, skb, &mp_opt); =20 opt_mp_capable =3D !!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYN); opt_mp_join =3D !!(mp_opt.suboptions & OPTION_MPTCP_MPJ_SYN); @@ -308,7 +308,7 @@ int mptcp_subflow_init_cookie_req(struct request_sock *= req, int err; =20 subflow_init_req(req, sk_listener); - mptcp_get_options(skb, &mp_opt); + mptcp_get_options(sk_listener, skb, &mp_opt); =20 opt_mp_capable =3D !!(mp_opt.suboptions & OPTION_MPTCP_MPC_ACK); opt_mp_join =3D !!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK); @@ -579,7 +579,7 @@ static void subflow_finish_connect(struct sock *sk, con= st struct sk_buff *skb) subflow->ssn_offset =3D TCP_SKB_CB(skb)->seq; pr_debug("subflow=3D%p synack seq=3D%x\n", subflow, subflow->ssn_offset); =20 - mptcp_get_options(skb, &mp_opt); + mptcp_get_options(sk, skb, &mp_opt); if (subflow->request_mptcp) { if (!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYNACK)) { if (!mptcp_try_fallback(sk, @@ -881,13 +881,13 @@ static struct sock *subflow_syn_recv_sock(const struc= t sock *sk, * reordered MPC will cause fallback, but we don't have other * options. */ - mptcp_get_options(skb, &mp_opt); + mptcp_get_options(sk, skb, &mp_opt); if (!(mp_opt.suboptions & (OPTION_MPTCP_MPC_SYN | OPTION_MPTCP_MPC_ACK))) fallback =3D true; =20 } else if (subflow_req->mp_join) { - mptcp_get_options(skb, &mp_opt); + mptcp_get_options(sk, skb, &mp_opt); if (!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK)) fallback =3D true; } --=20 2.55.0 From nobody Thu Nov 5 07:32:45 2026 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793307948; b=iS+z4RPVo1xFs+dzbk4xr617UGlEYln5gKh9HcywluB5DrRxMt9BmEWf4l6fMcsIu05P 3RmCc1gP0WPlCXlLssoLDIis1cmldiQEUuY50H8NMdH93yFva1/8o9ug5Y1fxPlNcAjIG ARS8vBX4qiTp0b/MSYaNcRPWRk0TaPFqDKrXLx4nYpyDpU0RbUExbyQWDtH3afem2+ox/ tjaE+9nXRJa/yPJFi9J75qruiBmOcpKC9C1cjhOxw8fiMTj0CANbjkWBnRArVPo8BYotm tgbjqwIrti7JwSza8UV6wiyonHk5wYhJCCxp3oYHVVvtG8tnonYSBes02XyvsbOZSnw== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793307948; h=Received:DKIM-Signature:From:Date:Subject:MIME-Version:Content-Type: Content-Transfer-Encoding:Message-Id:References:In-Reply-To:To:Cc: X-Mailer:X-Developer-Signature:X-Developer-Key; bh=r6asDAUO1ZgOqeLABDcbvAtU3LZeI5YEwYy5cfxQ7nA=; b=MOh/cogcF0msucj/6fjL63SNc6S7yyqD1aDdo+WcvOIeOWfcW3gSJAbcvINnl5Fgx92Q qax9NfAvkvC2ECI187ZlGmZMzOzn3DZiDiwbzF/M5zhtnb7mYvPAQYfCd0JnUL4FAGITo l5sAVy87N39tVSFs7ajA8iBftlnzcyy0rQdjkcO34emli8iEoT2sXpbFix7HYLf7NKgWR GidZi+xwu4guohdrTvoPrmyermdicKjsu0ytdgyzctxfHH4koTwGOSRUTHEupjwbD0hF7 Py8/GiKS6PzolDiedhPgas4J7H8KVWgfwh+KJJhsF6vmnQXE7xJyGZyX9SiNemtMVZA== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=gwvcVEgB; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2905A606A31A for ; Thu, 29 Oct 2026 21:05:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=gwvcVEgB Received: by smtp.kernel.org (Postfix) with ESMTPSA id 659D51F01826; Thu, 29 Oct 2026 21:05:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793307947; bh=r6asDAUO1ZgOqeLABDcbvAtU3LZeI5YEwYy5cfxQ7nA=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=gwvcVEgB0aupWeetcDPImQ1gDWVDYQOtbdh9OoGpEFU0N90sZRyik6Kdawf4SwFMU I7mmnipPYXEHZgJR3brW6IdtF0P/rrw2j8ZTXmoNU70rgemOCdCjd/XZtXDyTHe/z1 blZF7VoIiXFVSxVaN19ika6arze3kLE4RiWHQfuv1BjqLAqi7NGpRotV6DXL1/iWaj dVRzTNbeI4MmHuEQO6RpKpCJKapoNFEggv7xl/8xHqO5WYsUf/rUPKpQpmI0ik7v1R +tfHRiaNa6itWOweq/uFPd6NlLjzJqFzZDotufZcce15YlWYtN8d351lNp50lIg2nE gKlnBr300e9gw== From: "Matthieu Baerts (NGI0)" Date: Thu, 29 Oct 2026 22:05:33 +0100 Subject: [PATCH mptcp-next v3 3/3] mptcp: options: reset parsing in case of invalidity X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20261029-mptcp-mib-inval-opt-v3-3-428f42a35674@kernel.org> References: <20261029-mptcp-mib-inval-opt-v3-0-428f42a35674@kernel.org> In-Reply-To: <20261029-mptcp-mib-inval-opt-v3-0-428f42a35674@kernel.org> To: MPTCP Linux Cc: "Matthieu Baerts (NGI0)" X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2722; i=matttbe@kernel.org; h=from:subject:message-id; bh=WCeVedKM2Ge5u2uI8ZfXLfAnrlbXW8ka4EohFd6L5+A=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLIeb9VIWVVZfP+f25bF1efTXOwD9zatlVzwSrbqU92xQ wfmmz937ihlYRDjYpAVU2SRbovMn/m8irfEy88CZg4rE8gQBi5OAZjI+ukM/7QOPL1WbtKrHLVr +vdFR9bNvWH1YWa1z7cjf5hvnmh6bjqNkeHPspppHYGttjz6177zH7r86MCTPXpxV492GC47p6l w6S87AA== X-Developer-Key: i=matttbe@kernel.org; a=openpgp; fpr=E8CB85F76877057A6E27F77AF6B7824F4269A073 When an invalid option is detected -- any unexpected suboptions combinations or use of invalid sizes -- the current behaviour is to ignore the currently parsed option. Receiving such invalid options is suspicious: either this is coming from a buggy host, or an attacker. In these cases, it seems safer to drop any previously parsed MPTCP option from such packets. This will likely lead to a fallback to TCP or a subflow reject, which seems to be a good reaction in these situations. Signed-off-by: Matthieu Baerts (NGI0) --- v2: break the while-loop, not the switch-case. --- net/mptcp/options.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index 10a150e2ad69..b068f4f1861e 100644 --- a/net/mptcp/options.c +++ b/net/mptcp/options.c @@ -20,7 +20,7 @@ static bool mptcp_cap_flag_sha256(u8 flags) return (flags & MPTCP_CAP_FLAG_MASK) =3D=3D MPTCP_CAP_HMAC_SHA256; } =20 -static void mptcp_parse_option(const struct sock *sk, const struct sk_buff= *skb, +static bool mptcp_parse_option(const struct sock *sk, const struct sk_buff= *skb, const unsigned char *ptr, int opsize, struct mptcp_options_received *mp_opt) { @@ -214,14 +214,8 @@ static void mptcp_parse_option(const struct sock *sk, = const struct sk_buff *skb, * RFC 8684 Section 3.3.0 checks later in subflow_data_ready */ if (opsize !=3D expected_opsize && - opsize !=3D expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) { - mp_opt->dsn64 =3D 0; - mp_opt->use_map =3D 0; - mp_opt->ack64 =3D 0; - mp_opt->use_ack =3D 0; - mp_opt->data_fin =3D 0; + opsize !=3D expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) goto invalid; - } =20 mp_opt->suboptions |=3D OPTION_MPTCP_DSS; if (mp_opt->use_ack) { @@ -424,10 +418,11 @@ static void mptcp_parse_option(const struct sock *sk,= const struct sk_buff *skb, break; } =20 - return; + return true; =20 invalid: MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OPTINVALID); + return false; } =20 void mptcp_get_options(const struct sock *sk, const struct sk_buff *skb, @@ -464,9 +459,12 @@ void mptcp_get_options(const struct sock *sk, const st= ruct sk_buff *skb, return; if (opsize > length) return; /* don't parse partial options */ - if (opcode =3D=3D TCPOPT_MPTCP) - mptcp_parse_option(sk, skb, ptr, opsize, - mp_opt); + if (opcode =3D=3D TCPOPT_MPTCP && + !mptcp_parse_option(sk, skb, ptr, opsize, mp_opt)) { + /* invalid option, drop previously parsed opt */ + *(u32 *)&mp_opt->status =3D 0; + return; + } ptr +=3D opsize - 2; length -=3D opsize; } --=20 2.55.0