[PATCH net 1/5] mptcp: avoid combining some incoming suboptions
From: Matthieu Baerts (NGI0)
Date: Tue Jul 28 2026 - 14:36:20 EST
Some MPTCP suboptions are mutually exclusive according to the RFC8684,
but also because in different places, the code doesn't expect some
combinations to be present. That's specially true for suboptions that
would be present twice, but with different attributes.
The new restrictions are the same as the ones applied on the output
side, with mptcp_write_options. The same rules can be reused:
Which options can be used together?
X: mutually exclusive
O: often used together
C: can be used together in some cases
P: could be used together but we prefer not to (optimisations)
| Opt: | MPC | MPJ | DSS | ADD | RM | PRIO | FAIL | FC |
|------|------|------|------|------|------|------|------|------|
| MPC |------|------|------|------|------|------|------|------|
| MPJ | X |------|------|------|------|------|------|------|
| DSS | X | X |------|------|------|------|------|------|
| ADD | X | X | P |------|------|------|------|------|
| RM | C | C | C | P |------|------|------|------|
| PRIO | X | C | C | C | C |------|------|------|
| FAIL | X | X | C | X | X | X |------|------|
| FC | X | X | X | X | X | X | X |------|
| RST | X | X | X | X | X | X | O | O |
|------|------|------|------|------|------|------|------|------|
The only difference is with the 'P': another stack could send and
ADD_ADDR with other suboptions (DSS, RM_ADDR), and this should be
allowed.
A point of attention is with the MP_CAPABLE: it could be used with a
RM_ADDR, but there is no reason to add it with a SYN. Note that even
with a 4th ACK, it doesn't seem to be useful, except when IDs are known
in advance via another channel. Better not to break that.
Also, in mp_opt->suboptions, there is also a bit reserved to the
checksum, which can be used in an MP_CAPABLE and a DSS. Each time a DSS
option can be used in parallel with another option, the checksum can be
set, so the verification is combined into a new OPTIONS_MPTCP_DSS macro.
Fixes: eda7acddf808 ("mptcp: Handle MPTCP TCP options")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@xxxxxxxxxx>
---
Cc: Florian Westphal <fw@xxxxxxxxx>
Cc: Davide Caratti <dcaratti@xxxxxxxxxx>
Cc: Christoph Paasch <cpaasch@xxxxxxxxxx>
Note: Peter Krystad's email address is no longer valid
---
net/mptcp/options.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++
net/mptcp/protocol.h | 1 +
2 files changed, 56 insertions(+)
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index c664023d37ba..3b8539f1c224 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -50,6 +50,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
}
}
+ /* Only the MPC + ACK can be used with a RM_ADDR */
+ if (subopt == OPTION_MPTCP_MPC_ACK) {
+ if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR) != 0)
+ break;
+ } else if (mp_opt->suboptions != 0) {
+ break;
+ }
+
/* Cfr RFC 8684 Section 3.3.0:
* If a checksum is present but its use had
* not been negotiated in the MP_CAPABLE handshake, the receiver MUST
@@ -122,6 +130,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
case MPTCPOPT_MP_JOIN:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTION_MPTCP_RM_ADDR |
+ OPTION_MPTCP_PRIO)) != 0)
+ break;
+
if (opsize == TCPOLEN_MPTCP_MPJ_SYN) {
mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYN;
mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP;
@@ -153,6 +166,13 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
case MPTCPOPT_DSS:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTION_MPTCP_ADD_ADDR |
+ OPTION_MPTCP_RM_ADDR |
+ OPTION_MPTCP_PRIO |
+ OPTION_MPTCP_FAIL)) != 0)
+ break;
+
pr_debug("DSS\n");
ptr++;
@@ -234,6 +254,12 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
case MPTCPOPT_ADD_ADDR:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_RM_ADDR |
+ OPTION_MPTCP_PRIO)) != 0)
+ break;
+
mp_opt->echo = (*ptr++) & MPTCP_ADDR_ECHO;
if (!mp_opt->echo) {
if (opsize == TCPOLEN_MPTCP_ADD_ADDR ||
@@ -293,6 +319,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
case MPTCPOPT_RM_ADDR:
+ /* 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_ADD_ADDR |
+ OPTION_MPTCP_PRIO)) != 0)
+ break;
+
if (opsize < TCPOLEN_MPTCP_RM_ADDR_BASE + 1 ||
opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX)
break;
@@ -307,6 +341,13 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
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_ADD_ADDR |
+ OPTION_MPTCP_RM_ADDR)) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_PRIO)
break;
@@ -316,6 +357,10 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
case MPTCPOPT_MP_FASTCLOSE:
+ /* Can be used only with RST */
+ if ((mp_opt->suboptions & ~OPTION_MPTCP_RST) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_FASTCLOSE)
break;
@@ -327,6 +372,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
case MPTCPOPT_RST:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTION_MPTCP_FAIL |
+ OPTION_MPTCP_FASTCLOSE)) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_RST)
break;
@@ -342,6 +392,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
case MPTCPOPT_MP_FAIL:
+ /* Can be used with a restricted number of other options */
+ if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_RST)) != 0)
+ break;
+
if (opsize != TCPOLEN_MPTCP_FAIL)
break;
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 4a2d40cd7b13..c13680d18994 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -37,6 +37,7 @@
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)
/* MPTCP option subtypes */
#define MPTCPOPT_MP_CAPABLE 0
--
2.53.0