From nobody Sat Sep 5 05:51:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8BCBD456E12 for ; Thu, 3 Sep 2026 11:25:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788434720; cv=none; b=F7LS0Y9qADSfAT6vbiWP7H2/rH98jwFNOPC/c6Wng9ruvCzYkKHBqNYgFogkIOn+Dluq91ZKlnLJdkPnoLVvNCrefRIrLXbFA9D1NhieA4LyfAAK2wXmAW6+NFdRYWhTKzOOVK6FQxsdS8TPRYIQG1Eg6n67OVDH8Q3Y0xWKrVs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788434720; c=relaxed/simple; bh=qQOSM8dvXGPMjLM2qWRjFKGbCmlcWGVfV3F77lw6gpE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JlmW4uO5hZfUR9/2uUtMSjnaCNSFdyHcZxbaD+SzT5fzjN+SgokiQFuSJBweLDOPzgPjxPpiInBHNqtGkYrLdrTgTBiLjYfyCwIpADxOXD1qOBlcpYHPGMtzxsuGXsj/o6yKJExxJtS2OdeOB33BNd8Z6Kx/vpewTdUD+KEMUL8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D/pCeEu7; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="D/pCeEu7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 565111F00A3D; Thu, 3 Sep 2026 11:25:14 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788434714; bh=7myiKEy0D4UKHgenVh1S2Zrg6ZN3z/J9zfHpyFbWl/Y=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=D/pCeEu7OVCn0+Er8UQ4F8V10pY/EV9b/ebXFKXeNRl22AJVVvCXDJXqKFO5zp5mi pvdOACKiTBuUiWUUVo/qV3s27DSp4qCLbMWuDo5GlBP9LDOJ9oIj+jMqOv61u8h0O3 QTNAzrhVLOoKnQUDfQQrjQc/A1dpWRGIV/rWS5qV72n8f3bT9x4Ks+8hoBSrBSL889 EYLqwGiAIPvCQuBaMq/blqSIQPmyzhy6tmqmh3EX7hMqqPHe4wybc56sui5ampy9zX xXVWRYO3/74+EEcmzbDHkt8oZK09SXLIdmu+jxnYZoaARWaStL0vdwujhhs/+FaFbH 3ToOebo7vfiEw== From: "Matthieu Baerts (NGI0)" Date: Thu, 03 Sep 2026 13:24:54 +0200 Subject: [PATCH mptcp-next 1/3] mptcp: options: use a dedicated bit for csum reqd Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-mptcp-mib-inval-opt-v1-1-84a553c552b6@kernel.org> References: <20260903-mptcp-mib-inval-opt-v1-0-84a553c552b6@kernel.org> In-Reply-To: <20260903-mptcp-mib-inval-opt-v1-0-84a553c552b6@kernel.org> To: MPTCP Linux Cc: "Matthieu Baerts (NGI0)" X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=6244; i=matttbe@kernel.org; h=from:subject:message-id; bh=qQOSM8dvXGPMjLM2qWRjFKGbCmlcWGVfV3F77lw6gpE=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLJmRor5ShySm+k64223vPOaS4/3WouwSO1av//micUJ0 kncuxZYdZSyMIhxMciKKbJIt0Xmz3xexVvi5WcBM4eVCWQIAxenAExkExvDb5YrM2Mfi29kXekg c/djGPtV7b9vri15s6f7WLPmW9nfG/YxMtx6eObR3SVq00JYwv/uW7uzcunE3TLibUsFV9X9WP7 VspwdAA== 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 | 23 +++++++++++------------ net/mptcp/protocol.c | 2 +- net/mptcp/protocol.h | 6 ++---- net/mptcp/subflow.c | 2 +- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/net/mptcp/options.c b/net/mptcp/options.c index f87707110c75..afda3f2ca935 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", @@ -248,14 +247,14 @@ 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->data_len, mp_opt->csum_reqd, mp_opt->csum); } =20 @@ -263,7 +262,7 @@ static void mptcp_parse_option(const struct sk_buff *sk= b, =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; @@ -330,7 +329,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; @@ -351,7 +350,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; @@ -366,7 +365,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 @@ -402,7 +401,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 @@ -1349,7 +1348,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 0b24e0afedfb..0e4616054955 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3771,7 +3771,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 b3121c8c766b..c8d413e14064 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; ); u8 join_id; u32 token; diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 2d7ccb01d234..df1d18a4e906 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -553,7 +553,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 Sat Sep 5 05:51:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A1CE4562B3 for ; Thu, 3 Sep 2026 11:25:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788434720; cv=none; b=HUbRNv9DUSK8QDD5Gni6g4r12pU6UNMEasHk4l2cMrE8je39Va57QHJD8pWCYkjnQRSpKrYfH66lcgJBLWhFbmhNp5WJxCgmqtC9ZLzZJWABp5FtCbMF5cLlS1PAzV1SGRe66gKMxrPpLcS+3PB1XmlhXtaAFJ1NbfHDiTrtQAY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788434720; c=relaxed/simple; bh=KKzKMsjYyjaxWRelc4j/x7eK4DZtJO+YlZE0tuHmLVs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=G6vTbM2qpSRWrp4IOki1v7IfWvwZdclDQQZTHSWqmBcbvm4SOpvbFX/3VT1xDXd0aCl+F+ZdJyahDYIMeRH4W4vBJ11voMvPFuAghq/hvl53Z6/m2pyiHrhUDnrYF/NTvZUpV+orK1n1NklkeXNh5Xju6w7tZ4Kpx+YmWO3dhjo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MUtZrho9; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MUtZrho9" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 298CE1F00A3E; Thu, 3 Sep 2026 11:25:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788434715; bh=qYOE/UKVXKX+6JOPLz+IAWs0ozHAqvoTIse44beEmNg=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=MUtZrho9Egq/uw3jThUfuITD0+4SktgwuNMnqfXkp5E6KCcvSjO4xx1FPqBIrJI1x zky3ePi+Wh/rk9dV0uBdIKT4tqFZc9tFs0uzqaUFDo6QrXh7Y3F1GIdrmBY+3yJP21 QBGbrvC88R+HmYmmVw4wZzF6T+uRe1wfsQhsEN7JJ2pe6z6BO6bz2UsLySMd0XPIjh HpGiEvmDWUbeFsq7OxxJo6SCGX0nnt4cq86tkXI1lMDlye6LKoEG6KBKeROyb6jEZC aOSjVjlEpbfsulpdg+oOrlQqMVp52ychKalQEHc1Es53kFA829JzB4xFDGGQw2C1CB fuFCFaG33qGdQ== From: "Matthieu Baerts (NGI0)" Date: Thu, 03 Sep 2026 13:24:55 +0200 Subject: [PATCH mptcp-next 2/3] mptcp: options: track invalid suboptions Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-mptcp-mib-inval-opt-v1-2-84a553c552b6@kernel.org> References: <20260903-mptcp-mib-inval-opt-v1-0-84a553c552b6@kernel.org> In-Reply-To: <20260903-mptcp-mib-inval-opt-v1-0-84a553c552b6@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=10430; i=matttbe@kernel.org; h=from:subject:message-id; bh=KKzKMsjYyjaxWRelc4j/x7eK4DZtJO+YlZE0tuHmLVs=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLJmRooH8/opRad+j1BbNN+6OTRdO98hYMJL2QrTrit3N /57y/ulo5SFQYyLQVZMkUW6LTJ/5vMq3hIvPwuYOaxMIEMYuDgFYCLzrjH8d/oorNebr5zmtvGL w9x5/+7PU0m75bvc+M2Vt9c++Z//68nIcG9a8OHXDxvW/K1VtTzaXCmg1r0hvOdZbW8Eq0iB5Ox f/AA= 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 afda3f2ca935..aaaabcab0f8f 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; @@ -133,7 +133,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; @@ -162,6 +162,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 @@ -172,7 +174,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++; @@ -215,7 +217,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; @@ -265,7 +267,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) { @@ -278,7 +280,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) @@ -289,7 +291,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; @@ -332,11 +334,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 @@ -353,10 +355,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; @@ -367,10 +369,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->rcvr_key =3D get_unaligned_be64(ptr); @@ -383,10 +385,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; @@ -403,10 +405,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; @@ -415,11 +417,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); @@ -454,7 +462,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; } @@ -1248,7 +1257,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 c8d413e14064..739f9006c1e1 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -925,7 +925,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 df1d18a4e906..2b4b2179fe03 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -167,7 +167,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); @@ -273,7 +273,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); @@ -540,7 +540,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, @@ -842,13 +842,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 Sat Sep 5 05:51:21 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D17A545A28E for ; Thu, 3 Sep 2026 11:25:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788434724; cv=none; b=ulY3Sif7V5cXE84tumvgLIYC7I9tiaAV8q8p0qq7Fhl9r4pS5U8ic8hU5Xl+QW+ZqNE44PLM4ejQS2hn9qGdwVdmh8yNnP3+qA+GWvvfWcU1U0iybj/9+BcUY8uJiUkqpb0BTkk3WuWGFikNhLSOfGzmrUGV/nwYuWDB6vre0u4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788434724; c=relaxed/simple; bh=mQSnv+WGutmf8prHrR1ljHZNqnlEDoBVtvwI2MF69w8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=OfZSf/lT0eCXWVOAx0Z4jsFo+fkNveRJ/ZnvGr5JZ5lsDfDADevA5maL07CPolYpZGhdfhNnzW+5SxJ+rqesz6DRr71FFjTlG1/tW57eMpPDG9yqdhpQ52XR/v4PaTT6xm2SpaNnz4yMS2D7QJXLBy1DVZR/3ocLH0Wtw1cQ9rg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Lm4IQelI; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Lm4IQelI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 21FDB1F00A3A; Thu, 3 Sep 2026 11:25:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788434716; bh=Y6XLctRiRwRS4VEjVvThSJrp2Z1FKbkwRHPugJMFbDE=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Lm4IQelIPqtG5wcrfYgYqym/yiXaQYmA5dvsqHeFnYfbhYlPU30Ra651wpZigHUNN 6aQ6jkkOigKNT7wVgs9q0zu6eQBSj6fHalsUfT0wVAh3kV6vBohjWlNHN3mgLOLplP tZjKTqdQfbPzYxxoECJ/6EDbLccQk7Irqezx7Oa8iW4VH6iXfvJ4gxOLmurlDCl5lg gGVS0R7PI4LCXkzqhJb+fKN5G2MAwHMbYnxrG6nJ4bE6QBRQKGfqBIMPNKK0+1nxIZ +RtlYohzmnwJymR4tjayaxAA5i7QVnF//5cfuIcHhEGvQqB6jBfFI1RTwLhC7sl00i wAlaA+FZdTY2Q== From: "Matthieu Baerts (NGI0)" Date: Thu, 03 Sep 2026 13:24:56 +0200 Subject: [PATCH mptcp-next 3/3] mptcp: options: reset parsing in case of invalidity Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260903-mptcp-mib-inval-opt-v1-3-84a553c552b6@kernel.org> References: <20260903-mptcp-mib-inval-opt-v1-0-84a553c552b6@kernel.org> In-Reply-To: <20260903-mptcp-mib-inval-opt-v1-0-84a553c552b6@kernel.org> To: MPTCP Linux Cc: "Matthieu Baerts (NGI0)" X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=2668; i=matttbe@kernel.org; h=from:subject:message-id; bh=mQSnv+WGutmf8prHrR1ljHZNqnlEDoBVtvwI2MF69w8=; b=owGbwMvMwCVWo/Th0Gd3rumMp9WSGLJmRkpYrHQXC9WceGw5x9QY9Q2tP+MXXkleWxGirhH/L cXPjremo5SFQYyLQVZMkUW6LTJ/5vMq3hIvPwuYOaxMIEMYuDgFYCLz9jIyLM5evOLwmpULBNIe z9VfeFzrzfmwT7YpSxoFps0yOPRbTZ/hf/qO3tvcgo06CZYXGysSKzXdqvR+VDzk0tlrd8rRVf0 qDwA= 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) --- 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 aaaabcab0f8f..b6d2e39f8464 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) { @@ -211,14 +211,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) { @@ -421,10 +415,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, @@ -461,9 +456,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; + break; + } ptr +=3D opsize - 2; length -=3D opsize; } --=20 2.55.0