[Z/Y/X/T SRU] Fix CVE-2017-9074

Stefan Bader stefan.bader at canonical.com
Thu Jun 8 07:13:24 UTC 2017


On 08.06.2017 05:12, Po-Hsu Lin (Sam) wrote:
> From the CVE tracker, I think we need this for Artful as well.

Right I probably should have added an Artful hint there as well. I was rather
concentrating on SRU and maybe implicitly hoping that on devel things will fix
themselves in a semi-magical way (rebase or some upstream stable)...

-Stefan

> 
> On Wed, Jun 7, 2017 at 5:28 PM, Stefan Bader <stefan.bader at canonical.com> wrote:
>> The same patch applies to all series (needs -C2 for Trusty, though).
>> Result compile tested for Trusty.
>>
>> -Stefan
>>
>> ---
>>
>> From 2423496af35d94a87156b063ea5cedffc10a70a1 Mon Sep 17 00:00:00 2001
>> From: Craig Gallek <kraig at google.com>
>> Date: Tue, 16 May 2017 14:36:23 -0400
>> Subject: [PATCH] ipv6: Prevent overrun when parsing v6 header options
>>
>> The KASAN warning repoted below was discovered with a syzkaller
>> program.  The reproducer is basically:
>>   int s = socket(AF_INET6, SOCK_RAW, NEXTHDR_HOP);
>>   send(s, &one_byte_of_data, 1, MSG_MORE);
>>   send(s, &more_than_mtu_bytes_data, 2000, 0);
>>
>> The socket() call sets the nexthdr field of the v6 header to
>> NEXTHDR_HOP, the first send call primes the payload with a non zero
>> byte of data, and the second send call triggers the fragmentation path.
>>
>> The fragmentation code tries to parse the header options in order
>> to figure out where to insert the fragment option.  Since nexthdr points
>> to an invalid option, the calculation of the size of the network header
>> can made to be much larger than the linear section of the skb and data
>> is read outside of it.
>>
>> This fix makes ip6_find_1stfrag return an error if it detects
>> running out-of-bounds.
>>
>> [   42.361487] ==================================================================
>> [   42.364412] BUG: KASAN: slab-out-of-bounds in ip6_fragment+0x11c8/0x3730
>> [   42.365471] Read of size 840 at addr ffff88000969e798 by task ip6_fragment-oo/3789
>> [   42.366469]
>> [   42.366696] CPU: 1 PID: 3789 Comm: ip6_fragment-oo Not tainted 4.11.0+ #41
>> [   42.367628] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.1-1ubuntu1 04/01/2014
>> [   42.368824] Call Trace:
>> [   42.369183]  dump_stack+0xb3/0x10b
>> [   42.369664]  print_address_description+0x73/0x290
>> [   42.370325]  kasan_report+0x252/0x370
>> [   42.370839]  ? ip6_fragment+0x11c8/0x3730
>> [   42.371396]  check_memory_region+0x13c/0x1a0
>> [   42.371978]  memcpy+0x23/0x50
>> [   42.372395]  ip6_fragment+0x11c8/0x3730
>> [   42.372920]  ? nf_ct_expect_unregister_notifier+0x110/0x110
>> [   42.373681]  ? ip6_copy_metadata+0x7f0/0x7f0
>> [   42.374263]  ? ip6_forward+0x2e30/0x2e30
>> [   42.374803]  ip6_finish_output+0x584/0x990
>> [   42.375350]  ip6_output+0x1b7/0x690
>> [   42.375836]  ? ip6_finish_output+0x990/0x990
>> [   42.376411]  ? ip6_fragment+0x3730/0x3730
>> [   42.376968]  ip6_local_out+0x95/0x160
>> [   42.377471]  ip6_send_skb+0xa1/0x330
>> [   42.377969]  ip6_push_pending_frames+0xb3/0xe0
>> [   42.378589]  rawv6_sendmsg+0x2051/0x2db0
>> [   42.379129]  ? rawv6_bind+0x8b0/0x8b0
>> [   42.379633]  ? _copy_from_user+0x84/0xe0
>> [   42.380193]  ? debug_check_no_locks_freed+0x290/0x290
>> [   42.380878]  ? ___sys_sendmsg+0x162/0x930
>> [   42.381427]  ? rcu_read_lock_sched_held+0xa3/0x120
>> [   42.382074]  ? sock_has_perm+0x1f6/0x290
>> [   42.382614]  ? ___sys_sendmsg+0x167/0x930
>> [   42.383173]  ? lock_downgrade+0x660/0x660
>> [   42.383727]  inet_sendmsg+0x123/0x500
>> [   42.384226]  ? inet_sendmsg+0x123/0x500
>> [   42.384748]  ? inet_recvmsg+0x540/0x540
>> [   42.385263]  sock_sendmsg+0xca/0x110
>> [   42.385758]  SYSC_sendto+0x217/0x380
>> [   42.386249]  ? SYSC_connect+0x310/0x310
>> [   42.386783]  ? __might_fault+0x110/0x1d0
>> [   42.387324]  ? lock_downgrade+0x660/0x660
>> [   42.387880]  ? __fget_light+0xa1/0x1f0
>> [   42.388403]  ? __fdget+0x18/0x20
>> [   42.388851]  ? sock_common_setsockopt+0x95/0xd0
>> [   42.389472]  ? SyS_setsockopt+0x17f/0x260
>> [   42.390021]  ? entry_SYSCALL_64_fastpath+0x5/0xbe
>> [   42.390650]  SyS_sendto+0x40/0x50
>> [   42.391103]  entry_SYSCALL_64_fastpath+0x1f/0xbe
>> [   42.391731] RIP: 0033:0x7fbbb711e383
>> [   42.392217] RSP: 002b:00007ffff4d34f28 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
>> [   42.393235] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbbb711e383
>> [   42.394195] RDX: 0000000000001000 RSI: 00007ffff4d34f60 RDI: 0000000000000003
>> [   42.395145] RBP: 0000000000000046 R08: 00007ffff4d34f40 R09: 0000000000000018
>> [   42.396056] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000400aad
>> [   42.396598] R13: 0000000000000066 R14: 00007ffff4d34ee0 R15: 00007fbbb717af00
>> [   42.397257]
>> [   42.397411] Allocated by task 3789:
>> [   42.397702]  save_stack_trace+0x16/0x20
>> [   42.398005]  save_stack+0x46/0xd0
>> [   42.398267]  kasan_kmalloc+0xad/0xe0
>> [   42.398548]  kasan_slab_alloc+0x12/0x20
>> [   42.398848]  __kmalloc_node_track_caller+0xcb/0x380
>> [   42.399224]  __kmalloc_reserve.isra.32+0x41/0xe0
>> [   42.399654]  __alloc_skb+0xf8/0x580
>> [   42.400003]  sock_wmalloc+0xab/0xf0
>> [   42.400346]  __ip6_append_data.isra.41+0x2472/0x33d0
>> [   42.400813]  ip6_append_data+0x1a8/0x2f0
>> [   42.401122]  rawv6_sendmsg+0x11ee/0x2db0
>> [   42.401505]  inet_sendmsg+0x123/0x500
>> [   42.401860]  sock_sendmsg+0xca/0x110
>> [   42.402209]  ___sys_sendmsg+0x7cb/0x930
>> [   42.402582]  __sys_sendmsg+0xd9/0x190
>> [   42.402941]  SyS_sendmsg+0x2d/0x50
>> [   42.403273]  entry_SYSCALL_64_fastpath+0x1f/0xbe
>> [   42.403718]
>> [   42.403871] Freed by task 1794:
>> [   42.404146]  save_stack_trace+0x16/0x20
>> [   42.404515]  save_stack+0x46/0xd0
>> [   42.404827]  kasan_slab_free+0x72/0xc0
>> [   42.405167]  kfree+0xe8/0x2b0
>> [   42.405462]  skb_free_head+0x74/0xb0
>> [   42.405806]  skb_release_data+0x30e/0x3a0
>> [   42.406198]  skb_release_all+0x4a/0x60
>> [   42.406563]  consume_skb+0x113/0x2e0
>> [   42.406910]  skb_free_datagram+0x1a/0xe0
>> [   42.407288]  netlink_recvmsg+0x60d/0xe40
>> [   42.407667]  sock_recvmsg+0xd7/0x110
>> [   42.408022]  ___sys_recvmsg+0x25c/0x580
>> [   42.408395]  __sys_recvmsg+0xd6/0x190
>> [   42.408753]  SyS_recvmsg+0x2d/0x50
>> [   42.409086]  entry_SYSCALL_64_fastpath+0x1f/0xbe
>> [   42.409513]
>> [   42.409665] The buggy address belongs to the object at ffff88000969e780
>> [   42.409665]  which belongs to the cache kmalloc-512 of size 512
>> [   42.410846] The buggy address is located 24 bytes inside of
>> [   42.410846]  512-byte region [ffff88000969e780, ffff88000969e980)
>> [   42.411941] The buggy address belongs to the page:
>> [   42.412405] page:ffffea000025a780 count:1 mapcount:0 mapping:          (null) index:0x0 compound_mapcount: 0
>> [   42.413298] flags: 0x100000000008100(slab|head)
>> [   42.413729] raw: 0100000000008100 0000000000000000 0000000000000000 00000001800c000c
>> [   42.414387] raw: ffffea00002a9500 0000000900000007 ffff88000c401280 0000000000000000
>> [   42.415074] page dumped because: kasan: bad access detected
>> [   42.415604]
>> [   42.415757] Memory state around the buggy address:
>> [   42.416222]  ffff88000969e880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>> [   42.416904]  ffff88000969e900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
>> [   42.417591] >ffff88000969e980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc
>> [   42.418273]                    ^
>> [   42.418588]  ffff88000969ea00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>> [   42.419273]  ffff88000969ea80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>> [   42.419882] ==================================================================
>>
>> Reported-by: Andrey Konovalov <andreyknvl at google.com>
>> Signed-off-by: Craig Gallek <kraig at google.com>
>> Signed-off-by: David S. Miller <davem at davemloft.net>
>>
>> CVE-2017-9074
>>
>> (cherry-picked from 2423496af35d94a87156b063ea5cedffc10a70a1)
>> Signed-off-by: Stefan Bader <stefan.bader at canonical.com>
>> ---
>>  net/ipv6/ip6_offload.c |  2 ++
>>  net/ipv6/ip6_output.c  |  4 ++++
>>  net/ipv6/output_core.c | 14 ++++++++------
>>  net/ipv6/udp_offload.c |  2 ++
>>  4 files changed, 16 insertions(+), 6 deletions(-)
>>
>> diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
>> index 93e58a5..eab36ab 100644
>> --- a/net/ipv6/ip6_offload.c
>> +++ b/net/ipv6/ip6_offload.c
>> @@ -117,6 +117,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
>>
>>                 if (udpfrag) {
>>                         unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
>> +                       if (unfrag_ip6hlen < 0)
>> +                               return ERR_PTR(unfrag_ip6hlen);
>>                         fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen);
>>                         fptr->frag_off = htons(offset);
>>                         if (skb->next)
>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>> index 58f6288..01deecd 100644
>> --- a/net/ipv6/ip6_output.c
>> +++ b/net/ipv6/ip6_output.c
>> @@ -598,6 +598,10 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,
>>         u8 *prevhdr, nexthdr = 0;
>>
>>         hlen = ip6_find_1stfragopt(skb, &prevhdr);
>> +       if (hlen < 0) {
>> +               err = hlen;
>> +               goto fail;
>> +       }
>>         nexthdr = *prevhdr;
>>
>>         mtu = ip6_skb_dst_mtu(skb);
>> diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c
>> index cd42523..e9065b8 100644
>> --- a/net/ipv6/output_core.c
>> +++ b/net/ipv6/output_core.c
>> @@ -79,14 +79,13 @@ EXPORT_SYMBOL(ipv6_select_ident);
>>  int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
>>  {
>>         u16 offset = sizeof(struct ipv6hdr);
>> -       struct ipv6_opt_hdr *exthdr =
>> -                               (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1);
>>         unsigned int packet_len = skb_tail_pointer(skb) -
>>                 skb_network_header(skb);
>>         int found_rhdr = 0;
>>         *nexthdr = &ipv6_hdr(skb)->nexthdr;
>>
>> -       while (offset + 1 <= packet_len) {
>> +       while (offset <= packet_len) {
>> +               struct ipv6_opt_hdr *exthdr;
>>
>>                 switch (**nexthdr) {
>>
>> @@ -107,13 +106,16 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
>>                         return offset;
>>                 }
>>
>> -               offset += ipv6_optlen(exthdr);
>> -               *nexthdr = &exthdr->nexthdr;
>> +               if (offset + sizeof(struct ipv6_opt_hdr) > packet_len)
>> +                       return -EINVAL;
>> +
>>                 exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) +
>>                                                  offset);
>> +               offset += ipv6_optlen(exthdr);
>> +               *nexthdr = &exthdr->nexthdr;
>>         }
>>
>> -       return offset;
>> +       return -EINVAL;
>>  }
>>  EXPORT_SYMBOL(ip6_find_1stfragopt);
>>
>> diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
>> index ac858c4..b348cff 100644
>> --- a/net/ipv6/udp_offload.c
>> +++ b/net/ipv6/udp_offload.c
>> @@ -91,6 +91,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
>>                  * bytes to insert fragment header.
>>                  */
>>                 unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr);
>> +               if (unfrag_ip6hlen < 0)
>> +                       return ERR_PTR(unfrag_ip6hlen);
>>                 nexthdr = *prevhdr;
>>                 *prevhdr = NEXTHDR_FRAGMENT;
>>                 unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) +
>> --
>> 2.7.4
>>
>>
>> --
>> kernel-team mailing list
>> kernel-team at lists.ubuntu.com
>> https://lists.ubuntu.com/mailman/listinfo/kernel-team


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20170608/a6f7dd10/attachment.sig>


More information about the kernel-team mailing list