kernel: fq_codel match flows_cnt to limit sizing
[openwrt/openwrt.git] / target / linux / generic / patches-4.1 / 080-ipv6-ip6_fragment-fix-headroom-tests-and-skb-leak.patch
1 From: Florian Westphal <fw@strlen.de>
2 Date: Thu, 17 Sep 2015 11:24:48 +0100
3 Subject: [PATCH] ipv6: ip6_fragment: fix headroom tests and skb leak
4
5 David Woodhouse reports skb_under_panic when we try to push ethernet
6 header to fragmented ipv6 skbs:
7
8 skbuff: skb_under_panic: text:c1277f1e len:1294 put:14 head:dec98000
9 data:dec97ffc tail:0xdec9850a end:0xdec98f40 dev:br-lan
10 [..]
11 ip6_finish_output2+0x196/0x4da
12
13 David further debugged this:
14 [..] offending fragments were arriving here with skb_headroom(skb)==10.
15 Which is reasonable, being the Solos ADSL card's header of 8 bytes
16 followed by 2 bytes of PPP frame type.
17
18 The problem is that if netfilter ipv6 defragmentation is used, skb_cow()
19 in ip6_forward will only see reassembled skb.
20
21 Therefore, headroom is overestimated by 8 bytes (we pulled fragment
22 header) and we don't check the skbs in the frag_list either.
23
24 We can't do these checks in netfilter defrag since outdev isn't known yet.
25
26 Furthermore, existing tests in ip6_fragment did not consider the fragment
27 or ipv6 header size when checking headroom of the fraglist skbs.
28
29 While at it, also fix a skb leak on memory allocation -- ip6_fragment
30 must consume the skb.
31
32 I tested this e1000 driver hacked to not allocate additional headroom
33 (we end up in slowpath, since LL_RESERVED_SPACE is 16).
34
35 If 2 bytes of headroom are allocated, fastpath is taken (14 byte
36 ethernet header was pulled, so 16 byte headroom available in all
37 fragments).
38
39 Reported-by: David Woodhouse <dwmw2@infradead.org>
40 Diagnosed-by: David Woodhouse <dwmw2@infradead.org>
41 Signed-off-by: Florian Westphal <fw@strlen.de>
42 Closes 20532
43 ---
44
45 --- a/net/ipv6/ip6_output.c
46 +++ b/net/ipv6/ip6_output.c
47 @@ -587,20 +587,22 @@ int ip6_fragment(struct sock *sk, struct
48 }
49 mtu -= hlen + sizeof(struct frag_hdr);
50
51 + hroom = LL_RESERVED_SPACE(rt->dst.dev);
52 if (skb_has_frag_list(skb)) {
53 int first_len = skb_pagelen(skb);
54 struct sk_buff *frag2;
55
56 if (first_len - hlen > mtu ||
57 ((first_len - hlen) & 7) ||
58 - skb_cloned(skb))
59 + skb_cloned(skb) ||
60 + skb_headroom(skb) < (hroom + sizeof(struct frag_hdr)))
61 goto slow_path;
62
63 skb_walk_frags(skb, frag) {
64 /* Correct geometry. */
65 if (frag->len > mtu ||
66 ((frag->len & 7) && frag->next) ||
67 - skb_headroom(frag) < hlen)
68 + skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr)))
69 goto slow_path_clean;
70
71 /* Partially cloned skb? */
72 @@ -617,8 +619,6 @@ int ip6_fragment(struct sock *sk, struct
73
74 err = 0;
75 offset = 0;
76 - frag = skb_shinfo(skb)->frag_list;
77 - skb_frag_list_init(skb);
78 /* BUILD HEADER */
79
80 *prevhdr = NEXTHDR_FRAGMENT;
81 @@ -626,8 +626,11 @@ int ip6_fragment(struct sock *sk, struct
82 if (!tmp_hdr) {
83 IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
84 IPSTATS_MIB_FRAGFAILS);
85 - return -ENOMEM;
86 + err = -ENOMEM;
87 + goto fail;
88 }
89 + frag = skb_shinfo(skb)->frag_list;
90 + skb_frag_list_init(skb);
91
92 __skb_pull(skb, hlen);
93 fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr));
94 @@ -725,7 +728,6 @@ slow_path:
95 */
96
97 *prevhdr = NEXTHDR_FRAGMENT;
98 - hroom = LL_RESERVED_SPACE(rt->dst.dev);
99 troom = rt->dst.dev->needed_tailroom;
100
101 /*