All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ido Schimmel <idosch@nvidia.com>
To: Zhiling Zou <zhilinz@nebusec.ai>
Cc: netdev@vger.kernel.org, dsahern@kernel.org, davem@davemloft.net,
	edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
	horms@kernel.org, atenart@kernel.org, yuehaibing@huawei.com,
	kuniyu@google.com, kees@kernel.org, kylebot@openai.com,
	thorsten.blum@linux.dev, maoyixie.tju@gmail.com, vega@nebusec.ai
Subject: Re: [PATCH net v4 1/2] ip6_gre: fix hardware header length for NBMA tunnels
Date: Mon, 17 Aug 2026 09:42:50 +0300	[thread overview]
Message-ID: <20260817064250.GA196908@shredder> (raw)
In-Reply-To: <64b46542bbe1701f07702aaa50273e2a87903db5.1786542637.git.zhilinz@nebusec.ai>

On Thu, Aug 13, 2026 at 12:22:34AM +0800, Zhiling Zou wrote:
> ip6gre_tnl_link_config_route() accumulates the lower device's hardware
> header length into dev->hard_header_len whenever header_ops is set. This
> is incorrect for both users of header_ops.
> 
> ip6gretap and ip6erspan have a fixed Ethernet hardware header length.
> For an NBMA ip6gre tunnel, ip6gre_header() creates only the GRE header,
> the optional FOU or GUE header, and the outer IPv6 header. The lower
> device header is headroom needed later, not part of the tunnel device's
> hardware header.
> 
> Keep the lower device header in needed_headroom. Set hard_header_len to
> the tunnel header length only for ARPHRD_IP6GRE devices with header_ops,
> and leave the fixed Ethernet header length unchanged for tap and erspan
> devices.
> 
> Fixes: 832ba596494b ("net: ip6_gre: set dev->hard_header_len when using header_ops")
> Cc: stable@vger.kernel.org
> Reported-by: Vega <vega@nebusec.ai>

It wasn't reported by Vega.

> Suggested-by: Ido Schimmel <idosch@nvidia.com>
> Signed-off-by: Zhiling Zou <zhilinz@nebusec.ai>

Reviewed-by: Ido Schimmel <idosch@nvidia.com>

You are expected to reply to AI feedback.

"
Patch authors are expected to proactively look into the AI-generated
reviews and handle such feedback as any other kind of review: either
debate it or address it. In both cases a reply on the mailing list is
expected.
"

https://docs.kernel.org/next/process/maintainer-netdev.html#review-timelines

