After successfull destroying of vhost-user device (may be after virtio driver unbinding after disconnection of vhost-user socket) QEMU will fail to bind virtio driver again with segmentation fault:
[-------------------------------- cut -----------------------------------] # After vhost-user socket diconnection. [guest]# ip link show eth0 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc <...> link/ether 00:16:35:af:aa:4b brd ff:ff:ff:ff:ff:ff [guest]# echo -n '0000:00:01.0' > /sys/bus/pci/drivers/virtio-pci/unbind qemu: Failed to read msg header. Read 0 instead of 12. Original request 11. qemu: Failed to read msg header. Read 0 instead of 12. Original request 11. [guest]# echo -n '0000:00:01.0' > /sys/bus/pci/drivers/virtio-pci/bind Child terminated with signal = 0xb (SIGSEGV) GDBserver exiting [-------------------------------- cut -----------------------------------] [host]# gdb Program received signal SIGSEGV, Segmentation fault. vhost_set_vring_enable (<...>) at /hw/net/vhost_net.c:425 425 if (vhost_ops->vhost_set_vring_enable) { (gdb) bt #0 vhost_set_vring_enable (nc=0xfff8a0, enable=enable@entry=1) net = 0x0 # NULL pointer to vhost_net device ! vhost_ops = <(Cannot access memory at address 0x110)> res = 0 #1 peer_attach #2 virtio_net_set_queues #3 virtio_net_set_multiqueue #4 virtio_net_set_features #5 virtio_set_features_nocheck #6 memory_region_write_accessor #7 access_with_adjusted_size #8 memory_region_dispatch_write #9 address_space_write_continue #10 address_space_write <...> [-------------------------------- cut -----------------------------------] This happens because of invalid vhost_net device pointer. Fix that by checking this pointer in all functions before using. Result: [-------------------------------- cut -----------------------------------] [guest]# echo -n '0000:00:01.0' > /sys/bus/pci/drivers/virtio-pci/bind # Check link in guest. No crashes here, link in DOWN state. [guest]# ip link show eth0 7: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc <...> link/ether 00:16:35:af:aa:4b brd ff:ff:ff:ff:ff:ff [-------------------------------- cut -----------------------------------] Signed-off-by: Ilya Maximets <i.maxim...@samsung.com> --- hw/net/vhost_net.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 0996e5d..4c3363f 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -202,6 +202,10 @@ static int vhost_net_start_one(struct vhost_net *net, struct vhost_vring_file file = { }; int r; + if (!net) { + return -1; + } + net->dev.nvqs = 2; net->dev.vqs = net->vqs; @@ -256,6 +260,10 @@ static void vhost_net_stop_one(struct vhost_net *net, { struct vhost_vring_file file = { .fd = -1 }; + if (!net) { + return; + } + if (net->nc->info->type == NET_CLIENT_OPTIONS_KIND_TAP) { for (file.index = 0; file.index < net->dev.nvqs; ++file.index) { const VhostOps *vhost_ops = net->dev.vhost_ops; @@ -287,6 +295,9 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs, struct vhost_net *net; net = get_vhost_net(ncs[i].peer); + if (!net) { + return -1; + } vhost_net_set_vq_index(net, i * 2); /* Suppress the masking guest notifiers on vhost user @@ -419,9 +430,14 @@ void put_vhost_net(NetClientState *nc) int vhost_set_vring_enable(NetClientState *nc, int enable) { VHostNetState *net = get_vhost_net(nc); - const VhostOps *vhost_ops = net->dev.vhost_ops; + const VhostOps *vhost_ops; int res = 0; + if (!net) { + return 0; + } + + vhost_ops = net->dev.vhost_ops; if (vhost_ops->vhost_set_vring_enable) { res = vhost_ops->vhost_set_vring_enable(&net->dev, enable); } -- 2.5.0