CVE-2017-9074-ipv6-Prevent-overrun-when-parsing-v6-header-options.patch 9.9 KB

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