render / rpms / libvirt

Forked from rpms/libvirt 9 months ago
Clone
d759b5
From 9bf517748d9fed50a0bee163625f119b25fdb0ea Mon Sep 17 00:00:00 2001
d759b5
Message-Id: <9bf517748d9fed50a0bee163625f119b25fdb0ea@dist-git>
d759b5
From: Laine Stump <laine@redhat.com>
d759b5
Date: Thu, 26 Sep 2019 18:05:26 -0400
d759b5
Subject: [PATCH] conf: utility function to update entry in def->nets array
d759b5
d759b5
A virDomainNetDef object in a domain's nets array might contain a
d759b5
virDomainHostdevDef, and when this is the case, the domain's hostdevs
d759b5
array will also have a pointer to this embedded hostdev (this is done
d759b5
so that internal functions that need to perform some operation on all
d759b5
hostdevs won't leave out the type='hostdev' network interfaces).
d759b5
d759b5
When a network device was updated with virDomainUpdateDeviceFlags(),
d759b5
we were replacing the entry in the nets array (and free'ing the
d759b5
original) but forgetting about the pointer in the hostdevs array
d759b5
(which would then point to the now-free'd hostdev contained in the old
d759b5
net object.) This often resulted in a libvirtd crash.
d759b5
d759b5
The solution is to add a function, virDomainNetUpdate(), called by
d759b5
qemuDomainUpdateDeviceConfig(), that updates the hostdevs array
d759b5
appropriately along with the nets array.
d759b5
d759b5
Resolves: https://bugzilla.redhat.com/1558934
d759b5
d759b5
Signed-off-by: Laine Stump <laine@redhat.com>
d759b5
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
d759b5
(cherry picked from commit 7e490cdad6364c82b326d5d9251826c757e8f77b)
d759b5
Message-Id: <20190926220526.12970-1-laine@redhat.com>
d759b5
Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
d759b5
---
d759b5
 src/conf/domain_conf.c   | 41 ++++++++++++++++++++++++++++++++++++++++
d759b5
 src/conf/domain_conf.h   |  1 +
d759b5
 src/libvirt_private.syms |  1 +
d759b5
 src/lxc/lxc_driver.c     |  6 ++++--
d759b5
 src/qemu/qemu_driver.c   |  6 ++++--
d759b5
 5 files changed, 51 insertions(+), 4 deletions(-)
d759b5
d759b5
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
d759b5
index 0352fad245..60f426df04 100644
d759b5
--- a/src/conf/domain_conf.c
d759b5
+++ b/src/conf/domain_conf.c
d759b5
@@ -17119,6 +17119,47 @@ virDomainNetRemove(virDomainDefPtr def, size_t i)
d759b5
     return net;
d759b5
 }
d759b5
 
d759b5
+
d759b5
+int
d759b5
+virDomainNetUpdate(virDomainDefPtr def,
d759b5
+                   size_t netidx,
d759b5
+                   virDomainNetDefPtr newnet)
d759b5
+{
d759b5
+    size_t hostdevidx;
d759b5
+    virDomainNetDefPtr oldnet = def->nets[netidx];
d759b5
+    virDomainHostdevDefPtr oldhostdev = virDomainNetGetActualHostdev(oldnet);
d759b5
+    virDomainHostdevDefPtr newhostdev = virDomainNetGetActualHostdev(newnet);
d759b5
+
d759b5
+    /*
d759b5
+     * if newnet or oldnet has a valid hostdev*, we need to update the
d759b5
+     * hostdevs list
d759b5
+     */
d759b5
+    if (oldhostdev) {
d759b5
+        for (hostdevidx = 0; hostdevidx < def->nhostdevs; hostdevidx++) {
d759b5
+            if (def->hostdevs[hostdevidx] == oldhostdev)
d759b5
+                break;
d759b5
+        }
d759b5
+    }
d759b5
+
d759b5
+    if (oldhostdev && hostdevidx < def->nhostdevs) {
d759b5
+        if (newhostdev) {
d759b5
+            /* update existing entry in def->hostdevs */
d759b5
+            def->hostdevs[hostdevidx] = newhostdev;
d759b5
+        } else {
d759b5
+            /* delete oldhostdev from def->hostdevs */
d759b5
+            virDomainHostdevRemove(def, hostdevidx);
d759b5
+        }
d759b5
+    } else if (newhostdev) {
d759b5
+        /* add newhostdev to end of def->hostdevs */
d759b5
+        if (VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, newhostdev) < 0)
d759b5
+            return -1;
d759b5
+    }
d759b5
+
d759b5
+    def->nets[netidx] = newnet;
d759b5
+    return 0;
d759b5
+}
d759b5
+
d759b5
+
d759b5
 int virDomainControllerInsert(virDomainDefPtr def,
d759b5
                               virDomainControllerDefPtr controller)
