Skip to content

Commit 82d93f5

Browse files
yiliu1765awilliam
authored andcommitted
vfio: Block device access via device fd until device is opened
Allow the vfio_device file to be in a state where the device FD is opened but the device cannot be used by userspace (i.e. its .open_device() hasn't been called). This inbetween state is not used when the device FD is spawned from the group FD, however when we create the device FD directly by opening a cdev it will be opened in the blocked state. The reason for the inbetween state is that userspace only gets a FD but doesn't gain access permission until binding the FD to an iommufd. So in the blocked state, only the bind operation is allowed. Completing bind will allow user to further access the device. This is implemented by adding a flag in struct vfio_device_file to mark the blocked state and using a simple smp_load_acquire() to obtain the flag value and serialize all the device setup with the thread accessing this device. Following this lockless scheme, it can safely handle the device FD unbound->bound but it cannot handle bound->unbound. To allow this we'd need to add a lock on all the vfio ioctls which seems costly. So once device FD is bound, it remains bound until the FD is closed. Suggested-by: Jason Gunthorpe <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Reviewed-by: Eric Auger <[email protected]> Tested-by: Terrence Xu <[email protected]> Tested-by: Nicolin Chen <[email protected]> Tested-by: Matthew Rosato <[email protected]> Tested-by: Yanting Jiang <[email protected]> Tested-by: Shameer Kolothum <[email protected]> Tested-by: Zhenzhong Duan <[email protected]> Signed-off-by: Yi Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent 05f37e1 commit 82d93f5

File tree

3 files changed

+27
-1
lines changed

3 files changed

+27
-1
lines changed

drivers/vfio/group.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,18 @@ static int vfio_df_group_open(struct vfio_device_file *df)
194194
df->iommufd = device->group->iommufd;
195195

196196
ret = vfio_df_open(df);
197-
if (ret)
197+
if (ret) {
198198
df->iommufd = NULL;
199+
goto out_put_kvm;
200+
}
201+
202+
/*
203+
* Paired with smp_load_acquire() in vfio_device_fops::ioctl/
204+
* read/write/mmap and vfio_file_has_device_access()
205+
*/
206+
smp_store_release(&df->access_granted, true);
199207

208+
out_put_kvm:
200209
if (device->open_count == 0)
201210
vfio_device_put_kvm(device);
202211

drivers/vfio/vfio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct vfio_container;
1919
struct vfio_device_file {
2020
struct vfio_device *device;
2121

22+
u8 access_granted;
2223
spinlock_t kvm_ref_lock; /* protect kvm field */
2324
struct kvm *kvm;
2425
struct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */

drivers/vfio/vfio_main.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,10 @@ static long vfio_device_fops_unl_ioctl(struct file *filep,
11291129
struct vfio_device *device = df->device;
11301130
int ret;
11311131

1132+
/* Paired with smp_store_release() following vfio_df_open() */
1133+
if (!smp_load_acquire(&df->access_granted))
1134+
return -EINVAL;
1135+
11321136
ret = vfio_device_pm_runtime_get(device);
11331137
if (ret)
11341138
return ret;
@@ -1156,6 +1160,10 @@ static ssize_t vfio_device_fops_read(struct file *filep, char __user *buf,
11561160
struct vfio_device_file *df = filep->private_data;
11571161
struct vfio_device *device = df->device;
11581162

1163+
/* Paired with smp_store_release() following vfio_df_open() */
1164+
if (!smp_load_acquire(&df->access_granted))
1165+
return -EINVAL;
1166+
11591167
if (unlikely(!device->ops->read))
11601168
return -EINVAL;
11611169

@@ -1169,6 +1177,10 @@ static ssize_t vfio_device_fops_write(struct file *filep,
11691177
struct vfio_device_file *df = filep->private_data;
11701178
struct vfio_device *device = df->device;
11711179

1180+
/* Paired with smp_store_release() following vfio_df_open() */
1181+
if (!smp_load_acquire(&df->access_granted))
1182+
return -EINVAL;
1183+
11721184
if (unlikely(!device->ops->write))
11731185
return -EINVAL;
11741186

@@ -1180,6 +1192,10 @@ static int vfio_device_fops_mmap(struct file *filep, struct vm_area_struct *vma)
11801192
struct vfio_device_file *df = filep->private_data;
11811193
struct vfio_device *device = df->device;
11821194

1195+
/* Paired with smp_store_release() following vfio_df_open() */
1196+
if (!smp_load_acquire(&df->access_granted))
1197+
return -EINVAL;
1198+
11831199
if (unlikely(!device->ops->mmap))
11841200
return -EINVAL;
11851201

0 commit comments

Comments
 (0)