Signed-off-by: Elena Ufimtseva <elena.ufimts...@oracle.com> Signed-off-by: John G Johnson <john.g.john...@oracle.com> Signed-off-by: Jagannathan Raman <jag.ra...@oracle.com> --- hw/vfio/user-protocol.h | 14 +++++++++++++ hw/vfio/user.h | 2 ++ hw/vfio/pci.c | 26 ++++++++++++++++++++++++ hw/vfio/user.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+)
diff --git a/hw/vfio/user-protocol.h b/hw/vfio/user-protocol.h index a0889f6..4ad8f45 100644 --- a/hw/vfio/user-protocol.h +++ b/hw/vfio/user-protocol.h @@ -92,4 +92,18 @@ typedef struct { #define VFIO_USER_DEF_MAX_XFER (1024 * 1024) #define VFIO_USER_MAX_MAX_XFER (64 * 1024 * 1024) + +/* + * VFIO_USER_DEVICE_GET_INFO + * imported from struct_device_info + */ +typedef struct { + VFIOUserHdr hdr; + uint32_t argsz; + uint32_t flags; + uint32_t num_regions; + uint32_t num_irqs; + uint32_t cap_offset; +} VFIOUserDeviceInfo; + #endif /* VFIO_USER_PROTOCOL_H */ diff --git a/hw/vfio/user.h b/hw/vfio/user.h index 00d21bf..633b3ea 100644 --- a/hw/vfio/user.h +++ b/hw/vfio/user.h @@ -85,4 +85,6 @@ void vfio_user_set_handler(VFIODevice *vbasedev, void *reqarg); int vfio_user_validate_version(VFIODevice *vbasedev, Error **errp); +extern VFIODevIO vfio_dev_io_sock; + #endif /* VFIO_USER_H */ diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 7e5b910..68d6f0c 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3416,6 +3416,8 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp) VFIODevice *vbasedev = &vdev->vbasedev; SocketAddress addr; VFIOProxy *proxy; + struct vfio_device_info info; + int ret; Error *err = NULL; /* @@ -3455,6 +3457,30 @@ static void vfio_user_pci_realize(PCIDevice *pdev, Error **errp) vbasedev->fd = -1; vbasedev->type = VFIO_DEVICE_TYPE_PCI; vbasedev->ops = &vfio_user_pci_ops; + vbasedev->io_ops = &vfio_dev_io_sock; + + ret = VDEV_GET_INFO(vbasedev, &info); + if (ret) { + error_setg_errno(errp, -ret, "get info failure"); + goto error; + } + /* must be PCI */ + if ((info.flags & VFIO_DEVICE_FLAGS_PCI) == 0) { + error_setg(errp, "remote device not PCI"); + goto error; + } + + 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); + vfio_populate_device(vdev, &err); + if (err) { + error_propagate(errp, err); + goto error; + } return; diff --git a/hw/vfio/user.c b/hw/vfio/user.c index dc3f1a6..51e23dd 100644 --- a/hw/vfio/user.c +++ b/hw/vfio/user.c @@ -30,6 +30,13 @@ #include "qapi/qmp/qnum.h" #include "user.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 uint64_t max_xfer_size = VFIO_USER_DEF_MAX_XFER; static uint64_t max_send_fds = VFIO_USER_DEF_MAX_FDS; static int wait_time = 1000; /* wait 1 sec for replies */ @@ -984,3 +991,50 @@ int vfio_user_validate_version(VFIODevice *vbasedev, Error **errp) return 0; } + +static int vfio_user_get_info(VFIOProxy *proxy, struct vfio_device_info *info) +{ + VFIOUserDeviceInfo msg; + + memset(&msg, 0, sizeof(msg)); + vfio_user_request_msg(&msg.hdr, VFIO_USER_DEVICE_GET_INFO, sizeof(msg), 0); + msg.argsz = sizeof(struct vfio_device_info); + + vfio_user_send_wait(proxy, &msg.hdr, NULL, 0, false); + if (msg.hdr.flags & VFIO_USER_ERROR) { + return -msg.hdr.error_reply; + } + + memcpy(info, &msg.argsz, sizeof(*info)); + return 0; +} + + +/* + * Socket-based io_ops + */ + +static int vfio_user_io_get_info(VFIODevice *vbasedev, + struct vfio_device_info *info) +{ + int ret; + + ret = vfio_user_get_info(vbasedev->proxy, info); + if (ret) { + 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; + } + + return 0; +} + +VFIODevIO vfio_dev_io_sock = { + .get_info = vfio_user_io_get_info, +}; + -- 1.8.3.1