[PATCH net] net: skbuff: reject invalid pull bounds

Shihuang Liu posted 1 patch 1 month ago
net/core/skbuff.c | 3 +++
1 file changed, 3 insertions(+)
[PATCH net] net: skbuff: reject invalid pull bounds
Posted by Shihuang Liu 1 month ago
skb_maybe_pull_tail() subtracts skb_headlen(skb) from the unsigned max
argument and passes the result to __pskb_pull_tail() as a signed int.  The
function does not ensure that max is at least skb_headlen(skb).

This can happen while parsing IPv6 extension headers when an skb already
has a linear area larger than MAX_IPV6_HDR_LEN.  Once the parser needs data
beyond the linear area, max - skb_headlen(skb) wraps and is converted to a
negative delta.  __pskb_pull_tail() then passes that negative length to
skb_copy_bits(), where it can become a very large copy length.

Reject this inconsistent bound before doing the subtraction.  In this case
pulling up to max cannot satisfy len because the initial check established
that skb_headlen(skb) is smaller than len.

Fixes: 1431fb31ecba ("xen-netback: fix fragment detection in checksum setup")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Shihuang Liu <shlomojune6@gmail.com>
---
 net/core/skbuff.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c82a147..33022f7 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -5838,6 +5838,9 @@ static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len,
 	if (max > skb->len)
 		max = skb->len;
 
+	if (max < skb_headlen(skb))
+		return -EPROTO;
+
 	if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL)
 		return -ENOMEM;
 
-- 
2.43.0
Re: [PATCH net] net: skbuff: reject invalid pull bounds
Posted by Eric Dumazet 1 month ago
On Sun, Aug 23, 2026 at 4:26 PM Shihuang Liu <shlomojune6@gmail.com> wrote:
>
> skb_maybe_pull_tail() subtracts skb_headlen(skb) from the unsigned max
> argument and passes the result to __pskb_pull_tail() as a signed int.  The
> function does not ensure that max is at least skb_headlen(skb).
>
> This can happen while parsing IPv6 extension headers when an skb already
> has a linear area larger than MAX_IPV6_HDR_LEN.  Once the parser needs data
> beyond the linear area, max - skb_headlen(skb) wraps and is converted to a
> negative delta.  __pskb_pull_tail() then passes that negative length to
> skb_copy_bits(), where it can become a very large copy length.
>
> Reject this inconsistent bound before doing the subtraction.  In this case
> pulling up to max cannot satisfy len because the initial check established
> that skb_headlen(skb) is smaller than len.
>
> Fixes: 1431fb31ecba ("xen-netback: fix fragment detection in checksum setup")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM

> Signed-off-by: Shihuang Liu <shlomojune6@gmail.com>
> ---
>  net/core/skbuff.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index c82a147..33022f7 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -5838,6 +5838,9 @@ static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len,
>         if (max > skb->len)
>                 max = skb->len;
>
> +       if (max < skb_headlen(skb))
> +               return -EPROTO;
> +

pw-bot: rejected

Please ask your LLM not to slow down the fast path, and find a better
fix in skb_checksum_setup_ipv6().

Note how skb_checksum_setup_ip() is fine.

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d4382b68d56e0b3b247868b4d29ab383cfcf7440..f77d7480594ca6a1dcce2fea737e421d5ea2d38d
100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -5974,7 +5974,8 @@ static int skb_checksum_setup_ipv6(struct
sk_buff *skb, bool recalculate)
                        err = skb_maybe_pull_tail(skb,
                                                  off +
                                                  sizeof(struct ipv6_opt_hdr),
-                                                 MAX_IPV6_HDR_LEN);
+                                                 off +
+                                                 sizeof(struct ipv6_opt_hdr));
                        if (err < 0)
                                goto out;

@@ -5989,7 +5990,8 @@ static int skb_checksum_setup_ipv6(struct
sk_buff *skb, bool recalculate)
                        err = skb_maybe_pull_tail(skb,
                                                  off +
                                                  sizeof(struct ip_auth_hdr),
-                                                 MAX_IPV6_HDR_LEN);
+                                                 off +
+                                                 sizeof(struct ip_auth_hdr));
                        if (err < 0)
                                goto out;

