[PATCH 0/3] qemu: forbid modifying portForwards with live update-device
See 3/3 for details. Resolves: https://issues.redhat.com/browse/RHEL-7338 Laine Stump (3): util: fix equivalence of AF_UNSPEC virSocketAddrs conf: new function virDomainNetPortForwardIsEqual() qemu: forbid modifying network device portForwards with update-device src/conf/domain_conf.c | 53 ++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 3 +++ src/libvirt_private.syms | 1 + src/qemu/qemu_hotplug.c | 9 +++++++ src/util/virsocketaddr.c | 2 ++ 5 files changed, 68 insertions(+) -- 2.52.0
If a virSocketAddr has family AF_UNSPEC that means it is unspecified/empty. If two virSocketAddrs are AF_UNSPEC then they are equal, but virSocketAddrEqual() was countint that as *not* equal. This doesn't make a difference for current uses of the function since they all check that at least one of the virSocketAddrs is *not* AF_UNSPEC before calling virSocketAddrEqual(), but an upcoming patch using virSocketAddrEqual() will not be making that check, so let's fix the utility function. Signed-off-by: Laine Stump <laine@redhat.com> --- src/util/virsocketaddr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/virsocketaddr.c b/src/util/virsocketaddr.c index f53768878e..4d4a6b2a0f 100644 --- a/src/util/virsocketaddr.c +++ b/src/util/virsocketaddr.c @@ -369,6 +369,8 @@ virSocketAddrEqual(const virSocketAddr *s1, const virSocketAddr *s2) return false; switch (s1->data.stor.ss_family) { + case AF_UNSPEC: + return true; case AF_INET: return (memcmp(&s1->data.inet4.sin_addr.s_addr, &s2->data.inet4.sin_addr.s_addr, -- 2.52.0
This function checks two arrays of virDomainNetPortForwards for equality. It seemed silly to send a separate #elements for each array just to check for their equality, but I could easily be convinced to do it that way (rather than having the caller check for equal #element and then just send it once). Signed-off-by: Laine Stump <laine@redhat.com> --- src/conf/domain_conf.c | 53 ++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 3 +++ src/libvirt_private.syms | 1 + 3 files changed, 57 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 9ca5c2450c..d00a43e969 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -21037,6 +21037,59 @@ virDomainNetBackendIsEqual(virDomainNetBackend *src, return true; } +static bool +virDomainNetPortForwardRangeIsEqual(virDomainNetPortForwardRange *r1, + virDomainNetPortForwardRange *r2) +{ + if (!r1 && !r2) + return true; + if (!(r1 && r2)) + return false; + + return (r1->start == r2->start && + r1->end == r2->end && + r1->to == r2->to && + r1->exclude == r2->exclude); +} + + +bool +virDomainNetPortForwardsIsEqual(virDomainNetPortForward **pfs1, + virDomainNetPortForward **pfs2, + size_t npfs) +{ + size_t i; + + if (!pfs1 && !pfs2) + return true; + if (!(pfs1 && pfs2)) + return false; + + for (i = 0; i < npfs; i++) { + virDomainNetPortForward *pf1 = pfs1[0]; + virDomainNetPortForward *pf2 = pfs2[0]; + + if (!pf1 && !pf2) + continue; + if (!(pf1 && pf2)) + return false; + + if (STRNEQ_NULLABLE(pf1->dev, pf2->dev) || + pf1->proto != pf2->proto || + !virSocketAddrEqual(&pf1->address, &pf2->address) || + pf1->nRanges != pf2->nRanges) { + return false; + } + + for (i = 0; i < pf1->nRanges; i++) { + if (!virDomainNetPortForwardRangeIsEqual(pf1->ranges[i], pf2->ranges[i])) + return false; + } + } + + return true; +} + static bool virDomainNetDefCheckABIStability(virDomainNetDef *src, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index cb35ff06bd..83d49969d3 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -4099,6 +4099,9 @@ void virDomainNetInsert(virDomainDef *def, virDomainNetDef *net); void virDomainNetUpdate(virDomainDef *def, size_t netidx, virDomainNetDef *newnet); bool virDomainNetBackendIsEqual(virDomainNetBackend *src, virDomainNetBackend *dst); +bool virDomainNetPortForwardsIsEqual(virDomainNetPortForward **pfs1, + virDomainNetPortForward **pfs2, + size_t npfs); int virDomainNetDHCPInterfaces(virDomainDef *def, virDomainInterfacePtr **ifaces); int virDomainNetARPInterfaces(virDomainDef *def, virDomainInterfacePtr **ifaces); virDomainNetDef *virDomainNetRemove(virDomainDef *def, size_t i); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 4e57e4a8f6..ab2ab8afd2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -577,6 +577,7 @@ virDomainNetModelTypeFromString; virDomainNetModelTypeToString; virDomainNetNotifyActualDevice; virDomainNetPortForwardFree; +virDomainNetPortForwardsIsEqual; virDomainNetReleaseActualDevice; virDomainNetRemove; virDomainNetRemoveByObj; -- 2.52.0
Prior to this patch, a network device of a running domain could be updated to change the portForwards list, and libvirt wouldn't complain, but the change would be silently ignored. This list is only used by the passt backend, and passt can only change the list of portForwards by killing and re-running the passt process, which we don't want to do because that would destroy any open tcp session flows in passt (ie. it would disrupt guest network traffic); we don't want to do *that*, but we should at least let the user know that their requested change isn't possible. This patch checks if the portForwards list of the updated network device exactly matches the portForwards list of the current network device, and fails the update if they don't match. Resolves: https://issues.redhat.com/browse/RHEL-7338 Signed-off-by: Laine Stump <laine@redhat.com> --- src/qemu/qemu_hotplug.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index fccbef5d0c..cfc586e17d 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -3966,6 +3966,15 @@ qemuDomainChangeNet(virQEMUDriver *driver, goto cleanup; } + if (olddev->nPortForwards != newdev->nPortForwards || + !virDomainNetPortForwardsIsEqual(olddev->portForwards, + newdev->portForwards, + olddev->nPortForwards)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("cannot modify network device portForward settings")); + goto cleanup; + } + /* allocate new actual device to compare to old - we will need to * free it if we fail for any reason */ -- 2.52.0
On 1/13/26 08:35, Laine Stump via Devel wrote:
See 3/3 for details.
Resolves: https://issues.redhat.com/browse/RHEL-7338
Laine Stump (3): util: fix equivalence of AF_UNSPEC virSocketAddrs conf: new function virDomainNetPortForwardIsEqual() qemu: forbid modifying network device portForwards with update-device
src/conf/domain_conf.c | 53 ++++++++++++++++++++++++++++++++++++++++ src/conf/domain_conf.h | 3 +++ src/libvirt_private.syms | 1 + src/qemu/qemu_hotplug.c | 9 +++++++ src/util/virsocketaddr.c | 2 ++ 5 files changed, 68 insertions(+)
Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Michal
participants (2)
-
Laine Stump -
Michal Prívozník