]> git.proxmox.com Git - pve-kernel.git/blame - CVE-2017-9074-ipv6-Prevent-overrun-when-parsing-v6-header-options.patch
update kernel source to Ubuntu-4.10.0-26.30
[pve-kernel.git] / CVE-2017-9074-ipv6-Prevent-overrun-when-parsing-v6-header-options.patch
CommitLineData
0f831b3c
FG
1From 1b56ac5ee17e975a07740b4c865918984ec14b52 Mon Sep 17 00:00:00 2001
2From: Craig Gallek <kraig@google.com>
3Date: Tue, 16 May 2017 14:36:23 -0400
4Subject: [PATCH] ipv6: Prevent overrun when parsing v6 header options
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9The KASAN warning repoted below was discovered with a syzkaller
10program. The reproducer is basically:
11 int s = socket(AF_INET6, SOCK_RAW, NEXTHDR_HOP);
12 send(s, &one_byte_of_data, 1, MSG_MORE);
13 send(s, &more_than_mtu_bytes_data, 2000, 0);
14
15The socket() call sets the nexthdr field of the v6 header to
16NEXTHDR_HOP, the first send call primes the payload with a non zero
17byte of data, and the second send call triggers the fragmentation path.
18
19The fragmentation code tries to parse the header options in order
20to figure out where to insert the fragment option. Since nexthdr points
21to an invalid option, the calculation of the size of the network header
22can made to be much larger than the linear section of the skb and data
23is read outside of it.
24
25This fix makes ip6_find_1stfrag return an error if it detects
26running out-of-bounds.
27
28[ 42.361487] ==================================================================
29[ 42.364412] BUG: KASAN: slab-out-of-bounds in ip6_fragment+0x11c8/0x3730
30[ 42.365471] Read of size 840 at addr ffff88000969e798 by task ip6_fragment-oo/3789
31[ 42.366469]
32[ 42.366696] CPU: 1 PID: 3789 Comm: ip6_fragment-oo Not tainted 4.11.0+ #41
33[ 42.367628] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.1-1ubuntu1 04/01/2014
34[ 42.368824] Call Trace:
35[ 42.369183] dump_stack+0xb3/0x10b
36[ 42.369664] print_address_description+0x73/0x290
37[ 42.370325] kasan_report+0x252/0x370
38[ 42.370839] ? ip6_fragment+0x11c8/0x3730
39[ 42.371396] check_memory_region+0x13c/0x1a0
40[ 42.371978] memcpy+0x23/0x50
41[ 42.372395] ip6_fragment+0x11c8/0x3730
42[ 42.372920] ? nf_ct_expect_unregister_notifier+0x110/0x110
43[ 42.373681] ? ip6_copy_metadata+0x7f0/0x7f0
44[ 42.374263] ? ip6_forward+0x2e30/0x2e30
45[ 42.374803] ip6_finish_output+0x584/0x990
46[ 42.375350] ip6_output+0x1b7/0x690
47[ 42.375836] ? ip6_finish_output+0x990/0x990
48[ 42.376411] ? ip6_fragment+0x3730/0x3730
49[ 42.376968] ip6_local_out+0x95/0x160
50[ 42.377471] ip6_send_skb+0xa1/0x330
51[ 42.377969] ip6_push_pending_frames+0xb3/0xe0
52[ 42.378589] rawv6_sendmsg+0x2051/0x2db0
53[ 42.379129] ? rawv6_bind+0x8b0/0x8b0
54[ 42.379633] ? _copy_from_user+0x84/0xe0
55[ 42.380193] ? debug_check_no_locks_freed+0x290/0x290
56[ 42.380878] ? ___sys_sendmsg+0x162/0x930
57[ 42.381427] ? rcu_read_lock_sched_held+0xa3/0x120
58[ 42.382074] ? sock_has_perm+0x1f6/0x290
59[ 42.382614] ? ___sys_sendmsg+0x167/0x930
60[ 42.383173] ? lock_downgrade+0x660/0x660
61[ 42.383727] inet_sendmsg+0x123/0x500
62[ 42.384226] ? inet_sendmsg+0x123/0x500
63[ 42.384748] ? inet_recvmsg+0x540/0x540
64[ 42.385263] sock_sendmsg+0xca/0x110
65[ 42.385758] SYSC_sendto+0x217/0x380
66[ 42.386249] ? SYSC_connect+0x310/0x310
67[ 42.386783] ? __might_fault+0x110/0x1d0
68[ 42.387324] ? lock_downgrade+0x660/0x660
69[ 42.387880] ? __fget_light+0xa1/0x1f0
70[ 42.388403] ? __fdget+0x18/0x20
71[ 42.388851] ? sock_common_setsockopt+0x95/0xd0
72[ 42.389472] ? SyS_setsockopt+0x17f/0x260
73[ 42.390021] ? entry_SYSCALL_64_fastpath+0x5/0xbe
74[ 42.390650] SyS_sendto+0x40/0x50
75[ 42.391103] entry_SYSCALL_64_fastpath+0x1f/0xbe
76[ 42.391731] RIP: 0033:0x7fbbb711e383
77[ 42.392217] RSP: 002b:00007ffff4d34f28 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
78[ 42.393235] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbbb711e383
79[ 42.394195] RDX: 0000000000001000 RSI: 00007ffff4d34f60 RDI: 0000000000000003
80[ 42.395145] RBP: 0000000000000046 R08: 00007ffff4d34f40 R09: 0000000000000018
81[ 42.396056] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000400aad
82[ 42.396598] R13: 0000000000000066 R14: 00007ffff4d34ee0 R15: 00007fbbb717af00
83[ 42.397257]
84[ 42.397411] Allocated by task 3789:
85[ 42.397702] save_stack_trace+0x16/0x20
86[ 42.398005] save_stack+0x46/0xd0
87[ 42.398267] kasan_kmalloc+0xad/0xe0
88[ 42.398548] kasan_slab_alloc+0x12/0x20
89[ 42.398848] __kmalloc_node_track_caller+0xcb/0x380
90[ 42.399224] __kmalloc_reserve.isra.32+0x41/0xe0
91[ 42.399654] __alloc_skb+0xf8/0x580
92[ 42.400003] sock_wmalloc+0xab/0xf0
93[ 42.400346] __ip6_append_data.isra.41+0x2472/0x33d0
94[ 42.400813] ip6_append_data+0x1a8/0x2f0
95[ 42.401122] rawv6_sendmsg+0x11ee/0x2db0
96[ 42.401505] inet_sendmsg+0x123/0x500
97[ 42.401860] sock_sendmsg+0xca/0x110
98[ 42.402209] ___sys_sendmsg+0x7cb/0x930
99[ 42.402582] __sys_sendmsg+0xd9/0x190
100[ 42.402941] SyS_sendmsg+0x2d/0x50
101[ 42.403273] entry_SYSCALL_64_fastpath+0x1f/0xbe
102[ 42.403718]
103[ 42.403871] Freed by task 1794:
104[ 42.404146] save_stack_trace+0x16/0x20
105[ 42.404515] save_stack+0x46/0xd0
106[ 42.404827] kasan_slab_free+0x72/0xc0
107[ 42.405167] kfree+0xe8/0x2b0
108[ 42.405462] skb_free_head+0x74/0xb0
109[ 42.405806] skb_release_data+0x30e/0x3a0
110[ 42.406198] skb_release_all+0x4a/0x60
111[ 42.406563] consume_skb+0x113/0x2e0
112[ 42.406910] skb_free_datagram+0x1a/0xe0
113[ 42.407288] netlink_recvmsg+0x60d/0xe40
114[ 42.407667] sock_recvmsg+0xd7/0x110
115[ 42.408022] ___sys_recvmsg+0x25c/0x580
116[ 42.408395] __sys_recvmsg+0xd6/0x190
117[ 42.408753] SyS_recvmsg+0x2d/0x50
118[ 42.409086] entry_SYSCALL_64_fastpath+0x1f/0xbe
119[ 42.409513]
120[ 42.409665] The buggy address belongs to the object at ffff88000969e780
121[ 42.409665] which belongs to the cache kmalloc-512 of size 512
122[ 42.410846] The buggy address is located 24 bytes inside of
123[ 42.410846] 512-byte region [ffff88000969e780, ffff88000969e980)
124[ 42.411941] The buggy address belongs to the page:
125[ 42.412405] page:ffffea000025a780 count:1 mapcount:0 mapping: (null) index:0x0 compound_mapcount: 0
126[ 42.413298] flags: 0x100000000008100(slab|head)
127[ 42.413729] raw: 0100000000008100 0000000000000000 0000000000000000 00000001800c000c
128[ 42.414387] raw: ffffea00002a9500 0000000900000007 ffff88000c401280 0000000000000000
129[ 42.415074] page dumped because: kasan: bad access detected
130[ 42.415604]
131[ 42.415757] Memory state around the buggy address:
132[ 42.416222] ffff88000969e880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
133[ 42.416904] ffff88000969e900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
134[ 42.417591] >ffff88000969e980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
135[ 42.418273] ^
136[ 42.418588] ffff88000969ea00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
137[ 42.419273] ffff88000969ea80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
138[ 42.419882] ==================================================================
139
140Reported-by: Andrey Konovalov <andreyknvl@google.com>
141Signed-off-by: Craig Gallek <kraig@google.com>
142Signed-off-by: David S. Miller <davem@davemloft.net>
143
144CVE-2017-9074
145
146(cherry-picked from 2423496af35d94a87156b063ea5cedffc10a70a1)
147Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
148Acked-by: Colin King <colin.king@canonical.com>
149Acked-by: Andy Whitcroft <andy.whitcroft@canonical.com>
150Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
151
152Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
153---
154 net/ipv6/ip6_offload.c | 2 ++
155 net/ipv6/ip6_output.c | 4 ++++
156 net/ipv6/output_core.c | 14 ++++++++------
157 net/ipv6/udp_offload.c | 2 ++
158 4 files changed, 16 insertions(+), 6 deletions(-)
159
160diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
161index 33b04ec2744a..9881a87696bc 100644
162--- a/net/ipv6/ip6_offload.c
163+++ b/net/ipv6/ip6_offload.c
164@@ -117,6 +117,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
165
166 if (udpfrag) {
167 unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
168+ if (unfrag_ip6hlen < 0)
169+ return ERR_PTR(unfrag_ip6hlen);
170 fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
171 fptr->frag_off = htons(offset);
172 if (skb->next)
173diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
174index d57f4ee5ec29..8f0814d301aa 100644
175--- a/net/ipv6/ip6_output.c
176+++ b/net/ipv6/ip6_output.c
177@@ -597,6 +597,10 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
178 u8 *prevhdr, nexthdr = 0;
179
180 hlen = ip6_find_1stfragopt(skb, &prevhdr);
181+ if (hlen < 0) {
182+ err = hlen;
183+ goto fail;
184+ }
185 nexthdr = *prevhdr;
186
187 mtu = ip6_skb_dst_mtu(skb);
188diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
189index cd4252346a32..e9065b8d3af8 100644
190--- a/net/ipv6/output_core.c
191+++ b/net/ipv6/output_core.c
192@@ -79,14 +79,13 @@ EXPORT_SYMBOL(ipv6_select_ident);
193 int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
194 {
195 u16 offset = sizeof(struct ipv6hdr);
196- struct ipv6_opt_hdr *exthdr =
197- (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
198 unsigned int packet_len = skb_tail_pointer(skb) -
199 skb_network_header(skb);
200 int found_rhdr = 0;
201 *nexthdr = &ipv6_hdr(skb)->nexthdr;
202
203- while (offset + 1 <= packet_len) {
204+ while (offset <= packet_len) {
205+ struct ipv6_opt_hdr *exthdr;
206
207 switch (**nexthdr) {
208
209@@ -107,13 +106,16 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
210 return offset;
211 }
212
213- offset += ipv6_optlen(exthdr);
214- *nexthdr = &exthdr->nexthdr;
215+ if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
216+ return -EINVAL;
217+
218 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
219 offset);
220+ offset += ipv6_optlen(exthdr);
221+ *nexthdr = &exthdr->nexthdr;
222 }
223
224- return offset;
225+ return -EINVAL;
226 }
227 EXPORT_SYMBOL(ip6_find_1stfragopt);
228
229diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
230index ac858c480f2f..b348cff47395 100644
231--- a/net/ipv6/udp_offload.c
232+++ b/net/ipv6/udp_offload.c
233@@ -91,6 +91,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
234 * bytes to insert fragment header.
235 */
236 unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
237+ if (unfrag_ip6hlen < 0)
238+ return ERR_PTR(unfrag_ip6hlen);
239 nexthdr = *prevhdr;
240 *prevhdr = NEXTHDR_FRAGMENT;
241 unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
242--
2432.11.0
244