@@ -113,4 +113,16 @@ typedef struct {
*/
#define VFIO_USER_DEF_MAX_BITMAP (256 * 1024 * 1024)
+/*
+ * VFIO_USER_DEVICE_GET_INFO
+ * imported from struct vfio_device_info
+ */
+typedef struct {
+ VFIOUserHdr hdr;
+ uint32_t argsz;
+ uint32_t flags;
+ uint32_t num_regions;
+ uint32_t num_irqs;
+} VFIOUserDeviceInfo;
+
#endif /* VFIO_USER_PROTOCOL_H */
@@ -90,6 +90,7 @@ void vfio_user_disconnect(VFIOUserProxy *proxy);
void vfio_user_set_handler(VFIODevice *vbasedev,
void (*handler)(void *opaque, VFIOUserMsg *msg),
void *reqarg);
+int vfio_user_get_device(VFIODevice *vbasedev, Error **errp);
int vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp);
#endif /* VFIO_USER_H */
@@ -254,6 +254,9 @@ void vfio_put_group(VFIOGroup *group);
int vfio_get_device(VFIOGroup *group, const char *name,
VFIODevice *vbasedev, Error **errp);
+void vfio_init_device(VFIODevice *vbasedev, VFIOGroup *group,
+ struct vfio_device_info *info);
+
extern const MemoryRegionOps vfio_region_ops;
typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList;
extern VFIOGroupList vfio_group_list;
@@ -2369,6 +2369,20 @@ void vfio_get_all_regions(VFIODevice *vbasedev)
}
}
+void vfio_init_device(VFIODevice *vbasedev, VFIOGroup *group,
+ struct vfio_device_info *info)
+{
+ vbasedev->group = group;
+ QLIST_INSERT_HEAD(&group->device_list, vbasedev, next);
+
+ vbasedev->num_irqs = info->num_irqs;
+ vbasedev->num_regions = info->num_regions;
+ vbasedev->flags = info->flags;
+ vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET);
+
+ vfio_get_all_regions(vbasedev);
+}
+
int vfio_get_device(VFIOGroup *group, const char *name,
VFIODevice *vbasedev, Error **errp)
{
@@ -2414,18 +2428,11 @@ int vfio_get_device(VFIOGroup *group, const char *name,
}
vbasedev->fd = fd;
- vbasedev->group = group;
- QLIST_INSERT_HEAD(&group->device_list, vbasedev, next);
-
- vbasedev->num_irqs = dev_info.num_irqs;
- vbasedev->num_regions = dev_info.num_regions;
- vbasedev->flags = dev_info.flags;
+ vfio_init_device(vbasedev, group, &dev_info);
trace_vfio_get_device(name, dev_info.flags, dev_info.num_regions,
dev_info.num_irqs);
- vfio_get_all_regions(vbasedev);
- vbasedev->reset_works = !!(dev_info.flags & VFIO_DEVICE_FLAGS_RESET);
return 0;
}
@@ -77,6 +77,7 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp)
VFIODevice *vbasedev = &vdev->vbasedev;
SocketAddress addr;
VFIOUserProxy *proxy;
+ int ret;
Error *err = NULL;
/*
@@ -116,6 +117,11 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp)
vbasedev->type = VFIO_DEVICE_TYPE_PCI;
vbasedev->dev = DEVICE(vdev);
+ ret = vfio_user_get_device(vbasedev, errp);
+ if (ret) {
+ goto error;
+ }
+
return;
error:
@@ -32,6 +32,14 @@
#include "user.h"
#include "trace.h"
+
+/*
+ * These are to defend against a malign server trying
+ * to force us to run out of memory.
+ */
+#define VFIO_USER_MAX_REGIONS 100
+#define VFIO_USER_MAX_IRQS 50
+
static int wait_time = 5000; /* wait up to 5 sec for busy servers */
static IOThread *vfio_user_iothread;
@@ -55,6 +63,9 @@ static void vfio_user_send_wait(VFIOUserProxy *proxy, VFIOUserHdr *hdr,
static void vfio_user_request_msg(VFIOUserHdr *hdr, uint16_t cmd,
uint32_t size, uint32_t flags);
+static int vfio_user_get_info(VFIOUserProxy *proxy,
+ struct vfio_device_info *info);
+
static inline void vfio_user_set_error(VFIOUserHdr *hdr, uint32_t err)
{
hdr->flags |= VFIO_USER_ERROR;
@@ -807,6 +818,30 @@ void vfio_user_disconnect(VFIOUserProxy *proxy)
g_free(proxy);
}
+int vfio_user_get_device(VFIODevice *vbasedev, Error **errp)
+{
+ struct vfio_device_info info = { .argsz = sizeof(info) };
+ int ret;
+
+ ret = vfio_user_get_info(vbasedev->proxy, &info);
+ if (ret) {
+ error_setg_errno(errp, -ret, "get info failure");
+ return ret;
+ }
+
+ /* defend against a malicious server */
+ if (info.num_regions > VFIO_USER_MAX_REGIONS ||
+ info.num_irqs > VFIO_USER_MAX_IRQS) {
+ error_printf("vfio_user_get_info: invalid reply\n");
+ return -EINVAL;
+ }
+
+ vbasedev->fd = -1;
+ vfio_init_device(vbasedev, NULL, &info);
+
+ return 0;
+}
+
static void vfio_user_request_msg(VFIOUserHdr *hdr, uint16_t cmd,
uint32_t size, uint32_t flags)
{
@@ -1088,3 +1123,23 @@ int vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp)
trace_vfio_user_version(msgp->major, msgp->minor, msgp->capabilities);
return 0;
}
+
+static int vfio_user_get_info(VFIOUserProxy *proxy,
+ struct vfio_device_info *info)
+{
+ VFIOUserDeviceInfo msg;
+ uint32_t argsz = sizeof(msg) - sizeof(msg.hdr);
+
+ memset(&msg, 0, sizeof(msg));
+ vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_INFO, sizeof(msg), 0);
+ msg.argsz = argsz;
+
+ vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, false);
+ if (msg.hdr.flags & VFIO_USER_ERROR) {
+ return -msg.hdr.error_reply;
+ }
+ trace_vfio_user_get_info(msg.num_regions, msg.num_irqs);
+
+ memcpy(info, &msg.argsz, argsz);
+ return 0;
+}
@@ -173,3 +173,4 @@ vfio_user_recv_read(uint16_t id, int read) " id 0x%x read 0x%x"
vfio_user_recv_request(uint16_t cmd) " command 0x%x"
vfio_user_send_write(uint16_t id, int wrote) " id 0x%x wrote 0x%x"
vfio_user_version(uint16_t major, uint16_t minor, const char *caps) " major %d minor %d caps: %s"
+vfio_user_get_info(uint32_t nregions, uint32_t nirqs) " #regions %d #irqs %d"