• Jason Gunthorpe's avatar
    iommufd: Do not UAF during iommufd_put_object() · 6f9c4d8c
    Jason Gunthorpe authored
    The mixture of kernel and user space lifecycle objects continues to be
    complicated inside iommufd. The obj->destroy_rwsem is used to bring order
    to the kernel driver destruction sequence but it cannot be sequenced right
    with the other refcounts so we end up possibly UAF'ing:
    
      BUG: KASAN: slab-use-after-free in __up_read+0x627/0x750 kernel/locking/rwsem.c:1342
      Read of size 8 at addr ffff888073cde868 by task syz-executor934/6535
    
      CPU: 1 PID: 6535 Comm: syz-executor934 Not tainted 6.6.0-rc7-syzkaller-00195-g2af9b20d #0
      Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/09/2023
      Call Trace:
       <TASK>
       __dump_stack lib/dump_stack.c:88 [inline]
       dump_stack_lvl+0xd9/0x1b0 lib/dump_stack.c:106
       print_address_description mm/kasan/report.c:364 [inline]
       print_report+0xc4/0x620 mm/kasan/report.c:475
       kasan_report+0xda/0x110 mm/kasan/report.c:588
       __up_read+0x627/0x750 kernel/locking/rwsem.c:1342
       iommufd_put_object drivers/iommu/iommufd/iommufd_private.h:149 [inline]
       iommufd_vfio_ioas+0x46c/0x580 drivers/iommu/iommufd/vfio_compat.c:146
       iommufd_fops_ioctl+0x347/0x4d0 drivers/iommu/iommufd/main.c:398
       vfs_ioctl fs/ioctl.c:51 [inline]
       __do_sys_ioctl fs/ioctl.c:871 [inline]
       __se_sys_ioctl fs/ioctl.c:857 [inline]
       __x64_sys_ioctl+0x18f/0x210 fs/ioctl.c:857
       do_syscall_x64 arch/x86/entry/common.c:50 [inline]
       do_syscall_64+0x38/0xb0 arch/x86/entry/common.c:80
       entry_SYSCALL_64_after_hwframe+0x63/0xcd
    
    There are two races here, the more obvious one:
    
         CPU 0                                 CPU 1
     iommufd_put_object()
                                              iommufd_destroy()
      refcount_dec(&obj->users)
    
     	                                   iommufd_object_remove()
    					   kfree()
      up_read(&obj->destroy_rwsem) // Boom
    
    And there is also perhaps some possibility that the rwsem could hit an
    issue:
    
         CPU 0                                 CPU 1
     iommufd_put_object()
                                             iommufd_object_destroy_user()
      refcount_dec(&obj->users);
     	                                  down_write(&obj->destroy_rwsem)
      up_read(&obj->destroy_rwsem);
                                                 atomic_long_or(RWSEM_FLAG_WAITERS, &sem->count);
          tmp = atomic_long_add_return_release()
                                                 rwsem_try_write_lock()
     	                                  iommufd_object_remove()
    	                                  up_write(&obj->destroy_rwsem)
    					  kfree()
          clear_nonspinnable() // Boom
    
    Fix this by reorganizing this again so that two refcounts are used to keep
    track of things with a rule that users == 0 && shortterm_users == 0 means
    no other threads have that memory. Put a wait_queue in the iommufd_ctx
    object that is triggered when any sub object reaches a 0
    shortterm_users. This allows the same wait for userspace ioctls to finish
    behavior that the rwsem was providing.
    
    This is weaker still than the prior versions:
    
     - There is no bias on shortterm_users so if some thread is waiting to
       destroy other threads can continue to get new read sides
    
     - If destruction fails, eg because of an active in-kernel user, then
       shortterm_users will have cycled to zero momentarily blocking new users
    
     - If userspace races destroy with other userspace operations they
       continue to get an EBUSY since we still can't intermix looking up an ID
       and sleeping for its unref
    
    In all cases these are things that userspace brings on itself, correct
    programs will not hit them.
    
    Fixes: 99f98a7c ("iommufd: IOMMUFD_DESTROY should not increase the refcount")
    Link: https://lore.kernel.org/all/2-v2-ca9e00171c5b+123-iommufd_syz4_jgg@nvidia.com/
    Reported-by: syzbot+d31adfb277377ef8fcba@syzkaller.appspotmail.com
    Closes: https://lore.kernel.org/r/00000000000055ef9a0609336580@google.comReviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
    Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
    6f9c4d8c
main.c 15.4 KB