Message ID | 20150916132733.GQ24810@breakpoint.cc |
---|---|
State | RFC, archived |
Delegated to: | David Miller |
Headers | show |
On Wed, 2015-09-16 at 15:27 +0200, Florian Westphal wrote: > > David, could you test this? I'd do an official patch submission > then. Compiles. Doesn't fix the problem.
On Wed, 2015-09-16 at 15:27 +0200, Florian Westphal wrote: > @@ -599,7 +600,7 @@ int ip6_fragment(struct sock *sk, struct sk_buff > *skb, > /* Correct geometry. */ > if (frag->len > mtu || > ((frag->len & 7) && frag->next) || > - skb_headroom(frag) < hlen) > + skb_headroom(frag) < (hlen + hroom)) > goto slow_path_clean; > > /* Partially cloned skb? */ My test is 'ping -s 2000', and I end up with a fragment of 1280 bytes followed by a fragment of 776 bytes. The test cited above is only actually running on the latter fragment (which for some reason is fine and has headroom of 58 bytes). The first, larger, fragment isn't being checked. And that's the one with only 10 bytes of headroom. [ 62.027984] has frag list [ 62.030616] line 604 check frag ddc5fcc0 len 776 headroom 58 (hlen 40 hroom 16) [ 62.036720] line 678 send skb ded050c0 len 1280 headroom 10 [ 62.041096] skbuff: skb_under_panic: text:c125f9ca len:1294 put:14 head:dec89 000 data:dec88ffc tail:0xdec8950a end:0xdec89f50 dev:br-lan
David Woodhouse <dwmw2@infradead.org> wrote: > > if (frag->len > mtu || > > ((frag->len & 7) && frag->next) || > > - skb_headroom(frag) < hlen) > > + skb_headroom(frag) < (hlen + hroom)) > > goto slow_path_clean; > > > > /* Partially cloned skb? */ > > My test is 'ping -s 2000', and I end up with a fragment of 1280 bytes > followed by a fragment of 776 bytes. > > The test cited above is only actually running on the latter fragment > (which for some reason is fine and has headroom of 58 bytes). > > The first, larger, fragment isn't being checked. And that's the one > with only 10 bytes of headroom. Thanks for this detailed analysis. I've sent a patch that should address all of these issues. Turns out that all tests are wrong in your case. ip6_fragment doesn't expand headroom, since this skb had the ipv6 fragment header pulled, so that part thinks there are 18 bytes available (we later push the frag header back when sending fragments). The 'skb_headroom(frag) < hlen))' is wrong since it neither accounts for device header length nor the fragment header that we need to push. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -586,6 +586,7 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr); + hroom = LL_RESERVED_SPACE(rt->dst.dev); if (skb_has_frag_list(skb)) { int first_len = skb_pagelen(skb); struct sk_buff *frag2; @@ -599,7 +600,7 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb, /* Correct geometry. */ if (frag->len > mtu || ((frag->len & 7) && frag->next) || - skb_headroom(frag) < hlen) + skb_headroom(frag) < (hlen + hroom)) goto slow_path_clean; /* Partially cloned skb? */ @@ -724,7 +725,6 @@ slow_path: */ *prevhdr = NEXTHDR_FRAGMENT; - hroom = LL_RESERVED_SPACE(rt->dst.dev); troom = rt->dst.dev->needed_tailroom; /*