Netdev List
 help / color / mirror / Atom feed
From: Zhang Cen <rollkingzzc@gmail.com>
To: Jamal Hadi Salim <jhs@mojatatu.com>,
	Jiri Pirko <jiri@resnulli.us>,
	"David S. Miller" <davem@davemloft.net>,
	Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Simon Horman <horms@kernel.org>
Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	zerocling0077@gmail.com, 2045gemini@gmail.com,
	Zhang Cen <rollkingzzc@gmail.com>,
	stable@vger.kernel.org
Subject: [PATCH] net/sched: act_pedit: extend the writable skb range per key
Date: Sun, 17 May 2026 00:28:25 +0800	[thread overview]
Message-ID: <20260516162825.1480113-1-rollkingzzc@gmail.com> (raw)

tcf_pedit_act() builds a rough writable prefix from tcfp_off_max_hint
before the action mutates any packet bytes.

Since 6c02568fd1ae, TCP and UDP keys recompute their L4 base from the
current L3 header inside the key loop. An earlier key can therefore
change a later header-relative base and make the final store land
outside the initially ensured prefix, where it can fall back to
skb_store_bits() on skb frags.

Keep the initial estimate as a fast path, but grow the ensured writable
range from each key's final computed write offset before loading or
storing the edited word.

Fixes: 6c02568fd1ae ("net/sched: act_pedit: Parse L3 Header for L4 offset")
Cc: stable@vger.kernel.org
Co-developed-by: Han Guidong <2045gemini@gmail.com>
Signed-off-by: Han Guidong <2045gemini@gmail.com>
Signed-off-by: Zhang Cen <rollkingzzc@gmail.com>
---
While researching recent page cache bugs, we discovered this bug. We confirmed it allows overwriting the page cache of read-only files via splice(). We haven't attempted to write an exploit, but the corruption primitive is verified. PoC available upon request. Recommend fixing ASAP.
---
 net/sched/act_pedit.c | 36 ++++++++++++++++++++++++++----------
 1 file changed, 26 insertions(+), 10 deletions(-)

diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index bc20f08a27890..58a8eae6d43e7 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -398,11 +398,12 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
 
 	parms = rcu_dereference_bh(p->parms);
 
-	max_offset = (skb_transport_header_was_set(skb) ?
-		      skb_transport_offset(skb) :
-		      skb_network_offset(skb)) +
-		     parms->tcfp_off_max_hint;
-	if (skb_ensure_writable(skb, min(skb->len, max_offset)))
+	max_offset = min_t(u32, skb->len,
+			   (skb_transport_header_was_set(skb) ?
+			    skb_transport_offset(skb) :
+			    skb_network_offset(skb)) +
+			   parms->tcfp_off_max_hint);
+	if (skb_ensure_writable(skb, max_offset))
 		goto done;
 
 	tcf_lastuse_update(&p->tcf_tm);
@@ -414,8 +415,9 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
 	for (i = parms->tcfp_nkeys; i > 0; i--, tkey++) {
 		int offset = tkey->off;
 		int hoffset = 0;
+		int write_offset;
 		u32 *ptr, hdata;
-		u32 val;
+		u32 val, write_end;
 		int rc;
 
 		if (tkey_ex) {
@@ -451,12 +453,26 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
 			}
 		}
 
-		if (!offset_valid(skb, hoffset + offset)) {
-			pr_info_ratelimited("tc action pedit offset %d out of bounds\n", hoffset + offset);
+		write_offset = hoffset + offset;
+		if (!offset_valid(skb, write_offset)) {
+			pr_info_ratelimited("tc action pedit offset %d out of bounds\n",
+					    write_offset);
 			goto bad;
 		}
 
-		ptr = skb_header_pointer(skb, hoffset + offset,
+		/* Earlier edits can change later header-relative offsets, so
+		 * grow the writable window from the final per-key store.
+		 */
+		if (write_offset >= 0) {
+			write_end = (u32)write_offset + sizeof(hdata);
+			if (write_end > max_offset) {
+				max_offset = min_t(u32, skb->len, write_end);
+				if (skb_ensure_writable(skb, max_offset))
+					goto bad;
+			}
+		}
+
+		ptr = skb_header_pointer(skb, write_offset,
 					 sizeof(hdata), &hdata);
 		if (!ptr)
 			goto bad;
@@ -475,7 +491,7 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
 
 		*ptr = ((*ptr & tkey->mask) ^ val);
 		if (ptr == &hdata)
-			skb_store_bits(skb, hoffset + offset, ptr, 4);
+			skb_store_bits(skb, write_offset, ptr, sizeof(hdata));
 	}
 
 	goto done;
-- 
2.43.0


                 reply	other threads:[~2026-05-16 16:28 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20260516162825.1480113-1-rollkingzzc@gmail.com \
    --to=rollkingzzc@gmail.com \
    --cc=2045gemini@gmail.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=jhs@mojatatu.com \
    --cc=jiri@resnulli.us \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=stable@vger.kernel.org \
    --cc=zerocling0077@gmail.com \
    /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