d759b5
 {
d759b5
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
d759b5
index 1c4556cecd..ef8f061ae2 100644
d759b5
--- a/src/conf/domain_conf.h
d759b5
+++ b/src/conf/domain_conf.h
d759b5
@@ -3168,6 +3168,7 @@ virDomainNetDefPtr virDomainNetFind(virDomainDefPtr def, const char *device);
d759b5
 virDomainNetDefPtr virDomainNetFindByName(virDomainDefPtr def, const char *ifname);
d759b5
 bool virDomainHasNet(virDomainDefPtr def, virDomainNetDefPtr net);
d759b5
 int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net);
d759b5
+int virDomainNetUpdate(virDomainDefPtr def, size_t netidx, virDomainNetDefPtr newnet);
d759b5
 virDomainNetDefPtr virDomainNetRemove(virDomainDefPtr def, size_t i);
d759b5
 void virDomainNetRemoveHostdev(virDomainDefPtr def, virDomainNetDefPtr net);
d759b5
 
d759b5
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
d759b5
index 9b5e1350f0..b213e5764b 100644
d759b5
--- a/src/libvirt_private.syms
d759b5
+++ b/src/libvirt_private.syms
d759b5
@@ -476,6 +476,7 @@ virDomainNetSetDeviceImpl;
d759b5
 virDomainNetTypeFromString;
d759b5
 virDomainNetTypeSharesHostView;
d759b5
 virDomainNetTypeToString;
d759b5
+virDomainNetUpdate;
d759b5
 virDomainNostateReasonTypeFromString;
d759b5
 virDomainNostateReasonTypeToString;
d759b5
 virDomainObjAssignDef;
d759b5
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
d759b5
index 5978183e7f..0f2ef47bb5 100644
d759b5
--- a/src/lxc/lxc_driver.c
d759b5
+++ b/src/lxc/lxc_driver.c
d759b5
@@ -3526,8 +3526,10 @@ lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
d759b5
                                          false) < 0)
d759b5
             return -1;
d759b5
 
d759b5
-        virDomainNetDefFree(vmdef->nets[idx]);
d759b5
-        vmdef->nets[idx] = net;
d759b5
+        if (virDomainNetUpdate(vmdef, idx, net) < 0)
d759b5
+            return -1;
d759b5
+
d759b5
+        virDomainNetDefFree(oldDev.data.net);
d759b5
         dev->data.net = NULL;
d759b5
         ret = 0;
d759b5
 
d759b5
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
d759b5
index d95c97928d..2852b96edd 100644
d759b5
--- a/src/qemu/qemu_driver.c
d759b5
+++ b/src/qemu/qemu_driver.c
d759b5
@@ -8341,8 +8341,10 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
d759b5
                                          false) < 0)
d759b5
             return -1;
d759b5
 
d759b5
-        virDomainNetDefFree(vmdef->nets[pos]);
d759b5
-        vmdef->nets[pos] = net;
d759b5
+        if (virDomainNetUpdate(vmdef, pos, net))
d759b5
+            return -1;
d759b5
+
d759b5
+        virDomainNetDefFree(oldDev.data.net);
d759b5
         dev->data.net = NULL;
d759b5
         break;
d759b5
 
d759b5
-- 
d759b5
2.23.0
d759b5