RE: [PATCH rc 2/3] iommufd: IOMMUFD_DESTROY should not increase the refcount

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> From: Jason Gunthorpe <jgg@xxxxxxxxxx>
> Sent: Wednesday, July 26, 2023 3:06 AM
> 
> syzkaller found a race where IOMMUFD_DESTROY increments the refcount:
> 
>        obj = iommufd_get_object(ucmd->ictx, cmd->id, IOMMUFD_OBJ_ANY);
>        if (IS_ERR(obj))
>                return PTR_ERR(obj);
>        iommufd_ref_to_users(obj);
>        /* See iommufd_ref_to_users() */
>        if (!iommufd_object_destroy_user(ucmd->ictx, obj))
> 
> As part of the sequence to join the two existing primitives together.
> 
> Allowing the refcount the be elevated without holding the destroy_rwsem
> violates the assumption that all temporary refcoutn elevations are

s/refcoutn/refcount/

> protected by destroy_rwsem. Racing IOMMUFD_DESTROY with
> iommufd_object_destroy_user() will cause spurious failures:
> 
>   WARNING: CPU: 0 PID: 3076 at drivers/iommu/iommufd/device.c:477
> iommufd_access_destroy+0x18/0x20 drivers/iommu/iommufd/device.c:478
>   Modules linked in:
>   CPU: 0 PID: 3076 Comm: syz-executor.0 Not tainted 6.3.0-rc1-syzkaller #0
>   Hardware name: Google Google Compute Engine/Google Compute Engine,
> BIOS Google 07/03/2023
>   RIP: 0010:iommufd_access_destroy+0x18/0x20
> drivers/iommu/iommufd/device.c:477
>   Code: e8 3d 4e 00 00 84 c0 74 01 c3 0f 0b c3 0f 1f 44 00 00 f3 0f 1e fa 48 89
> fe 48 8b bf a8 00 00 00 e8 1d 4e 00 00 84 c0 74 01 c3 <0f> 0b c3 0f 1f 44 00 00
> 41 57 41 56 41 55 4c 8d ae d0 00 00 00 41
>   RSP: 0018:ffffc90003067e08 EFLAGS: 00010246
>   RAX: 0000000000000000 RBX: ffff888109ea0300 RCX: 0000000000000000
>   RDX: 0000000000000001 RSI: 0000000000000000 RDI: 00000000ffffffff
>   RBP: 0000000000000004 R08: 0000000000000000 R09: ffff88810bbb3500
>   R10: ffff88810bbb3e48 R11: 0000000000000000 R12: ffffc90003067e88
>   R13: ffffc90003067ea8 R14: ffff888101249800 R15: 00000000fffffffe
>   FS:  00007ff7254fe6c0(0000) GS:ffff888237c00000(0000)
> knlGS:0000000000000000
>   CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>   CR2: 0000555557262da8 CR3: 000000010a6fd000 CR4: 0000000000350ef0
>   Call Trace:
>    <TASK>
>    iommufd_test_create_access drivers/iommu/iommufd/selftest.c:596
> [inline]
>    iommufd_test+0x71c/0xcf0 drivers/iommu/iommufd/selftest.c:813
>    iommufd_fops_ioctl+0x10f/0x1b0 drivers/iommu/iommufd/main.c:337
>    vfs_ioctl fs/ioctl.c:51 [inline]
>    __do_sys_ioctl fs/ioctl.c:870 [inline]
>    __se_sys_ioctl fs/ioctl.c:856 [inline]
>    __x64_sys_ioctl+0x84/0xc0 fs/ioctl.c:856
>    do_syscall_x64 arch/x86/entry/common.c:50 [inline]
>    do_syscall_64+0x38/0x80 arch/x86/entry/common.c:80
>    entry_SYSCALL_64_after_hwframe+0x63/0xcd
> 
> The solution is to not increment the refcount on the IOMMUFD_DESTROY
> path
> at all. Instead use the xa_lock to serialize everything. The refcount
> check == 1 and xa_erase can be done under a single critical region. This
> avoids the need for any refcount incrementing.
> 
> It has the downside that if userspace races destroy with other operations
> it will get an EBUSY instead of waiting, but this is kind of racing is
> already dangerous.

it's not a new downside. Even old code also returns -EBUSY if
iommufd_object_destroy_user() returns false.

> +
>  /*
>   * The caller holds a users refcount and wants to destroy the object. Returns

s/users/user's/

> +
> +	/*
> +	 * If there is a bug and we couldn't destroy the object then we did put
> +	 * back the callers refcount and will eventually try to free it again

s/callers/caller's/

Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>

btw,

> -	iommufd_ref_to_users(obj);
> -	/* See iommufd_ref_to_users() */
> -	if (!iommufd_object_destroy_user(ucmd->ictx, obj))
> -		return -EBUSY;

I wonder whether there is any other reason to keep iommufd_ref_to_users().
Now the only invocation is in iommufd_access_attach(), but it could be
simply replaced by "get_object(); refcount_inc(); put_object()" as all other
places are doing.




[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux