]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.9.11/ipv6-fix-ip6_tnl_parse_tlv_enc_lim.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.9.11 / ipv6-fix-ip6_tnl_parse_tlv_enc_lim.patch
1 From foo@baz Tue Feb 14 17:03:08 PST 2017
2 From: Eric Dumazet <edumazet@google.com>
3 Date: Mon, 23 Jan 2017 16:43:06 -0800
4 Subject: ipv6: fix ip6_tnl_parse_tlv_enc_lim()
5
6 From: Eric Dumazet <edumazet@google.com>
7
8
9 [ Upstream commit fbfa743a9d2a0ffa24251764f10afc13eb21e739 ]
10
11 This function suffers from multiple issues.
12
13 First one is that pskb_may_pull() may reallocate skb->head,
14 so the 'raw' pointer needs either to be reloaded or not used at all.
15
16 Second issue is that NEXTHDR_DEST handling does not validate
17 that the options are present in skb->data, so we might read
18 garbage or access non existent memory.
19
20 With help from Willem de Bruijn.
21
22 Signed-off-by: Eric Dumazet <edumazet@google.com>
23 Reported-by: Dmitry Vyukov <dvyukov@google.com>
24 Cc: Willem de Bruijn <willemb@google.com>
25 Signed-off-by: David S. Miller <davem@davemloft.net>
26 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
27 ---
28 net/ipv6/ip6_tunnel.c | 34 ++++++++++++++++++++++------------
29 1 file changed, 22 insertions(+), 12 deletions(-)
30
31 --- a/net/ipv6/ip6_tunnel.c
32 +++ b/net/ipv6/ip6_tunnel.c
33 @@ -400,18 +400,19 @@ ip6_tnl_dev_uninit(struct net_device *de
34
35 __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
36 {
37 - const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
38 - __u8 nexthdr = ipv6h->nexthdr;
39 - __u16 off = sizeof(*ipv6h);
40 + const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
41 + unsigned int nhoff = raw - skb->data;
42 + unsigned int off = nhoff + sizeof(*ipv6h);
43 + u8 next, nexthdr = ipv6h->nexthdr;
44
45 while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
46 - __u16 optlen = 0;
47 struct ipv6_opt_hdr *hdr;
48 - if (raw + off + sizeof(*hdr) > skb->data &&
49 - !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
50 + u16 optlen;
51 +
52 + if (!pskb_may_pull(skb, off + sizeof(*hdr)))
53 break;
54
55 - hdr = (struct ipv6_opt_hdr *) (raw + off);
56 + hdr = (struct ipv6_opt_hdr *)(skb->data + off);
57 if (nexthdr == NEXTHDR_FRAGMENT) {
58 struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
59 if (frag_hdr->frag_off)
60 @@ -422,20 +423,29 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct s
61 } else {
62 optlen = ipv6_optlen(hdr);
63 }
64 + /* cache hdr->nexthdr, since pskb_may_pull() might
65 + * invalidate hdr
66 + */
67 + next = hdr->nexthdr;
68 if (nexthdr == NEXTHDR_DEST) {
69 - __u16 i = off + 2;
70 + u16 i = 2;
71 +
72 + /* Remember : hdr is no longer valid at this point. */
73 + if (!pskb_may_pull(skb, off + optlen))
74 + break;
75 +
76 while (1) {
77 struct ipv6_tlv_tnl_enc_lim *tel;
78
79 /* No more room for encapsulation limit */
80 - if (i + sizeof (*tel) > off + optlen)
81 + if (i + sizeof(*tel) > optlen)
82 break;
83
84 - tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
85 + tel = (struct ipv6_tlv_tnl_enc_lim *) skb->data + off + i;
86 /* return index of option if found and valid */
87 if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
88 tel->length == 1)
89 - return i;
90 + return i + off - nhoff;
91 /* else jump to next option */
92 if (tel->type)
93 i += tel->length + 2;
94 @@ -443,7 +453,7 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct s
95 i++;
96 }
97 }
98 - nexthdr = hdr->nexthdr;
99 + nexthdr = next;
100 off += optlen;
101 }
102 return 0;