• Dmitry Vyukov's avatar
    kasan: fix races in quarantine_remove_cache() · ce5bec54
    Dmitry Vyukov authored
    quarantine_remove_cache() frees all pending objects that belong to the
    cache, before we destroy the cache itself.  However there are currently
    two possibilities how it can fail to do so.
    
    First, another thread can hold some of the objects from the cache in
    temp list in quarantine_put().  quarantine_put() has a windows of
    enabled interrupts, and on_each_cpu() in quarantine_remove_cache() can
    finish right in that window.  These objects will be later freed into the
    destroyed cache.
    
    Then, quarantine_reduce() has the same problem.  It grabs a batch of
    objects from the global quarantine, then unlocks quarantine_lock and
    then frees the batch.  quarantine_remove_cache() can finish while some
    objects from the cache are still in the local to_free list in
    quarantine_reduce().
    
    Fix the race with quarantine_put() by disabling interrupts for the whole
    duration of quarantine_put().  In combination with on_each_cpu() in
    quarantine_remove_cache() it ensures that quarantine_remove_cache()
    either sees the objects in the per-cpu list or in the global list.
    
    Fix the race with quarantine_reduce() by protecting quarantine_reduce()
    with srcu critical section and then doing synchronize_srcu() at the end
    of quarantine_remove_cache().
    
    I've done some assessment of how good synchronize_srcu() works in this
    case.  And on a 4 CPU VM I see that it blocks waiting for pending read
    critical sections in about 2-3% of cases.  Which looks good to me.
    
    I suspect that these races are the root cause of some GPFs that I
    episodically hit.  Previously I did not have any explanation for them.
    
      BUG: unable to handle kernel NULL pointer dereference at 00000000000000c8
      IP: qlist_free_all+0x2e/0xc0 mm/kasan/quarantine.c:155
      PGD 6aeea067
      PUD 60ed7067
      PMD 0
      Oops: 0000 [#1] SMP KASAN
      Dumping ftrace buffer:
         (ftrace buffer empty)
      Modules linked in:
      CPU: 0 PID: 13667 Comm: syz-executor2 Not tainted 4.10.0+ #60
      Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
      task: ffff88005f948040 task.stack: ffff880069818000
      RIP: 0010:qlist_free_all+0x2e/0xc0 mm/kasan/quarantine.c:155
      RSP: 0018:ffff88006981f298 EFLAGS: 00010246
      RAX: ffffea0000ffff00 RBX: 0000000000000000 RCX: ffffea0000ffff1f
      RDX: 0000000000000000 RSI: ffff88003fffc3e0 RDI: 0000000000000000
      RBP: ffff88006981f2c0 R08: ffff88002fed7bd8 R09: 00000001001f000d
      R10: 00000000001f000d R11: ffff88006981f000 R12: ffff88003fffc3e0
      R13: ffff88006981f2d0 R14: ffffffff81877fae R15: 0000000080000000
      FS:  00007fb911a2d700(0000) GS:ffff88003ec00000(0000) knlGS:0000000000000000
      CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
      CR2: 00000000000000c8 CR3: 0000000060ed6000 CR4: 00000000000006f0
      Call Trace:
       quarantine_reduce+0x10e/0x120 mm/kasan/quarantine.c:239
       kasan_kmalloc+0xca/0xe0 mm/kasan/kasan.c:590
       kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:544
       slab_post_alloc_hook mm/slab.h:456 [inline]
       slab_alloc_node mm/slub.c:2718 [inline]
       kmem_cache_alloc_node+0x1d3/0x280 mm/slub.c:2754
       __alloc_skb+0x10f/0x770 net/core/skbuff.c:219
       alloc_skb include/linux/skbuff.h:932 [inline]
       _sctp_make_chunk+0x3b/0x260 net/sctp/sm_make_chunk.c:1388
       sctp_make_data net/sctp/sm_make_chunk.c:1420 [inline]
       sctp_make_datafrag_empty+0x208/0x360 net/sctp/sm_make_chunk.c:746
       sctp_datamsg_from_user+0x7e8/0x11d0 net/sctp/chunk.c:266
       sctp_sendmsg+0x2611/0x3970 net/sctp/socket.c:1962
       inet_sendmsg+0x164/0x5b0 net/ipv4/af_inet.c:761
       sock_sendmsg_nosec net/socket.c:633 [inline]
       sock_sendmsg+0xca/0x110 net/socket.c:643
       SYSC_sendto+0x660/0x810 net/socket.c:1685
       SyS_sendto+0x40/0x50 net/socket.c:1653
    
    I am not sure about backporting.  The bug is quite hard to trigger, I've
    seen it few times during our massive continuous testing (however, it
    could be cause of some other episodic stray crashes as it leads to
    memory corruption...).  If it is triggered, the consequences are very
    bad -- almost definite bad memory corruption.  The fix is non trivial
    and has chances of introducing new bugs.  I am also not sure how
    actively people use KASAN on older releases.
    
    [dvyukov@google.com: - sorted includes[
      Link: http://lkml.kernel.org/r/20170309094028.51088-1-dvyukov@google.com
    Link: http://lkml.kernel.org/r/20170308151532.5070-1-dvyukov@google.comSigned-off-by: 's avatarDmitry Vyukov <dvyukov@google.com>
    Acked-by: 's avatarAndrey Ryabinin <aryabinin@virtuozzo.com>
    Cc: Greg Thelen <gthelen@google.com>
    Signed-off-by: 's avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: 's avatarLinus Torvalds <torvalds@linux-foundation.org>
    ce5bec54