mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
vfio: Reject a second cdev open before mutating shared device state
The cdev single-open check lives in vfio_df_open(), which runs at the end of the bind ioctl, after vfio_df_ioctl_bind_iommufd() has already updated state shared across all opens: vfio_df_check_token() can set the PF vf_token and vfio_df_get_kvm_safe() records the caller's KVM pointer in device->kvm and takes a reference. A second cdev bind of an already-open device runs both, only to be rejected in vfio_df_open(). The error path clears device->kvm and drops the reference, tearing down the current opener's KVM association and potentially resulting in an unbalanced reference on close or premature release, while the vf_token remains clobbered. Move the single-open check into vfio_df_ioctl_bind_iommufd() ahead of both mutations, so a bind that cannot complete leaves the current opener's state untouched. df->group is NULL on this path, so a non-zero open_count is exactly what vfio_df_open() rejected. The test in vfio_df_open() becomes redundant and is removed. Return -EBUSY rather than -EINVAL here. The arguments are not invalid, the device is in use, which could be a transient condition due to a delayed fput if the prior user is terminated. This provides compatibility with the group path, where a group open returns -EBUSY, and users may choose bounded polling to detect such a transient condition. Fixes:839e692fa4("vfio: Make vfio_df_open() single open for device cdev path") Fixes:5fcc26969a("vfio: Add VFIO_DEVICE_BIND_IOMMUFD") Fixes:86624ba3b5("vfio/pci: Do vf_token checks for VFIO_DEVICE_BIND_IOMMUFD") Assisted-by: LLM Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Alex Williamson <alex.williamson@nvidia.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Link: https://lore.kernel.org/r/20260911170429.1642480-2-alex.williamson@nvidia.com Signed-off-by: Alex Williamson <alex@shazbot.org>
This commit is contained in:
parent
b1d0f0d97a
commit
258ba46543
|
|
@ -130,6 +130,18 @@ long vfio_df_ioctl_bind_iommufd(struct vfio_device_file *df,
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* The cdev path allows only a single open. Reject a second open here,
|
||||
* before the VF token and device->kvm updates below would clobber the
|
||||
* current opener's state on a bind that cannot complete. Return -EBUSY
|
||||
* rather than -EINVAL since a delayed release of the prior opener can
|
||||
* make this transient.
|
||||
*/
|
||||
if (device->open_count) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
ret = vfio_df_check_token(device, &bind);
|
||||
if (ret)
|
||||
goto out_unlock;
|
||||
|
|
|
|||
|
|
@ -603,13 +603,6 @@ int vfio_df_open(struct vfio_device_file *df)
|
|||
|
||||
lockdep_assert_held(&device->dev_set->lock);
|
||||
|
||||
/*
|
||||
* Only the group path allows the device to be opened multiple
|
||||
* times. The device cdev path doesn't have a secure way for it.
|
||||
*/
|
||||
if (device->open_count != 0 && !df->group)
|
||||
return -EINVAL;
|
||||
|
||||
device->open_count++;
|
||||
if (device->open_count == 1) {
|
||||
ret = vfio_df_device_first_open(df);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user