> ---
>  net/ipv6/ip6_gre.c | 13 ++++---------
>  1 file changed, 4 insertions(+), 9 deletions(-)
> 
> diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
> index b843116e9b703..70c1710910203 100644
> --- a/net/ipv6/ip6_gre.c
> +++ b/net/ipv6/ip6_gre.c
> @@ -1137,13 +1137,8 @@ static void ip6gre_tnl_link_config_route(struct ip6_tnl *t, int set_mtu,
>  			return;
>  
>  		if (rt->dst.dev) {
> -			unsigned short dst_len = rt->dst.dev->hard_header_len +
> -						 t_hlen;
> -
> -			if (t->dev->header_ops)
> -				dev->hard_header_len = dst_len;
> -			else
> -				dev->needed_headroom = dst_len;
> +			dev->needed_headroom = rt->dst.dev->hard_header_len +
> +					       t_hlen;

"
Since dev->hard_header_len was already set to t_hlen in ip6gre_calc_hlen()
for NBMA tunnels, doesn't adding t_hlen here double-count the tunnel header
length?
"

No. ip6gre_tnl_link_config_route() is a NOP for NBMA tunnels since they
don't have IP6_TNL_F_CAP_XMIT set.

>  
>  			if (set_mtu) {
>  				int mtu = rt->dst.dev->mtu - t_hlen;
> @@ -1171,8 +1166,8 @@ static int ip6gre_calc_hlen(struct ip6_tnl *tunnel)
>  
>  	t_hlen = tunnel->hlen + sizeof(struct ipv6hdr);
>  
> -	if (tunnel->dev->header_ops)
> -		tunnel->dev->hard_header_len = LL_MAX_HEADER + t_hlen;
> +	if (tunnel->dev->header_ops && tunnel->dev->type == ARPHRD_IP6GRE)
> +		tunnel->dev->hard_header_len = t_hlen;
>  	else
>  		tunnel->dev->needed_headroom = LL_MAX_HEADER + t_hlen;

"
By removing the LL_MAX_HEADER fallback for NBMA ip6gre tunnels, what happens
if rt6_lookup() fails in ip6gre_tnl_link_config_route() (which is expected
for NBMA tunnels with an ANY remote address)?
"

ip6gre_tnl_link_config_route() is not executed for NBMA tunnels.

"
Without the fallback, dev->needed_headroom would remain 0, and the total
allocated headroom would just be t_hlen. When transmitted, the packet will
require t_hlen + physical_dev->hard_header_len bytes, which would miss the
physical device's headroom and force a reallocation and copy via
pskb_expand_head() on every transmitted packet.
"

dev->needed_headroom was 0 even before the patch, but it's irrelevant
since NBMA tunnels seem to be completely broken. See below.

"
This isn't a bug introduced by this patch, but I noticed NBMA IPv6 GRE 
tunnels might be double-encapsulating packets and corrupting headers.

In net/ipv6/ip6_gre.c:__gre6_xmit(), the code relies on the dummy header
pushed by ip6gre_header() to read the destination address:

    if (dev->header_ops && dev->type == ARPHRD_IP6GRE)
        fl6->daddr = ((struct ipv6hdr *)skb->data)->daddr;

However, the dummy header is not pulled before pushing the real outer GRE
and IPv6 headers. Doesn't this leave the dummy headers in the payload,
causing double-encapsulation ([Real IPv6] [Real GRE] [Dummy IPv6]
[Dummy GRE] [Payload])?
"

This does look buggy, but NBMA tunnels are completely broken.
ip6gre_tunnel_xmit() is passing the wrong addresses to
ip6_tnl_xmit_ctl(), so it is always returning 0 and ip6gre_tunnel_xmit()
is dropping the packets. ip6gre_tunnel_xmit() is deriving the addresses
from the tunnel configuration (ANY) instead of from the packet, as
should be done with an NBMA tunnel.

And:

"
This is also a pre-existing issue, but looking at 
net/ipv6/ip6_gre.c:ip6gre_header():

    ipv6h = skb_push(skb, needed);
    ...
    p = (__be16 *)(ipv6h + 1);
    p[0] = ip_tunnel_flags_to_be16(t->parms.o_flags);
    p[1] = htons(type);

This function allocates the full header length via skb_push() and 
initializes the IPv6 header and the first 4 bytes of the GRE header.

Since the remaining bytes of t->hlen (up to 24 bytes for GRE keys, 
checksums, and sequence) are not initialized, and __gre6_xmit() fails 
to pull this dummy header, does this leak uninitialized kernel heap memory 
to the network in every packet?
"

Again, these packets don't even reach __gre6_xmit(), so they don't end
up on the wire.

"
This isn't a bug introduced by this patch, but now that hard_header_len is
set to exactly t_hlen, does it make the disagreement with ip6gre_header()
explicit?
"

Yes, it's returning the wrong value (needs to return 'needed'), but it's
pre-existing and NBMA tunnels wouldn't work even if this is fixed.

  reply	other threads:[~2026-08-17  6:43 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-12 16:22 [PATCH net v4 0/2] net: fix IP6GRE header length before capping tunnel headroom Zhiling Zou
2026-08-12 16:22 ` [PATCH net v4 1/2] ip6_gre: fix hardware header length for NBMA tunnels Zhiling Zou
2026-08-17  6:42   ` Ido Schimmel [this message]
2026-08-12 16:22 ` [PATCH net v4 2/2] net: cap advertised IP tunnel headroom Zhiling Zou
2026-08-17  6:43   ` Ido Schimmel

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=20260817064250.GA196908@shredder \
    --to=idosch@nvidia.com \
    --cc=atenart@kernel.org \
    --cc=davem@davemloft.net \
    --cc=dsahern@kernel.org \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kees@kernel.org \
    --cc=kuba@kernel.org \
    --cc=kuniyu@google.com \
    --cc=kylebot@openai.com \
    --cc=maoyixie.tju@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=thorsten.blum@linux.dev \
    --cc=vega@nebusec.ai \
    --cc=yuehaibing@huawei.com \
    --cc=zhilinz@nebusec.ai \
    /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.