VFIO group has historically allowed multi-open of the device FD. This
was made secure because the "open" was executed via an ioctl to the
group FD which is itself only single open.

However, no known use of multiple device FDs today. It is kind of a
strange thing to do because new device FDs can naturally be created
via dup().

When we implement the new device uAPI (only used in cdev path) there is
no natural way to allow the device itself from being multi-opened in a
secure manner. Without the group FD we cannot prove the security context
of the opener.

Thus, when moving to the new uAPI we block the ability of opening
a device multiple times. Given old group path still allows it we store
a vfio_group pointer in struct vfio_device_file to differentiate.

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: Yanting Jiang <[email protected]>
Tested-by: Shameer Kolothum <[email protected]>
Signed-off-by: Yi Liu <[email protected]>
---
 drivers/vfio/group.c     | 2 ++
 drivers/vfio/vfio.h      | 2 ++
 drivers/vfio/vfio_main.c | 7 +++++++
 3 files changed, 11 insertions(+)

diff --git a/drivers/vfio/group.c b/drivers/vfio/group.c
index fd4ddafb6152..a17584e8be15 100644
--- a/drivers/vfio/group.c
+++ b/drivers/vfio/group.c
@@ -245,6 +245,8 @@ static struct file *vfio_device_open_file(struct 
vfio_device *device)
                goto err_out;
        }
 
+       df->group = device->group;
+
        ret = vfio_device_group_open(df);
        if (ret)
                goto err_free;
diff --git a/drivers/vfio/vfio.h b/drivers/vfio/vfio.h
index 3c82d1cc4520..785afc40ece8 100644
--- a/drivers/vfio/vfio.h
+++ b/drivers/vfio/vfio.h
@@ -18,6 +18,8 @@ struct vfio_container;
 
 struct vfio_device_file {
        struct vfio_device *device;
+       struct vfio_group *group;
+
        bool access_granted;
        spinlock_t kvm_ref_lock; /* protect kvm field */
        struct kvm *kvm;
diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c
index 224425cb7259..513f9516aed2 100644
--- a/drivers/vfio/vfio_main.c
+++ b/drivers/vfio/vfio_main.c
@@ -492,6 +492,13 @@ int vfio_device_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_device_first_open(df);
-- 
2.34.1

Reply via email to