@@ -6004,7 +6006,8 @@ static int skb_checksum_setup_ipv6(struct
sk_buff *skb, bool recalculate)
                        err = skb_maybe_pull_tail(skb,
                                                  off +
                                                  sizeof(struct frag_hdr),
-                                                 MAX_IPV6_HDR_LEN);
+                                                 off +
+                                                 sizeof(struct frag_hdr));
                        if (err < 0)
                                goto out;
Re: [PATCH net] net: skbuff: reject invalid pull bounds
Posted by Eric Dumazet 1 month ago
On Sun, Aug 23, 2026 at 4:51 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Sun, Aug 23, 2026 at 4:26 PM Shihuang Liu <shlomojune6@gmail.com> wrote:
> >
> > skb_maybe_pull_tail() subtracts skb_headlen(skb) from the unsigned max
> > argument and passes the result to __pskb_pull_tail() as a signed int.  The
> > function does not ensure that max is at least skb_headlen(skb).
> >
> > This can happen while parsing IPv6 extension headers when an skb already
> > has a linear area larger than MAX_IPV6_HDR_LEN.  Once the parser needs data
> > beyond the linear area, max - skb_headlen(skb) wraps and is converted to a
> > negative delta.  __pskb_pull_tail() then passes that negative length to
> > skb_copy_bits(), where it can become a very large copy length.
> >
> > Reject this inconsistent bound before doing the subtraction.  In this case
> > pulling up to max cannot satisfy len because the initial check established
> > that skb_headlen(skb) is smaller than len.
> >
> > Fixes: 1431fb31ecba ("xen-netback: fix fragment detection in checksum setup")
> > Cc: stable@vger.kernel.org
> > Assisted-by: LLM
>
> > Signed-off-by: Shihuang Liu <shlomojune6@gmail.com>
> > ---
> >  net/core/skbuff.c | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> > index c82a147..33022f7 100644
> > --- a/net/core/skbuff.c
> > +++ b/net/core/skbuff.c
> > @@ -5838,6 +5838,9 @@ static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len,
> >         if (max > skb->len)
> >                 max = skb->len;
> >
> > +       if (max < skb_headlen(skb))
> > +               return -EPROTO;
> > +
>
> pw-bot: rejected
>
> Please ask your LLM not to slow down the fast path, and find a better
> fix in skb_checksum_setup_ipv6().
>
> Note how skb_checksum_setup_ip() is fine.
>
> diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> index d4382b68d56e0b3b247868b4d29ab383cfcf7440..f77d7480594ca6a1dcce2fea737e421d5ea2d38d
> 100644
> --- a/net/core/skbuff.c
> +++ b/net/core/skbuff.c
> @@ -5974,7 +5974,8 @@ static int skb_checksum_setup_ipv6(struct
> sk_buff *skb, bool recalculate)
>                         err = skb_maybe_pull_tail(skb,
>                                                   off +
>                                                   sizeof(struct ipv6_opt_hdr),
> -                                                 MAX_IPV6_HDR_LEN);
> +                                                 off +
> +                                                 sizeof(struct ipv6_opt_hdr));
>                         if (err < 0)
>                                 goto out;
>
> @@ -5989,7 +5990,8 @@ static int skb_checksum_setup_ipv6(struct
> sk_buff *skb, bool recalculate)
>                         err = skb_maybe_pull_tail(skb,
>                                                   off +
>                                                   sizeof(struct ip_auth_hdr),
> -                                                 MAX_IPV6_HDR_LEN);
> +                                                 off +
> +                                                 sizeof(struct ip_auth_hdr));
>                         if (err < 0)
>                                 goto out;
>
> @@ -6004,7 +6006,8 @@ static int skb_checksum_setup_ipv6(struct
> sk_buff *skb, bool recalculate)
>                         err = skb_maybe_pull_tail(skb,
>                                                   off +
>                                                   sizeof(struct frag_hdr),
> -                                                 MAX_IPV6_HDR_LEN);
> +                                                 off +
> +                                                 sizeof(struct frag_hdr));
>                         if (err < 0)
>                                 goto out;


Following up on this, are you planning to send a V2?

Thanks.
Re: [PATCH net] net: skbuff: reject invalid pull bounds
Posted by J4f J4f 2 weeks, 5 days ago
> Following up on this, are you planning to send a V2?

Yes, hopefully next week. I have a few other things to take care of
first. Sorry for the delay.

Thanks,
Shihuang