From: Gang Yan <gang.yan@linux.dev>
To: mptcp@lists.linux.dev
Cc: Gang Yan <yangang@kylinos.cn>
Subject: [PATCH mptcp-next 2/2] mptcp: add MIB counter for received invalid options
Date: Wed, 12 Aug 2026 18:05:50 +0800 [thread overview]
Message-ID: <20260812100550.148670-3-gang.yan@linux.dev> (raw)
In-Reply-To: <20260812100550.148670-1-gang.yan@linux.dev>
From: Gang Yan <yangang@kylinos.cn>
In mptcp_parse_option(), an MPTCP option is silently ignored via a
'break' under a number of conditions.
This patch adds a MIB counter tracking this as an evidence to show
someone is trying to attack the peer
Assisted-by: Claude:GLM-5.2
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/628
Signed-off-by: Gang Yan <yangang@kylinos.cn>
---
net/mptcp/mib.c | 1 +
net/mptcp/mib.h | 1 +
net/mptcp/options.c | 98 +++++++++++++++++++++++++++++++++------------
3 files changed, 74 insertions(+), 26 deletions(-)
diff --git a/net/mptcp/mib.c b/net/mptcp/mib.c
index 608cb568897c..10e8870dd985 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("InvalidOptionRx", MPTCP_MIB_INVALDOPTIONRX),
};
/* mptcp_mib_alloc - allocate percpu mib counters
diff --git a/net/mptcp/mib.h b/net/mptcp/mib.h
index 1ebdb55e9534..ae0751addd64 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_INVALDOPTIONRX, /* Received an invalid MPTCP option */
__MPTCP_MIB_MAX
};
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index dfdcc888efe3..e9deea0e483a 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -53,9 +53,12 @@ static void mptcp_parse_option(struct net *net,
/* 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)
+ if ((mp_opt->suboptions & ~OPTION_MPTCP_RM_ADDR) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
} else if (mp_opt->suboptions != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
}
@@ -71,22 +74,29 @@ static void mptcp_parse_option(struct net *net,
*/
if (opsize != expected_opsize &&
(expected_opsize != TCPOLEN_MPTCP_MPC_ACK_DATA ||
- opsize != TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM))
+ opsize != TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM)) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
/* try to be gentle vs future versions on the initial syn */
version = *ptr++ & MPTCP_VERSION_MASK;
if (opsize != TCPOLEN_MPTCP_MPC_SYN) {
- if (version != MPTCP_SUPPORTED_VERSION)
+ if (version != MPTCP_SUPPORTED_VERSION) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
} else if (version < MPTCP_SUPPORTED_VERSION) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
}
flags = *ptr++;
if (!mptcp_cap_flag_sha256(flags) ||
- (flags & MPTCP_CAP_EXTENSIBILITY))
+ (flags & MPTCP_CAP_EXTENSIBILITY)) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
/* RFC 6824, Section 3.1:
* "For the Checksum Required bit (labeled "A"), if either
@@ -133,8 +143,10 @@ static void mptcp_parse_option(struct net *net,
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)
+ OPTION_MPTCP_PRIO)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
if (opsize == TCPOLEN_MPTCP_MPJ_SYN) {
mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYN;
@@ -163,6 +175,8 @@ static void mptcp_parse_option(struct net *net,
ptr += 2;
memcpy(mp_opt->hmac, ptr, MPTCPOPT_HMAC_LEN);
pr_debug("MP_JOIN hmac\n");
+ } else {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
}
break;
@@ -172,8 +186,10 @@ static void mptcp_parse_option(struct net *net,
OPTION_MPTCP_RM_ADDR |
OPTION_MPTCP_PRIO |
OPTION_MPTCP_FASTCLOSE |
- OPTION_MPTCP_FAIL)) != 0)
+ OPTION_MPTCP_FAIL)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
pr_debug("DSS\n");
ptr++;
@@ -216,6 +232,7 @@ static void mptcp_parse_option(struct net *net,
mp_opt->ack64 = 0;
mp_opt->use_ack = 0;
mp_opt->data_fin = 0;
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
}
@@ -265,32 +282,38 @@ static void mptcp_parse_option(struct net *net,
/* 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)
+ OPTION_MPTCP_PRIO)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
mp_opt->echo = (*ptr++) & MPTCP_ADDR_ECHO;
if (!mp_opt->echo) {
if (opsize == TCPOLEN_MPTCP_ADD_ADDR ||
- opsize == TCPOLEN_MPTCP_ADD_ADDR_PORT)
+ opsize == TCPOLEN_MPTCP_ADD_ADDR_PORT) {
mp_opt->addr.family = AF_INET;
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
- else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6 ||
- opsize == TCPOLEN_MPTCP_ADD_ADDR6_PORT)
+ } else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6 ||
+ opsize == TCPOLEN_MPTCP_ADD_ADDR6_PORT) {
mp_opt->addr.family = AF_INET6;
#endif
- else
+ } else {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
} else {
if (opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE ||
- opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT)
+ opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT) {
mp_opt->addr.family = AF_INET;
#if IS_ENABLED(CONFIG_MPTCP_IPV6)
- else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE ||
- opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT)
+ } else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE ||
+ opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT) {
mp_opt->addr.family = AF_INET6;
#endif
- else
+ } else {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
}
mp_opt->suboptions |= OPTION_MPTCP_ADD_ADDR;
@@ -332,12 +355,16 @@ static void mptcp_parse_option(struct net *net,
OPTIONS_MPTCP_MPJ |
OPTIONS_MPTCP_DSS |
OPTION_MPTCP_ADD_ADDR |
- OPTION_MPTCP_PRIO)) != 0)
+ OPTION_MPTCP_PRIO)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
if (opsize < TCPOLEN_MPTCP_RM_ADDR_BASE + 1 ||
- opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX)
+ opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
ptr++;
@@ -353,11 +380,15 @@ static void mptcp_parse_option(struct net *net,
if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_MPJ |
OPTIONS_MPTCP_DSS |
OPTION_MPTCP_ADD_ADDR |
- OPTION_MPTCP_RM_ADDR)) != 0)
+ OPTION_MPTCP_RM_ADDR)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
- if (opsize != TCPOLEN_MPTCP_PRIO)
+ if (opsize != TCPOLEN_MPTCP_PRIO) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
mp_opt->suboptions |= OPTION_MPTCP_PRIO;
mp_opt->backup = *ptr++ & MPTCP_PRIO_BKUP;
@@ -367,11 +398,15 @@ static void mptcp_parse_option(struct net *net,
case MPTCPOPT_MP_FASTCLOSE:
/* Can be used with a restricted number of other options */
if ((mp_opt->suboptions & ~(OPTIONS_MPTCP_DSS |
- OPTION_MPTCP_RST)) != 0)
+ OPTION_MPTCP_RST)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
- if (opsize != TCPOLEN_MPTCP_FASTCLOSE)
+ if (opsize != TCPOLEN_MPTCP_FASTCLOSE) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
ptr += 2;
mp_opt->rcvr_key = get_unaligned_be64(ptr);
@@ -383,14 +418,20 @@ static void mptcp_parse_option(struct net *net,
case MPTCPOPT_RST:
/* Can be used with a restricted number of other options */
if ((mp_opt->suboptions & ~(OPTION_MPTCP_FAIL |
- OPTION_MPTCP_FASTCLOSE)) != 0)
+ OPTION_MPTCP_FASTCLOSE)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
- if (opsize != TCPOLEN_MPTCP_RST)
+ if (opsize != TCPOLEN_MPTCP_RST) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
- if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST))
+ if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
mp_opt->suboptions |= OPTION_MPTCP_RST;
flags = *ptr++;
@@ -403,11 +444,15 @@ static void mptcp_parse_option(struct net *net,
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)
+ OPTION_MPTCP_RST)) != 0) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
- if (opsize != TCPOLEN_MPTCP_FAIL)
+ if (opsize != TCPOLEN_MPTCP_FAIL) {
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
+ }
ptr += 2;
mp_opt->suboptions |= OPTION_MPTCP_FAIL;
@@ -416,6 +461,7 @@ static void mptcp_parse_option(struct net *net,
break;
default:
+ MPTCP_INC_STATS(net, MPTCP_MIB_INVALDOPTIONRX);
break;
}
}
--
2.43.0
next prev parent reply other threads:[~2026-08-12 10:06 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 10:05 [PATCH mptcp-next 0/2] mptcp: MIB counter for invalid option Gang Yan
2026-08-12 10:05 ` [PATCH mptcp-next 1/2] mptcp: pass net namespace to options parser Gang Yan
2026-08-12 10:05 ` Gang Yan [this message]
2026-08-12 10:16 ` [PATCH mptcp-next 2/2] mptcp: add MIB counter for received invalid options sashiko-bot
2026-08-12 11:17 ` [PATCH mptcp-next 0/2] mptcp: MIB counter for invalid option MPTCP CI
2026-08-12 15:03 ` Matthieu Baerts
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260812100550.148670-3-gang.yan@linux.dev \
--to=gang.yan@linux.dev \
--cc=mptcp@lists.linux.dev \
--cc=yangang@kylinos.cn \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.