MPTCP Linux Development
 help / color / mirror / Atom feed
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


  parent reply	other threads:[~2026-08-12 10:06 UTC|newest]

Thread overview: 7+ 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
2026-08-13  1:30   ` gang.yan

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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox