Skip to content

Commit 6a985ae

Browse files
jgunthorpeawilliam
authored andcommitted
vfio/pci: Use the struct file as the handle not the vfio_group
VFIO PCI does a security check as part of hot reset to prove that the user has permission to manipulate all the devices that will be impacted by the reset. Use a new API vfio_file_has_dev() to perform this security check against the struct file directly and remove the vfio_group from VFIO PCI. Since VFIO PCI was the last user of vfio_group_get_external_user() and vfio_group_put_external_user() remove it as well. Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alex Williamson <[email protected]>
1 parent 3e5449d commit 6a985ae

File tree

3 files changed

+40
-75
lines changed

3 files changed

+40
-75
lines changed

drivers/vfio/pci/vfio_pci_core.c

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ static int vfio_pci_fill_devs(struct pci_dev *pdev, void *data)
556556

557557
struct vfio_pci_group_info {
558558
int count;
559-
struct vfio_group **groups;
559+
struct file **files;
560560
};
561561

562562
static bool vfio_pci_dev_below_slot(struct pci_dev *pdev, struct pci_slot *slot)
@@ -1018,10 +1018,10 @@ long vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd,
10181018
} else if (cmd == VFIO_DEVICE_PCI_HOT_RESET) {
10191019
struct vfio_pci_hot_reset hdr;
10201020
int32_t *group_fds;
1021-
struct vfio_group **groups;
1021+
struct file **files;
10221022
struct vfio_pci_group_info info;
10231023
bool slot = false;
1024-
int group_idx, count = 0, ret = 0;
1024+
int file_idx, count = 0, ret = 0;
10251025

10261026
minsz = offsetofend(struct vfio_pci_hot_reset, count);
10271027

@@ -1054,17 +1054,17 @@ long vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd,
10541054
return -EINVAL;
10551055

10561056
group_fds = kcalloc(hdr.count, sizeof(*group_fds), GFP_KERNEL);
1057-
groups = kcalloc(hdr.count, sizeof(*groups), GFP_KERNEL);
1058-
if (!group_fds || !groups) {
1057+
files = kcalloc(hdr.count, sizeof(*files), GFP_KERNEL);
1058+
if (!group_fds || !files) {
10591059
kfree(group_fds);
1060-
kfree(groups);
1060+
kfree(files);
10611061
return -ENOMEM;
10621062
}
10631063

10641064
if (copy_from_user(group_fds, (void __user *)(arg + minsz),
10651065
hdr.count * sizeof(*group_fds))) {
10661066
kfree(group_fds);
1067-
kfree(groups);
1067+
kfree(files);
10681068
return -EFAULT;
10691069
}
10701070

@@ -1073,22 +1073,22 @@ long vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd,
10731073
* user interface and store the group and iommu ID. This
10741074
* ensures the group is held across the reset.
10751075
*/
1076-
for (group_idx = 0; group_idx < hdr.count; group_idx++) {
1077-
struct vfio_group *group;
1078-
struct fd f = fdget(group_fds[group_idx]);
1079-
if (!f.file) {
1076+
for (file_idx = 0; file_idx < hdr.count; file_idx++) {
1077+
struct file *file = fget(group_fds[file_idx]);
1078+
1079+
if (!file) {
10801080
ret = -EBADF;
10811081
break;
10821082
}
10831083

1084-
group = vfio_group_get_external_user(f.file);
1085-
fdput(f);
1086-
if (IS_ERR(group)) {
1087-
ret = PTR_ERR(group);
1084+
/* Ensure the FD is a vfio group FD.*/
1085+
if (!vfio_file_iommu_group(file)) {
1086+
fput(file);
1087+
ret = -EINVAL;
10881088
break;
10891089
}
10901090

1091-
groups[group_idx] = group;
1091+
files[file_idx] = file;
10921092
}
10931093

10941094
kfree(group_fds);
@@ -1098,15 +1098,15 @@ long vfio_pci_core_ioctl(struct vfio_device *core_vdev, unsigned int cmd,
10981098
goto hot_reset_release;
10991099

11001100
info.count = hdr.count;
1101-
info.groups = groups;
1101+
info.files = files;
11021102

11031103
ret = vfio_pci_dev_set_hot_reset(vdev->vdev.dev_set, &info);
11041104

11051105
hot_reset_release:
1106-
for (group_idx--; group_idx >= 0; group_idx--)
1107-
vfio_group_put_external_user(groups[group_idx]);
1106+
for (file_idx--; file_idx >= 0; file_idx--)
1107+
fput(files[file_idx]);
11081108

1109-
kfree(groups);
1109+
kfree(files);
11101110
return ret;
11111111
} else if (cmd == VFIO_DEVICE_IOEVENTFD) {
11121112
struct vfio_device_ioeventfd ioeventfd;
@@ -1972,7 +1972,7 @@ static bool vfio_dev_in_groups(struct vfio_pci_core_device *vdev,
19721972
unsigned int i;
19731973

19741974
for (i = 0; i < groups->count; i++)
1975-
if (groups->groups[i] == vdev->vdev.group)
1975+
if (vfio_file_has_dev(groups->files[i], &vdev->vdev))
19761976
return true;
19771977
return false;
19781978
}

drivers/vfio/vfio.c

Lines changed: 18 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,58 +1633,6 @@ static const struct file_operations vfio_device_fops = {
16331633
.mmap = vfio_device_fops_mmap,
16341634
};
16351635

1636-
/*
1637-
* External user API, exported by symbols to be linked dynamically.
1638-
*
1639-
* The protocol includes:
1640-
* 1. do normal VFIO init operation:
1641-
* - opening a new container;
1642-
* - attaching group(s) to it;
1643-
* - setting an IOMMU driver for a container.
1644-
* When IOMMU is set for a container, all groups in it are
1645-
* considered ready to use by an external user.
1646-
*
1647-
* 2. User space passes a group fd to an external user.
1648-
* The external user calls vfio_group_get_external_user()
1649-
* to verify that:
1650-
* - the group is initialized;
1651-
* - IOMMU is set for it.
1652-
* If both checks passed, vfio_group_get_external_user()
1653-
* increments the container user counter to prevent
1654-
* the VFIO group from disposal before KVM exits.
1655-
*
1656-
* 3. When the external KVM finishes, it calls
1657-
* vfio_group_put_external_user() to release the VFIO group.
1658-
* This call decrements the container user counter.
1659-
*/
1660-
struct vfio_group *vfio_group_get_external_user(struct file *filep)
1661-
{
1662-
struct vfio_group *group = filep->private_data;
1663-
int ret;
1664-
1665-
if (filep->f_op != &vfio_group_fops)
1666-
return ERR_PTR(-EINVAL);
1667-
1668-
ret = vfio_group_add_container_user(group);
1669-
if (ret)
1670-
return ERR_PTR(ret);
1671-
1672-
/*
1673-
* Since the caller holds the fget on the file group->users must be >= 1
1674-
*/
1675-
vfio_group_get(group);
1676-
1677-
return group;
1678-
}
1679-
EXPORT_SYMBOL_GPL(vfio_group_get_external_user);
1680-
1681-
void vfio_group_put_external_user(struct vfio_group *group)
1682-
{
1683-
vfio_group_try_dissolve_container(group);
1684-
vfio_group_put(group);
1685-
}
1686-
EXPORT_SYMBOL_GPL(vfio_group_put_external_user);
1687-
16881636
/**
16891637
* vfio_file_iommu_group - Return the struct iommu_group for the vfio group file
16901638
* @file: VFIO group file
@@ -1752,6 +1700,24 @@ void vfio_file_set_kvm(struct file *file, struct kvm *kvm)
17521700
}
17531701
EXPORT_SYMBOL_GPL(vfio_file_set_kvm);
17541702

1703+
/**
1704+
* vfio_file_has_dev - True if the VFIO file is a handle for device
1705+
* @file: VFIO file to check
1706+
* @device: Device that must be part of the file
1707+
*
1708+
* Returns true if given file has permission to manipulate the given device.
1709+
*/
1710+
bool vfio_file_has_dev(struct file *file, struct vfio_device *device)
1711+
{
1712+
struct vfio_group *group = file->private_data;
1713+
1714+
if (file->f_op != &vfio_group_fops)
1715+
return false;
1716+
1717+
return group == device->group;
1718+
}
1719+
EXPORT_SYMBOL_GPL(vfio_file_has_dev);
1720+
17551721
/*
17561722
* Sub-module support
17571723
*/

include/linux/vfio.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,10 @@ int vfio_mig_get_next_state(struct vfio_device *device,
138138
/*
139139
* External user API
140140
*/
141-
extern struct vfio_group *vfio_group_get_external_user(struct file *filep);
142-
extern void vfio_group_put_external_user(struct vfio_group *group);
143141
extern struct iommu_group *vfio_file_iommu_group(struct file *file);
144142
extern bool vfio_file_enforced_coherent(struct file *file);
145143
extern void vfio_file_set_kvm(struct file *file, struct kvm *kvm);
144+
extern bool vfio_file_has_dev(struct file *file, struct vfio_device *device);
146145

147146
#define VFIO_PIN_PAGES_MAX_ENTRIES (PAGE_SIZE/sizeof(unsigned long))
148147

0 commit comments

Comments
 (0)