* [PATCH mptcp-next 1/3] mptcp: options: use a dedicated bit for csum reqd
2026-09-03 11:24 [PATCH mptcp-next 0/3] mptcp: options: MIB for invalid & drop suboptions Matthieu Baerts (NGI0)
@ 2026-09-03 11:24 ` Matthieu Baerts (NGI0)
2026-09-03 11:24 ` [PATCH mptcp-next 2/3] mptcp: options: track invalid suboptions Matthieu Baerts (NGI0)
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Matthieu Baerts (NGI0) @ 2026-09-03 11:24 UTC (permalink / raw)
To: MPTCP Linux; +Cc: Matthieu Baerts (NGI0)
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) <matttbe@kernel.org>
---
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=0."
*/
- if ((flags & MPTCP_CAP_CHECKSUM_REQD) &&
- opsize < TCPOLEN_MPTCP_MPC_ACK_DATA)
- mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD;
+ mp_opt->csum_reqd = (flags & MPTCP_CAP_CHECKSUM_REQD) &&
+ opsize < TCPOLEN_MPTCP_MPC_ACK_DATA;
mp_opt->deny_join_id0 = !!(flags & MPTCP_CAP_DENY_JOIN_ID0);
@@ -122,7 +121,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
}
if (opsize == TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM) {
mp_opt->csum = get_unaligned((__force __sum16 *)ptr);
- mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD;
+ mp_opt->csum_reqd = 1;
ptr += 2;
}
pr_debug("MP_CAPABLE version=%x, flags=%x, optlen=%d sndr=%llu, rcvr=%llu len=%d csum=%u\n",
@@ -248,14 +247,14 @@ static void mptcp_parse_option(const struct sk_buff *skb,
ptr += 2;
if (opsize == expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) {
- mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD;
mp_opt->csum = get_unaligned((__force __sum16 *)ptr);
+ mp_opt->csum_reqd = 1;
ptr += 2;
}
pr_debug("data_seq=%llu subflow_seq=%u data_len=%u csum=%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);
}
@@ -263,7 +262,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
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)) != 0)
break;
@@ -330,7 +329,7 @@ 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_MPC_ACK |
OPTIONS_MPTCP_MPJ |
- OPTIONS_MPTCP_DSS |
+ OPTION_MPTCP_DSS |
OPTION_MPTCP_ADD_ADDR |
OPTION_MPTCP_PRIO)) != 0)
break;
@@ -351,7 +350,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
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)) != 0)
break;
@@ -366,7 +365,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
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)) != 0)
break;
@@ -402,7 +401,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
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)) != 0)
break;
@@ -1349,7 +1348,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
}
mpext->data_len = mp_opt.data_len;
mpext->use_map = 1;
- mpext->csum_reqd = !!(mp_opt.suboptions & OPTION_MPTCP_CSUMREQD);
+ mpext->csum_reqd = mp_opt.csum_reqd;
if (mpext->csum_reqd)
mpext->csum = 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 *sk,
WRITE_ONCE(msk->token, subflow_req->token);
msk->in_accept_queue = 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);
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)
-#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)
/* 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, const struct sk_buff *skb)
goto fallback;
}
- 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);
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH mptcp-next 2/3] mptcp: options: track invalid suboptions
2026-09-03 11:24 [PATCH mptcp-next 0/3] mptcp: options: MIB for invalid & drop suboptions Matthieu Baerts (NGI0)
2026-09-03 11:24 ` [PATCH mptcp-next 1/3] mptcp: options: use a dedicated bit for csum reqd Matthieu Baerts (NGI0)
@ 2026-09-03 11:24 ` Matthieu Baerts (NGI0)
2026-09-03 11:24 ` [PATCH mptcp-next 3/3] mptcp: options: reset parsing in case of invalidity Matthieu Baerts (NGI0)
2026-09-03 12:28 ` [PATCH mptcp-next 0/3] mptcp: options: MIB for invalid & drop suboptions MPTCP CI
3 siblings, 0 replies; 7+ messages in thread
From: Matthieu Baerts (NGI0) @ 2026-09-03 11:24 UTC (permalink / raw)
To: MPTCP Linux; +Cc: Matthieu Baerts (NGI0), Gang Yan
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 <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
---
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[] = {
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),
};
/* 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
};
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) == MPTCP_CAP_HMAC_SHA256;
}
-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 == OPTION_MPTCP_MPC_ACK) {
if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR) != 0)
- break;
+ goto invalid;
} else if (mp_opt->suboptions != 0) {
- break;
+ goto invalid;
}
/* Cfr RFC 8684 Section 3.3.0:
@@ -71,7 +71,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
if (opsize != expected_opsize &&
(expected_opsize != TCPOLEN_MPTCP_MPC_ACK_DATA ||
opsize != TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM))
- break;
+ goto invalid;
/* try to be gentle vs future versions on the initial syn */
version = *ptr++ & MPTCP_VERSION_MASK;
@@ -133,7 +133,7 @@ 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_RM_ADDR |
OPTION_MPTCP_PRIO)) != 0)
- break;
+ goto invalid;
if (opsize == TCPOLEN_MPTCP_MPJ_SYN) {
mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYN;
@@ -162,6 +162,8 @@ static void mptcp_parse_option(const struct sk_buff *skb,
ptr += 2;
memcpy(mp_opt->hmac, ptr, MPTCPOPT_HMAC_LEN);
pr_debug("MP_JOIN hmac\n");
+ } else {
+ goto invalid;
}
break;
@@ -172,7 +174,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
OPTION_MPTCP_PRIO |
OPTION_MPTCP_FASTCLOSE |
OPTION_MPTCP_FAIL)) != 0)
- break;
+ goto invalid;
pr_debug("DSS\n");
ptr++;
@@ -215,7 +217,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
mp_opt->ack64 = 0;
mp_opt->use_ack = 0;
mp_opt->data_fin = 0;
- break;
+ goto invalid;
}
mp_opt->suboptions |= OPTION_MPTCP_DSS;
@@ -265,7 +267,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
if ((mp_opt->suboptions & ~(OPTION_MPTCP_DSS |
OPTION_MPTCP_RM_ADDR |
OPTION_MPTCP_PRIO)) != 0)
- break;
+ goto invalid;
mp_opt->echo = (*ptr++) & MPTCP_ADDR_ECHO;
if (!mp_opt->echo) {
@@ -278,7 +280,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
mp_opt->addr.family = AF_INET6;
#endif
else
- break;
+ goto invalid;
} else {
if (opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE ||
opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT)
@@ -289,7 +291,7 @@ static void mptcp_parse_option(const struct sk_buff *skb,
mp_opt->addr.family = AF_INET6;
#endif
else
- break;
+ goto invalid;
}
mp_opt->suboptions |= 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)) != 0)
- break;
+ goto invalid;
if (opsize < TCPOLEN_MPTCP_RM_ADDR_BASE + 1 ||
opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX)
- break;
+ goto invalid;
ptr++;
@@ -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)) != 0)
- break;
+ goto invalid;
if (opsize != TCPOLEN_MPTCP_PRIO)
- break;
+ goto invalid;
mp_opt->suboptions |= OPTION_MPTCP_PRIO;
mp_opt->backup = *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)) != 0)
- break;
+ goto invalid;
if (opsize != TCPOLEN_MPTCP_FASTCLOSE)
- break;
+ goto invalid;
ptr += 2;
mp_opt->rcvr_key = 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)) != 0)
- break;
+ goto invalid;
if (opsize != TCPOLEN_MPTCP_RST)
- break;
+ goto invalid;
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)) != 0)
- break;
+ goto invalid;
if (opsize != TCPOLEN_MPTCP_FAIL)
- break;
+ goto invalid;
ptr += 2;
mp_opt->suboptions |= OPTION_MPTCP_FAIL;
@@ -415,11 +417,17 @@ static void mptcp_parse_option(const struct sk_buff *skb,
break;
default:
+ /* Not invalid: maybe used for experimentations */
break;
}
+
+ return;
+
+invalid:
+ MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OPTINVALID);
}
-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 = 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 == TCPOPT_MPTCP)
- mptcp_parse_option(skb, ptr, opsize, mp_opt);
+ mptcp_parse_option(sk, skb, ptr, opsize,
+ mp_opt);
ptr += opsize - 2;
length -= opsize;
}
@@ -1248,7 +1257,7 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
return !mptcp_over_limit(subflow->conn, sk, skb);
}
- mptcp_get_options(skb, &mp_opt);
+ mptcp_get_options(sk, skb, &mp_opt);
/* 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);
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
- mptcp_get_options(skb, &mp_opt);
+ mptcp_get_options(sk_listener, skb, &mp_opt);
opt_mp_capable = !!(mp_opt.suboptions & OPTION_MPTCP_MPC_SYN);
opt_mp_join = !!(mp_opt.suboptions & OPTION_MPTCP_MPJ_SYN);
@@ -273,7 +273,7 @@ int mptcp_subflow_init_cookie_req(struct request_sock *req,
int err;
subflow_init_req(req, sk_listener);
- mptcp_get_options(skb, &mp_opt);
+ mptcp_get_options(sk_listener, skb, &mp_opt);
opt_mp_capable = !!(mp_opt.suboptions & OPTION_MPTCP_MPC_ACK);
opt_mp_join = !!(mp_opt.suboptions & OPTION_MPTCP_MPJ_ACK);
@@ -540,7 +540,7 @@ static void subflow_finish_connect(struct sock *sk, const struct sk_buff *skb)
subflow->ssn_offset = TCP_SKB_CB(skb)->seq;
pr_debug("subflow=%p synack seq=%x\n", subflow, subflow->ssn_offset);
- 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 struct 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 = true;
} 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 = true;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH mptcp-next 3/3] mptcp: options: reset parsing in case of invalidity
2026-09-03 11:24 [PATCH mptcp-next 0/3] mptcp: options: MIB for invalid & drop suboptions Matthieu Baerts (NGI0)
2026-09-03 11:24 ` [PATCH mptcp-next 1/3] mptcp: options: use a dedicated bit for csum reqd Matthieu Baerts (NGI0)
2026-09-03 11:24 ` [PATCH mptcp-next 2/3] mptcp: options: track invalid suboptions Matthieu Baerts (NGI0)
@ 2026-09-03 11:24 ` Matthieu Baerts (NGI0)
2026-09-03 11:38 ` sashiko-bot
2026-09-03 12:28 ` [PATCH mptcp-next 0/3] mptcp: options: MIB for invalid & drop suboptions MPTCP CI
3 siblings, 1 reply; 7+ messages in thread
From: Matthieu Baerts (NGI0) @ 2026-09-03 11:24 UTC (permalink / raw)
To: MPTCP Linux; +Cc: Matthieu Baerts (NGI0)
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) <matttbe@kernel.org>
---
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) == MPTCP_CAP_HMAC_SHA256;
}
-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 != expected_opsize &&
- opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) {
- mp_opt->dsn64 = 0;
- mp_opt->use_map = 0;
- mp_opt->ack64 = 0;
- mp_opt->use_ack = 0;
- mp_opt->data_fin = 0;
+ opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM)
goto invalid;
- }
mp_opt->suboptions |= 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;
}
- return;
+ return true;
invalid:
MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_OPTINVALID);
+ return false;
}
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 struct sk_buff *skb,
return;
if (opsize > length)
return; /* don't parse partial options */
- if (opcode == TCPOPT_MPTCP)
- mptcp_parse_option(sk, skb, ptr, opsize,
- mp_opt);
+ if (opcode == TCPOPT_MPTCP &&
+ !mptcp_parse_option(sk, skb, ptr, opsize, mp_opt)) {
+ /* invalid option, drop previously parsed opt */
+ *(u32 *)&mp_opt->status = 0;
+ break;
+ }
ptr += opsize - 2;
length -= opsize;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread