From a48aaf882b100b30111b5c7c75e1d9e83fe76cfd Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Mon, 27 Jul 2020 17:38:07 +0300 Subject: virtio-pci: fix wrong index in virtio_pci_queue_enabled We should use the index passed by the caller instead of the queue_sel when checking the enablement of a specific virtqueue. This is reported in https://bugzilla.redhat.com/show_bug.cgi?id=1702608 Fixes: f19bcdfedd53 ("virtio-pci: implement queue_enabled method") Signed-off-by: Yuri Benditovich Signed-off-by: Jason Wang --- hw/virtio/virtio-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 4ad3ad8..ccdf54e 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1113,7 +1113,7 @@ static bool virtio_pci_queue_enabled(DeviceState *d, int n) VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { - return proxy->vqs[vdev->queue_sel].enabled; + return proxy->vqs[n].enabled; } return virtio_queue_enabled_legacy(vdev, n); -- cgit v1.1 From c546ecf27da1114d0274abe600cc6bde6584e659 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 25 Jul 2020 08:13:17 +0800 Subject: virtio-net: check the existence of peer before accessing vDPA config We try to check whether a peer is VDPA in order to get config from there - with no peer, this leads to a NULL pointer dereference. Add a check before trying to access the peer type. No peer means not VDPA. Fixes: 108a64818e69b ("vhost-vdpa: introduce vhost-vdpa backend") Cc: Cindy Lu Tested-by: Cornelia Huck Reviewed-by: Cornelia Huck Signed-off-by: Jason Wang --- hw/net/virtio-net.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 4895af1..a1fe9e9 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -125,6 +125,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) { VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_config netcfg; + NetClientState *nc = qemu_get_queue(n->nic); int ret = 0; memset(&netcfg, 0 , sizeof(struct virtio_net_config)); @@ -142,13 +143,16 @@ static void virtio_net_get_config(VirtIODevice *vdev, uint8_t *config) VIRTIO_NET_RSS_SUPPORTED_HASHES); memcpy(config, &netcfg, n->config_size); - NetClientState *nc = qemu_get_queue(n->nic); - if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + /* + * Is this VDPA? No peer means not VDPA: there's no way to + * disconnect/reconnect a VDPA peer. + */ + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { ret = vhost_net_get_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, - n->config_size); - if (ret != -1) { - memcpy(config, &netcfg, n->config_size); - } + n->config_size); + if (ret != -1) { + memcpy(config, &netcfg, n->config_size); + } } } @@ -156,6 +160,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) { VirtIONet *n = VIRTIO_NET(vdev); struct virtio_net_config netcfg = {}; + NetClientState *nc = qemu_get_queue(n->nic); memcpy(&netcfg, config, n->config_size); @@ -166,11 +171,14 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) qemu_format_nic_info_str(qemu_get_queue(n->nic), n->mac); } - NetClientState *nc = qemu_get_queue(n->nic); - if (nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { - vhost_net_set_config(get_vhost_net(nc->peer), (uint8_t *)&netcfg, - 0, n->config_size, - VHOST_SET_CONFIG_TYPE_MASTER); + /* + * Is this VDPA? No peer means not VDPA: there's no way to + * disconnect/reconnect a VDPA peer. + */ + if (nc->peer && nc->peer->info->type == NET_CLIENT_DRIVER_VHOST_VDPA) { + vhost_net_set_config(get_vhost_net(nc->peer), + (uint8_t *)&netcfg, 0, n->config_size, + VHOST_SET_CONFIG_TYPE_MASTER); } } -- cgit v1.1 From 22dc8663d9fc7baa22100544c600b6285a63c7a3 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 22 Jul 2020 16:57:46 +0800 Subject: net: forbid the reentrant RX The memory API allows DMA into NIC's MMIO area. This means the NIC's RX routine must be reentrant. Instead of auditing all the NIC, we can simply detect the reentrancy and return early. The queue->delivering is set and cleared by qemu_net_queue_deliver() for other queue helpers to know whether the delivering in on going (NIC's receive is being called). We can check it and return early in qemu_net_queue_flush() to forbid reentrant RX. Signed-off-by: Jason Wang --- net/queue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/queue.c b/net/queue.c index 0164727..19e32c8 100644 --- a/net/queue.c +++ b/net/queue.c @@ -250,6 +250,9 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) bool qemu_net_queue_flush(NetQueue *queue) { + if (queue->delivering) + return false; + while (!QTAILQ_EMPTY(&queue->packets)) { NetPacket *packet; int ret; -- cgit v1.1