public inbox for netfilter-devel@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Florian Westphal <fw@strlen.de>, sungzii <sungzii@pm.me>,
	Sasha Levin <sashal@kernel.org>,
	pablo@netfilter.org, netfilter-devel@vger.kernel.org,
	coreteam@netfilter.org
Subject: [PATCH AUTOSEL 6.19-5.10] netfilter: xt_tcpmss: check remaining length before reading optlen
Date: Sat, 14 Feb 2026 16:23:40 -0500	[thread overview]
Message-ID: <20260214212452.782265-75-sashal@kernel.org> (raw)
In-Reply-To: <20260214212452.782265-1-sashal@kernel.org>

From: Florian Westphal <fw@strlen.de>

[ Upstream commit 735ee8582da3d239eb0c7a53adca61b79fb228b3 ]

Quoting reporter:
  In net/netfilter/xt_tcpmss.c (lines 53-68), the TCP option parser reads
 op[i+1] directly without validating the remaining option length.

  If the last byte of the option field is not EOL/NOP (0/1), the code attempts
  to index op[i+1]. In the case where i + 1 == optlen, this causes an
  out-of-bounds read, accessing memory past the optlen boundary
  (either reading beyond the stack buffer _opt or the
  following payload).

Reported-by: sungzii <sungzii@pm.me>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis of netfilter: xt_tcpmss: check remaining length before
reading optlen

### 1. COMMIT MESSAGE ANALYSIS

The commit message is clear and detailed. The reporter (sungzii)
explains the exact bug mechanism:
- In the TCP option parser in `xt_tcpmss.c`, when iterating through TCP
  options, the code reads `op[i+1]` without first checking that `i+1` is
  within bounds.
- If the last byte of the option field is not EOL/NOP (value 0 or 1),
  the code falls through to the `else` branch and reads `op[i+1]`, which
  is an **out-of-bounds read** when `i + 1 == optlen`.

Key indicators:
- **"Reported-by: sungzii"** - a user found and reported this bug
- **Out-of-bounds read** - a real memory safety bug
- **Netfilter subsystem** - network-facing, security-sensitive code that
  processes packets

### 2. CODE CHANGE ANALYSIS

The fix is a single-line change:

```c
- if (op[i] < 2)
+               if (op[i] < 2 || i == optlen - 1)
```

**What was wrong:** The TCP option parsing loop iterates through option
bytes. Options with values 0 (EOL) and 1 (NOP) are single-byte. All
other options use a TLV (type-length-value) format where `op[i+1]`
contains the length. The code checks `if (op[i] < 2)` to handle single-
byte options, and otherwise reads `op[i+1]` for the length. But if `i`
is the last valid index (`i == optlen - 1`), and the option byte is >=
2, the code reads `op[i+1]` which is **past the end of the buffer**.

**The fix:** Before reading `op[i+1]`, the code now also checks if `i`
is at the last byte (`i == optlen - 1`). If so, it treats it as a
single-byte increment (just `i++`), which will terminate the loop on the
next iteration since `i` will then equal `optlen`.

This is:
- **Obviously correct** - if there's only one byte left, we can't read a
  2-byte option header
- **Minimal** - one condition added to an existing check
- **Safe** - the worst case is we skip a malformed trailing option byte,
  which is the right behavior

### 3. CLASSIFICATION

- **Bug type:** Out-of-bounds read (memory safety)
- **Security relevance:** HIGH - this is in the netfilter packet
  processing path. An attacker could craft TCP packets with malformed
  options to trigger the OOB read. This could leak kernel memory
  contents or trigger a crash depending on the memory layout.
- **Category:** Bounds validation fix

### 4. SCOPE AND RISK ASSESSMENT

- **Lines changed:** 1 line modified
- **Files changed:** 1 file (`net/netfilter/xt_tcpmss.c`)
- **Risk of regression:** Extremely low. The added condition only
  activates when `i == optlen - 1`, meaning the last byte of the
  options. In that case, incrementing by 1 exits the loop. This cannot
  break valid TCP option parsing because valid multi-byte options always
  have at least 2 bytes.
- **Subsystem:** Netfilter - core networking/firewall code used by
  virtually all Linux deployments

### 5. USER IMPACT

- **Who is affected:** Anyone using the `tcpmss` iptables/nftables match
  rule, which is common in firewall configurations
- **Trigger:** Receiving a TCP packet with malformed options (last
  option byte >= 2 with no room for the length byte)
- **Severity:** Out-of-bounds read in packet processing - potential
  information leak or crash
- **Exploitability:** Could be triggered remotely by sending crafted TCP
  packets

### 6. STABILITY INDICATORS

- Author is Florian Westphal, a well-known netfilter maintainer
- The fix is trivial and obviously correct
- The code being fixed has existed for a very long time (the `xt_tcpmss`
  module is ancient)

### 7. DEPENDENCY CHECK

- No dependencies on other commits
- The affected code exists in all stable trees (this is long-standing
  code)
- The patch applies cleanly as a standalone fix

### CONCLUSION

This is a textbook stable backport candidate:
- **Fixes a real bug:** Out-of-bounds read in TCP option parsing
- **Security-sensitive:** In the netfilter packet processing path,
  remotely triggerable
- **Minimal and surgical:** One condition added to one line
- **Zero regression risk:** The additional check is strictly correct
- **No new features:** Pure bug fix
- **Author is subsystem maintainer:** Florian Westphal maintains
  netfilter
- **Affects all stable trees:** The vulnerable code is ancient

**YES**

 net/netfilter/xt_tcpmss.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
index 37704ab017992..0d32d4841cb32 100644
--- a/net/netfilter/xt_tcpmss.c
+++ b/net/netfilter/xt_tcpmss.c
@@ -61,7 +61,7 @@ tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par)
 			return (mssval >= info->mss_min &&
 				mssval <= info->mss_max) ^ info->invert;
 		}
-		if (op[i] < 2)
+		if (op[i] < 2 || i == optlen - 1)
 			i++;
 		else
 			i += op[i+1] ? : 1;
-- 
2.51.0


      parent reply	other threads:[~2026-02-14 21:27 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260214212452.782265-1-sashal@kernel.org>
2026-02-14 21:22 ` [PATCH AUTOSEL 6.19-5.10] netfilter: nf_conntrack: Add allow_clash to generic protocol handler Sasha Levin
2026-02-14 21:23 ` Sasha Levin [this message]

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=20260214212452.782265-75-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=coreteam@netfilter.org \
    --cc=fw@strlen.de \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pablo@netfilter.org \
    --cc=patches@lists.linux.dev \
    --cc=stable@vger.kernel.org \
    --cc=sungzii@pm.me \
    /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