Netdev List
 help / color / mirror / Atom feed
From: Julian Anastasov <ja@ssi.bg>
To: Jakub Kicinski <kuba@kernel.org>
Cc: pablo@netfilter.org, netfilter-devel@vger.kernel.org,
	davem@davemloft.net, netdev@vger.kernel.org, pabeni@redhat.com,
	edumazet@google.com, fw@strlen.de, horms@kernel.org
Subject: Re: [PATCH net 08/10] ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
Date: Wed, 5 Aug 2026 07:18:14 +0300 (EEST)	[thread overview]
Message-ID: <94204793-387d-c4f4-cdbd-c5876739ad1c@ssi.bg> (raw)
In-Reply-To: <20260805001534.3978877-1-kuba@kernel.org>


	Hello,

On Tue, 4 Aug 2026, Jakub Kicinski wrote:

> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> ipvs: avoid out-of-bounds write in ip_vs_nat_icmp
> 
> This passes the already-parsed ip_vs_iphdr down into ip_vs_nat_icmp() so
> the embedded transport header offset comes from ciph->len instead of a
> second read of the inner IPv4 ihl field.  The IPv4 header sanity checks in
> ip_vs_out_icmp() and ip_vs_in_icmp() are also reworked to read ihl only
> once.
> 
> Link: https://sashiko.dev/#/patchset/20260722101517.36313-1-ja%40ssi.bg
> 
> > diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
> > index 6b79e0c4d9e28..0bdaeb4ed61e4 100644
> > --- a/net/netfilter/ipvs/ip_vs_core.c
> > +++ b/net/netfilter/ipvs/ip_vs_core.c
> > @@ -925,28 +925,27 @@ static int ip_vs_route_me_harder(struct netns_ipvs *ipvs, int af,
> >   */
> >  void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
> >  		    struct ip_vs_conn *cp, int inout, unsigned int toff,
> > -		    bool has_ports)
> > +		    bool has_ports, struct ip_vs_iphdr *ciph)
> >  {
> >  	struct iphdr *iph	 = ip_hdr(skb);
> >  	struct icmphdr *icmph	 = (struct icmphdr *)(skb->data + toff);
> > -	struct iphdr *ciph	 = (struct iphdr *)(icmph + 1);
> > -	unsigned int coff __maybe_unused = toff + sizeof(struct icmphdr);
> > +	struct iphdr *cih	 = (struct iphdr *)(icmph + 1);
> >  
> >  	if (inout) {
> >  		iph->saddr = cp->vaddr.ip;
> >  		ip_send_check(iph);
> > -		ciph->daddr = cp->vaddr.ip;
> > -		ip_send_check(ciph);
> > +		cih->daddr = cp->vaddr.ip;
> > +		ip_send_check(cih);
> >  	} else {
> >  		iph->daddr = cp->daddr.ip;
> >  		ip_send_check(iph);
> > -		ciph->saddr = cp->daddr.ip;
> > -		ip_send_check(ciph);
> > +		cih->saddr = cp->daddr.ip;
> > +		ip_send_check(cih);
> >  	}
> 
> [Severity: High]
> This isn't a bug introduced by this patch, but the two ip_send_check(cih)
> calls here still read the inner ihl field a second time, which looks like
> the same multi-read pattern the commit message describes fixing in this
> function.
> 
> ip_send_check() takes its own fresh read of ihl and checksums 4 * ihl
> bytes:
> 
> net/ipv4/ip_output.c:ip_send_check() {
> 	iph->check = 0;
> 	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
> }
> 
> The only length the callers guarantee is the snapshot value ciph->len (plus
> 4 when ports are mangled):
> 
> net/netfilter/ipvs/ip_vs_core.c:handle_response_icmp() {
> 	unsigned int ctoff = ciph->len;
> 	...
> 		ctoff += 2 * sizeof(__u16);
> 	if (skb_ensure_writable(skb, ctoff))
> 		goto out;
> 	...
> 		ip_vs_nat_icmp(skb, pp, cp, 1, toff, has_ports, ciph);
> }
> 
> ciph->len was computed earlier in ip_vs_fill_iph_skb_off() as
> offset + iph->ihl * 4 from a skb_header_pointer() snapshot, and
> skb_ensure_writable() -> pskb_may_pull() re-copies the bytes out of the
> fragments, so the ihl byte ip_send_check() then reads can differ from the
> one that sized the validated window.
> 
> If the fresh ihl is larger than the snapshot value, can ip_fast_csum() read
> up to 40 bytes past what skb_ensure_writable() guaranteed, and fold
> adjacent skb memory into the inner header checksum that is emitted?
> 
> If the fresh ihl ends up below 5 (for example the version/ihl byte going
> from 0x45 to 0x40, compensated in tot_len so both the inner IP and ICMP
> checksums stay valid), some architectures do not tolerate it:
> 
> arch/mips/include/asm/checksum.h:ip_fast_csum() {
> 	word += 4;
> 	do {
> 		csum += *word;
> 		carry = (csum < *word);
> 		csum += carry;
> 		word++;
> 	} while (word != stop);
> }
> 
> with stop = iph + ihl, so for ihl <= 4 the loop termination is never hit.
> 
> arch/s390/include/asm/checksum.h:ip_fast_csum() {
> 	ihl -= 4;
> 	while (ihl--)
> 		csum += *ptr++;
> }
> 
> where ihl == 0 underflows into roughly four billion forward word reads.
> 
> Would it make sense to checksum over the validated length
> (ciph->len - ciph->off), or to re-validate version/ihl after
> skb_ensure_writable(), matching what was done for the port offset?

	New version of this patch was delayed on friday with
some hours, so now I have a separate fix that revalidates ihl,
ready to be applied on top of this patch...

Regards

--
Julian Anastasov <ja@ssi.bg>


  reply	other threads:[~2026-08-05  4:18 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-31 15:17 [PATCH net 00/10] Netfilter/IPVS fixes for net Pablo Neira Ayuso
2026-07-31 15:17 ` [PATCH net 01/10] ipvs: stop estimator after disabled calc phase Pablo Neira Ayuso
2026-08-05 23:50   ` patchwork-bot+netdevbpf
2026-07-31 15:17 ` [PATCH net 02/10] netfilter: ebt_nflog: pin the NFLOG backend Pablo Neira Ayuso
2026-08-05  0:15   ` Jakub Kicinski
2026-08-05  7:11     ` Florian Westphal
2026-08-05  7:25       ` Paolo Abeni
2026-08-05 17:18     ` Pablo Neira Ayuso
2026-08-05 19:12       ` Florian Westphal
2026-07-31 15:17 ` [PATCH net 03/10] netfilter: ipset: rework cidr bookkeeping Pablo Neira Ayuso
2026-08-05  0:15   ` Jakub Kicinski
2026-08-05  7:33     ` Florian Westphal
2026-08-05 17:19     ` Pablo Neira Ayuso
2026-08-05 19:17       ` Florian Westphal
2026-07-31 15:18 ` [PATCH net 04/10] netfilter: ipset: switch ext_size to atomic64_t Pablo Neira Ayuso
2026-07-31 15:18 ` [PATCH net 05/10] netfilter: ipset: add small wrappers for hash and bucket sizes Pablo Neira Ayuso
2026-07-31 15:18 ` [PATCH net 06/10] netfilter: ipset: add and use mtype_del_cidr_all helper Pablo Neira Ayuso
2026-08-05  0:15   ` Jakub Kicinski
2026-07-31 15:18 ` [PATCH net 07/10] netfilter: ipset: switch to rcu work Pablo Neira Ayuso
2026-07-31 15:18 ` [PATCH net 08/10] ipvs: avoid out-of-bounds write in ip_vs_nat_icmp Pablo Neira Ayuso
2026-08-05  0:15   ` Jakub Kicinski
2026-08-05  4:18     ` Julian Anastasov [this message]
2026-08-05 17:20     ` Pablo Neira Ayuso
2026-07-31 15:18 ` [PATCH net 09/10] ipvs: return the csum validation for forward hook Pablo Neira Ayuso
2026-07-31 15:18 ` [PATCH net 10/10] netfilter: nft_ct: move custom expectation support to helper Pablo Neira Ayuso
2026-08-05  0:15   ` Jakub Kicinski
2026-08-05 17:38     ` Pablo Neira Ayuso
2026-08-05  7:42 ` [PATCH net 00/10] Netfilter/IPVS fixes for net Florian Westphal
2026-08-05 17:39 ` Pablo Neira Ayuso
2026-08-05 23:21   ` Jakub Kicinski

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=94204793-387d-c4f4-cdbd-c5876739ad1c@ssi.bg \
    --to=ja@ssi.bg \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pablo@netfilter.org \
    /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