Package: release.debian.org Severity: normal Tags: trixie X-Debbugs-Cc: [email protected] Control: affects -1 + src:libvirt User: [email protected] Usertags: pu
Please approve the attached diff as a stable update to trixie. [ Reason ] Various fixes for libvirt in trixie, specifically one functional bug and 5 CVEs. [ Tests ] I have performed a quick test to confirm that overall functionality of the package is not compromised. I haven't attempted to reproduce each single issue in trixie and confirm that the backported patches actually address them, but all fixes come directly from upstream so I am highly confident in their effectiveness. I have inspected each diff and found them all to be reasonable. [ Risks ] Very little risk given the targeted nature of the fixes and their origin. The libvirt project has an excellent track record when it comes to preserving backwards compatibility and avoiding regressions. [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [ ] the issue is verified as fixed in unstable One of the fixes is not in unstable yet, but it will once the new upstream release is out (in two days) and I have found time to upload it (shortly afterwards). [ Changes ] See the changelog. -- Andrea Bolognani <[email protected]> Resistance is futile, you will be garbage collected.
diff -Nru libvirt-11.3.0/debian/changelog libvirt-11.3.0/debian/changelog --- libvirt-11.3.0/debian/changelog 2025-12-07 16:22:24.000000000 +0100 +++ libvirt-11.3.0/debian/changelog 2026-08-30 15:59:50.000000000 +0200 @@ -1,3 +1,29 @@ +libvirt (11.3.0-3+deb13u3) trixie; urgency=medium + + * [7061212] patches: Add backports + - backport/qemuMonitorJSONMigrate-Drop-detach-QMP-option.patch + - Closes: #1145836 + * [eaa378a] patches: Add backports + - backport/remote-Fix-integer-overflow-in-RPC-handler-[...] + - CVE-2026-18917 + * [1b35d45] patches: Add backports + - backport/conf-reject-line-breaks-in-DNS-TXT-record-[...] + - backport/conf-reject-line-breaks-in-DNS-SRV-domain-[...] + - backport/network-reject-line-breaks-before-writing-[...] + - backport/tests-cover-line-break-rejection-in-DNS-[...] + - CVE-2026-61477 + * [4378d69] patches: Add backports + - backport/src-fix-crash-searching-for-XML-context-string-[...] + - CVE-2026-61478 + * [fd7eaa5] patches: Add backports + - backport/util-virFileChownFiles-do-not-follow-symlinks.patch + - CVE-2026-63622 + * [eccf219] patches: Add backports + - backport/storage-create-images-with-a-private-umask-[...] + - CVE-2026-63623 + + -- Andrea Bolognani <[email protected]> Sun, 30 Aug 2026 15:59:50 +0200 + libvirt (11.3.0-3+deb13u2) trixie; urgency=medium * [c5ef2ce] patches: Add backports diff -Nru libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-SRV-domain-and-target.patch libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-SRV-domain-and-target.patch --- libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-SRV-domain-and-target.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-SRV-domain-and-target.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,45 @@ +From: Michael Bommarito <[email protected]> +Date: Fri, 10 Jul 2026 07:06:59 -0400 +Subject: conf: reject line breaks in DNS SRV domain and target +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +The <dns><srv> domain and target attributes flow through the same +dnsmasq configuration emitter as TXT values, written into srv-host= +lines. Like the TXT value they accept XML numeric character +references for LF and CR and are not otherwise constrained, unlike +service and protocol which already have allow-lists. An embedded +line break ends the srv-host= directive and begins a new one. + +Reject LF and CR in the SRV domain and target during XML parsing, +reusing the helper added for TXT values. + +CVE-2026-61477 + +Fixes: 6612d1adb794 ("network: fix problems with SRV records") +Reviewed-by: Daniel P. Berrangé <[email protected]> +Signed-off-by: Michael Bommarito <[email protected]> +(cherry picked from commit 289ffa796d737a79a4c05d07232ebd75def9a12a) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/289ffa796d737a79a4c05d07232ebd75def9a12a +--- + src/conf/network_conf.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c +index 9c3cd2a..24c629b 100644 +--- a/src/conf/network_conf.c ++++ b/src/conf/network_conf.c +@@ -792,6 +792,10 @@ virNetworkDNSSrvDefParseXML(const char *networkName, + def->domain = virXMLPropString(node, "domain"); + def->target = virXMLPropString(node, "target"); + ++ if (virNetworkDNSDefCheckLineBreaks("SRV", "domain", def->domain) < 0 || ++ virNetworkDNSDefCheckLineBreaks("SRV", "target", def->target) < 0) ++ goto error; ++ + ret = virXPathUInt("string(./@port)", ctxt, &def->port); + if (ret >= 0 && !def->target) { + virReportError(VIR_ERR_XML_DETAIL, diff -Nru libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-TXT-record-values.patch libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-TXT-record-values.patch --- libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-TXT-record-values.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/conf-reject-line-breaks-in-DNS-TXT-record-values.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,75 @@ +From: Michael Bommarito <[email protected]> +Date: Fri, 10 Jul 2026 07:06:58 -0400 +Subject: conf: reject line breaks in DNS TXT record values +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +The network XML schema exposes typed DNS records through the +<dns><txt> element. The TXT value attribute accepts XML numeric +character references, including (LF) and (CR), which +survive attribute-value normalization. The network driver later +writes the value verbatim into dnsmasq's line-oriented configuration +file as a txt-record= line, so an embedded line break ends that +directive and starts a new one under attacker control. + +This is a real boundary where a management layer permits editing +typed DNS records while withholding the raw <dnsmasq:options> +passthrough: the injected line escapes that restriction. Direct +read-write access to the libvirt socket is already root-equivalent, +so for the default deployment this is schema-correctness hardening. + +Add a helper that rejects LF and CR and call it for the TXT value +during XML parsing. + +CVE-2026-61477 + +Fixes: 8b32c80df089 ("network: put dnsmasq parameters in conf-file instead of command line") +Reviewed-by: Daniel P. Berrangé <[email protected]> +Signed-off-by: Michael Bommarito <[email protected]> +(cherry picked from commit d44836a1dc6771ac22f69755fc69bf730f0eec87) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/d44836a1dc6771ac22f69755fc69bf730f0eec87 +--- + src/conf/network_conf.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c +index 8cd26de..9c3cd2a 100644 +--- a/src/conf/network_conf.c ++++ b/src/conf/network_conf.c +@@ -724,6 +724,23 @@ virNetworkDNSHostDefParseXML(const char *networkName, + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" \ + "_-+/*" + ++ ++static int ++virNetworkDNSDefCheckLineBreaks(const char *record, ++ const char *field, ++ const char *value) ++{ ++ if (virStringHasChars(value, "\r\n")) { ++ virReportError(VIR_ERR_XML_DETAIL, ++ _("invalid line break in DNS %1$s record %2$s attribute"), ++ record, field); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ + static int + virNetworkDNSSrvDefParseXML(const char *networkName, + xmlNodePtr node, +@@ -852,6 +869,9 @@ virNetworkDNSTxtDefParseXML(const char *networkName, + goto error; + } + ++ if (virNetworkDNSDefCheckLineBreaks("TXT", "value", def->value) < 0) ++ goto error; ++ + if (!(def->name || def->value)) { + virReportError(VIR_ERR_XML_DETAIL, + _("Missing required name or value in DNS TXT record of network %1$s"), diff -Nru libvirt-11.3.0/debian/patches/backport/network-reject-line-breaks-before-writing-dnsmasq-DNS-con.patch libvirt-11.3.0/debian/patches/backport/network-reject-line-breaks-before-writing-dnsmasq-DNS-con.patch --- libvirt-11.3.0/debian/patches/backport/network-reject-line-breaks-before-writing-dnsmasq-DNS-con.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/network-reject-line-breaks-before-writing-dnsmasq-DNS-con.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,95 @@ +From: Michael Bommarito <[email protected]> +Date: Fri, 10 Jul 2026 07:07:00 -0400 +Subject: network: reject line breaks before writing dnsmasq DNS config +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +The parser now rejects line breaks in typed DNS TXT and SRV fields, +but the dnsmasq configuration emitter is the actual trust boundary: +any future parser gap, or a value reaching the emitter by another +path, would again let a typed DNS field inject an arbitrary dnsmasq +directive. + +Add a defensive check in networkDnsmasqConfContents() that rejects +LF and CR in every typed DNS string immediately before it is written +to the line-based configuration file. This sits behind the parser +checks and keeps the emitter correct on its own. + +The raw <dnsmasq:options> namespace is intentionally left untouched: +it is the documented escape hatch for arbitrary dnsmasq options, and +sanitizing it would be a separate, deliberate behavior change. + +CVE-2026-61477 + +Fixes: 8b32c80df089 ("network: put dnsmasq parameters in conf-file instead of command line") +Reviewed-by: Daniel P. Berrangé <[email protected]> +Signed-off-by: Michael Bommarito <[email protected]> +(cherry picked from commit cb8974b923e3c40cde96f0c7bceaa638f7f9c72b) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/cb8974b923e3c40cde96f0c7bceaa638f7f9c72b +--- + src/network/bridge_driver.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c +index 34b655e..b7ec305 100644 +--- a/src/network/bridge_driver.c ++++ b/src/network/bridge_driver.c +@@ -62,6 +62,7 @@ + #include "virhook.h" + #include "virjson.h" + #include "virnetworkportdef.h" ++#include "virstring.h" + #include "virutil.h" + #include "virsystemd.h" + #include "netdev_bandwidth_conf.h" +@@ -117,6 +118,22 @@ networkDnsmasqDefNamespaceFree(void *nsdata) + G_DEFINE_AUTOPTR_CLEANUP_FUNC(networkDnsmasqXmlNsDef, networkDnsmasqDefNamespaceFree); + + ++static int ++networkDnsmasqConfCheckLineBreaks(const char *record, ++ const char *field, ++ const char *value) ++{ ++ if (virStringHasChars(value, "\r\n")) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("DNS %1$s record %2$s must not contain line breaks"), ++ record, field); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ + static int + networkDnsmasqDefNamespaceParseOptions(networkDnsmasqXmlNsDef *nsdef, + xmlXPathContextPtr ctxt) +@@ -1294,6 +1311,10 @@ networkDnsmasqConfContents(virNetworkObj *obj, + + if (wantDNS) { + for (i = 0; i < dns->ntxts; i++) { ++ if (networkDnsmasqConfCheckLineBreaks("TXT", "name", dns->txts[i].name) < 0 || ++ networkDnsmasqConfCheckLineBreaks("TXT", "value", dns->txts[i].value) < 0) ++ return -1; ++ + virBufferAsprintf(&configbuf, "txt-record=%s,%s\n", + dns->txts[i].name, + dns->txts[i].value); +@@ -1315,6 +1336,13 @@ networkDnsmasqConfContents(virNetworkObj *obj, + def->name); + return -1; + } ++ ++ if (networkDnsmasqConfCheckLineBreaks("SRV", "service", dns->srvs[i].service) < 0 || ++ networkDnsmasqConfCheckLineBreaks("SRV", "protocol", dns->srvs[i].protocol) < 0 || ++ networkDnsmasqConfCheckLineBreaks("SRV", "domain", dns->srvs[i].domain) < 0 || ++ networkDnsmasqConfCheckLineBreaks("SRV", "target", dns->srvs[i].target) < 0) ++ return -1; ++ + /* RFC2782 requires that service and protocol be preceded by + * an underscore. + */ diff -Nru libvirt-11.3.0/debian/patches/backport/qemuMonitorJSONMigrate-Drop-detach-QMP-option.patch libvirt-11.3.0/debian/patches/backport/qemuMonitorJSONMigrate-Drop-detach-QMP-option.patch --- libvirt-11.3.0/debian/patches/backport/qemuMonitorJSONMigrate-Drop-detach-QMP-option.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/qemuMonitorJSONMigrate-Drop-detach-QMP-option.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,37 @@ +From: Peter Krempa <[email protected]> +Date: Wed, 21 May 2025 09:59:53 +0200 +Subject: qemuMonitorJSONMigrate: Drop 'detach' QMP option + +The argument was always ignored by qemu [1], as of qemu-10.1 it will be +deprecated. As it was always unused/ignored we can drop it without any +extra logic. + +[1] qemu docs state: + + 3. The user Monitor's "detach" argument is invalid in QMP and + should not be used. + +Signed-off-by: Peter Krempa <[email protected]> +Reviewed-by: Michal Privoznik <[email protected]> +(cherry picked from commit 17e170a137911837867feb680ed5d5d132133621) + +Bug-Debian: https://bugs.debian.org/1145836 + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/17e170a137911837867feb680ed5d5d132133621 +--- + src/qemu/qemu_monitor_json.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c +index dc2eaac..9a2f279 100644 +--- a/src/qemu/qemu_monitor_json.c ++++ b/src/qemu/qemu_monitor_json.c +@@ -3198,7 +3198,6 @@ int qemuMonitorJSONMigrate(qemuMonitor *mon, + { + bool resume = !!(flags & QEMU_MONITOR_MIGRATE_RESUME); + g_autoptr(virJSONValue) cmd = qemuMonitorJSONMakeCommand("migrate", +- "b:detach", true, + "b:resume", resume, + "s:uri", uri, + NULL); diff -Nru libvirt-11.3.0/debian/patches/backport/remote-Fix-integer-overflow-in-RPC-handler-for-virNodeGet.patch libvirt-11.3.0/debian/patches/backport/remote-Fix-integer-overflow-in-RPC-handler-for-virNodeGet.patch --- libvirt-11.3.0/debian/patches/backport/remote-Fix-integer-overflow-in-RPC-handler-for-virNodeGet.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/remote-Fix-integer-overflow-in-RPC-handler-for-virNodeGet.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,65 @@ +From: Peter Krempa <[email protected]> +Date: Wed, 12 Aug 2026 16:51:58 +0200 +Subject: remote: Fix integer overflow in RPC handler for virNodeGetFreePages + (CVE-2026-18917) +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +CVE-2026-18917 + +The RPC handler 'remoteDispatchNodeGetFreePages' multiplies the 'npages' +argument with the 'cellcount' argument passed to 'virNodeGetFreePages', +both of which are declared as 'unsigned int' to both do an RPC limit +check against the 'REMOTE_NODE_MAX_CELLS' constant and then to allocate +the memory to hold the result from the actual hypervisor driver. + +Since both the values are 'unsigned int' the product is also unsigned +int so big enough numbers can overflow, both passing the check and also +allocating not enough memory for the result. The hypervisor driver +assumes that the passed buffer is large enough and overwrites memory. + +When this happens the the hypervisor daemon crashes. + +This can be triggered e.g. by passing 1023 and 4198405 as values which +multiply to 1019 after wrapping to 32 bit unsigned value. + +Use the VIR_INT_MULTIPLY_OVERFLOW macro in the check to avoid the issue +the same way as we do for other APIs doing multiplication of arguments +to determine amount of required memory. + +Fixes: 34f2d0319d2098c77c8cc27d8350616029125a2b (v1.2.5-164-g34f2d0319d) +Closes: https://gitlab.com/libvirt/libvirt/-/work_items/903 +Signed-off-by: Peter Krempa <[email protected]> +Reviewed-by: Daniel P. Berrangé <[email protected]> +(cherry picked from commit 5a62cbf2907d4590283597b46da9c0f41e7b4d4f) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/5a62cbf2907d4590283597b46da9c0f41e7b4d4f +--- + src/remote/remote_daemon_dispatch.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c +index 5dfed7c..4bc62a4 100644 +--- a/src/remote/remote_daemon_dispatch.c ++++ b/src/remote/remote_daemon_dispatch.c +@@ -6658,13 +6658,14 @@ remoteDispatchNodeGetFreePages(virNetServer *server G_GNUC_UNUSED, + if (!conn) + goto cleanup; + +- if (args->pages.pages_len * args->cellCount > REMOTE_NODE_MAX_CELLS) { +- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", +- _("the result won't fit into REMOTE_NODE_MAX_CELLS")); ++ if (VIR_INT_MULTIPLY_OVERFLOW(args->pages.pages_len, args->cellCount) || ++ args->pages.pages_len * args->cellCount > REMOTE_NODE_MAX_CELLS) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("npages * cellcount > REMOTE_NODE_MAX_CELLS (%1$u)"), ++ REMOTE_NODE_MAX_CELLS); + goto cleanup; + } + +- /* Allocate return buffer. */ + ret->counts.counts_val = g_new0(uint64_t, + args->pages.pages_len * args->cellCount); + diff -Nru libvirt-11.3.0/debian/patches/backport/src-fix-crash-searching-for-XML-context-string-on-errors.patch libvirt-11.3.0/debian/patches/backport/src-fix-crash-searching-for-XML-context-string-on-errors.patch --- libvirt-11.3.0/debian/patches/backport/src-fix-crash-searching-for-XML-context-string-on-errors.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/src-fix-crash-searching-for-XML-context-string-on-errors.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,107 @@ +From: =?utf-8?b?IkRhbmllbCBQLiBCZXJyYW5nw6ki?= <[email protected]> +Date: Tue, 14 Jul 2026 16:32:57 +0100 +Subject: src: fix crash searching for XML context string on errors +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +When we have an XML parse error, libxml2 invokes a callback that +receives pointers to the start of the document being parsed and the +location where the error was triggered. + +In the case of a document that contains 100's of empty lines +(ie a sequence of newlines), at some point libxml2 will advance +the base pointer discarding the useful context. + +Thus when catchXMLError then searches backwards to discard empty +lines and look for the context element, it will eventually get +to the start of the string. When this happens the virBuffer that +holds the context string ends up empty and then catchXMLError will +dereference a NULL pointer. + +In almost all cases, the APIs which accept XML documents from +the user are behind the primary read-write socket, however, the +CPU baseline API is exposed to the read-only socket. Thus an +unprivileged user can trigger a denial of service by crashing +the libvirt daemons with a malicious XML document. + +Check for this empty string condition and skip inclusion of the +XML document context in the error message. + +Fixes: CVE-2026-61478 +Reported-by: Rx <[email protected]> +Reviewed-by: Peter Krempa <[email protected]> +Signed-off-by: Daniel P. Berrangé <[email protected]> +(cherry picked from commit 68da70aae766c6271b8d3b466374d3cc7d1a8afb) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/68da70aae766c6271b8d3b466374d3cc7d1a8afb +--- + src/util/virxml.c | 46 +++++++++++++++++++++++++++++++--------------- + 1 file changed, 31 insertions(+), 15 deletions(-) + +diff --git a/src/util/virxml.c b/src/util/virxml.c +index ad967a2..fe9447f 100644 +--- a/src/util/virxml.c ++++ b/src/util/virxml.c +@@ -1079,7 +1079,8 @@ catchXMLError(void *ctx, const char *msg G_GNUC_UNUSED, ...) + contextstr = virBufferContentAndReset(&buf); + + /* (leave buffer space for pointer + line terminator) */ +- for (n = 0; (n<col) && (contextstr[n] != 0); n++) { ++ ++ for (n = 0; (n<col) && contextstr && contextstr[n]; n++) { + if (contextstr[n] == '\t') + virBufferAddChar(&buf, '\t'); + else +@@ -1090,21 +1091,36 @@ catchXMLError(void *ctx, const char *msg G_GNUC_UNUSED, ...) + + pointerstr = virBufferContentAndReset(&buf); + +- if (filename) { +- virGenericReportError(domcode, VIR_ERR_XML_DETAIL, +- _("%1$s:%2$d: %3$s%4$s\n%5$s"), +- filename, +- lastError->line, +- lastError->message, +- contextstr, +- pointerstr); ++ if (contextstr) { ++ if (filename) { ++ virGenericReportError(domcode, VIR_ERR_XML_DETAIL, ++ _("%1$s:%2$d: %3$s%4$s\n%5$s"), ++ filename, ++ lastError->line, ++ lastError->message, ++ contextstr, ++ pointerstr); ++ } else { ++ virGenericReportError(domcode, VIR_ERR_XML_DETAIL, ++ _("at line %1$d: %2$s%3$s\n%4$s"), ++ lastError->line, ++ lastError->message, ++ contextstr, ++ pointerstr); ++ } + } else { +- virGenericReportError(domcode, VIR_ERR_XML_DETAIL, +- _("at line %1$d: %2$s%3$s\n%4$s"), +- lastError->line, +- lastError->message, +- contextstr, +- pointerstr); ++ if (filename) { ++ virGenericReportError(domcode, VIR_ERR_XML_DETAIL, ++ _("%1$s:%2$d: %3$s"), ++ filename, ++ lastError->line, ++ lastError->message); ++ } else { ++ virGenericReportError(domcode, VIR_ERR_XML_DETAIL, ++ _("at line %1$d: %2$s"), ++ lastError->line, ++ lastError->message); ++ } + } + } + diff -Nru libvirt-11.3.0/debian/patches/backport/storage-create-images-with-a-private-umask-during-qemu-im.patch libvirt-11.3.0/debian/patches/backport/storage-create-images-with-a-private-umask-during-qemu-im.patch --- libvirt-11.3.0/debian/patches/backport/storage-create-images-with-a-private-umask-during-qemu-im.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/storage-create-images-with-a-private-umask-during-qemu-im.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,57 @@ +From: =?utf-8?b?SEUgV0VJ77yI44Ku44Kr44Kv77yJ?= <[email protected]> +Date: Tue, 28 Jul 2026 17:30:57 +0100 +Subject: storage: create images with a private umask during qemu-img + create/convert +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +On the local (non-NETFS) path virStorageBackendCreateExecCommand() ran +qemu-img with umask 0, so the destination image was created +world-readable (0644) and the full source disk was written into it +before libvirt tightened the mode with a later chmod(). This is the same +class as CVE-2025-13193; apply the same fix by setting a 0077 umask so +qemu-img creates the file private from the start. + +Fixes: CVE-2026-63623 +Reported-by: HE WEI(ギカク) <[email protected]> +Signed-off-by: HE WEI(ギカク) <[email protected]> +[DB: merged the two virCommandSetUmask to one] +Reviewed-by: Ján Tomko <[email protected]> +Signed-off-by: Daniel P. Berrangé <[email protected]> +(cherry picked from commit 69335a484768d550854da1133d5490074695e825) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/69335a484768d550854da1133d5490074695e825 +--- + src/storage/storage_util.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c +index 28d5fce..8c4e31e 100644 +--- a/src/storage/storage_util.c ++++ b/src/storage/storage_util.c +@@ -464,6 +464,7 @@ virStorageBackendCreateExecCommand(virStoragePoolObj *pool, + bool filecreated = false; + int ret = -1; + ++ virCommandSetUmask(cmd, S_IRWXUGO ^ mode); + if ((def->type == VIR_STORAGE_POOL_NETFS) + && (((geteuid() == 0) + && (vol->target.perms->uid != (uid_t)-1) +@@ -473,7 +474,6 @@ virStorageBackendCreateExecCommand(virStoragePoolObj *pool, + + virCommandSetUID(cmd, vol->target.perms->uid); + virCommandSetGID(cmd, vol->target.perms->gid); +- virCommandSetUmask(cmd, S_IRWXUGO ^ mode); + + if (virCommandRun(cmd, NULL) == 0) { + /* command was successfully run, check if the file was created */ +@@ -505,7 +505,6 @@ virStorageBackendCreateExecCommand(virStoragePoolObj *pool, + /* don't change uid/gid/mode if we retry */ + virCommandSetUID(cmd, -1); + virCommandSetGID(cmd, -1); +- virCommandSetUmask(cmd, 0); + + if (virCommandRun(cmd, NULL) < 0) + goto cleanup; diff -Nru libvirt-11.3.0/debian/patches/backport/tests-cover-line-break-rejection-in-DNS-TXT-and-SRV-recor.patch libvirt-11.3.0/debian/patches/backport/tests-cover-line-break-rejection-in-DNS-TXT-and-SRV-recor.patch --- libvirt-11.3.0/debian/patches/backport/tests-cover-line-break-rejection-in-DNS-TXT-and-SRV-recor.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/tests-cover-line-break-rejection-in-DNS-TXT-and-SRV-recor.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,197 @@ +From: Michael Bommarito <[email protected]> +Date: Fri, 10 Jul 2026 07:07:01 -0400 +Subject: tests: cover line-break rejection in DNS TXT and SRV records +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +Add negative tests that feed XML numeric character references for LF +( ) and CR ( ) into the DNS TXT value and SRV domain/target +attributes, covering both the network XML parse path and the update +API. Literal newlines are insufficient because XML parsers normalize +raw attribute whitespace to spaces; the numeric references are what +survive to the configuration emitter. + +CVE-2026-61477 + +Reviewed-by: Daniel P. Berrangé <[email protected]> +Signed-off-by: Michael Bommarito <[email protected]> +(cherry picked from commit 3cfc77963b512d809348fca07f97fe924fac9a05) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/3cfc77963b512d809348fca07f97fe924fac9a05 +--- + .../nat-network-dns-srv-record-domain-newline.xml | 14 ++++++++++++++ + .../nat-network-dns-srv-record-target-newline.xml | 14 ++++++++++++++ + .../nat-network-dns-txt-record-newline.xml} | 11 ++++++----- + tests/networkxml2xmltest.c | 3 +++ + tests/networkxml2xmlupdatein/dns-txt-record-newline.xml | 1 + + tests/networkxml2xmlupdatein/srv-record-target-newline.xml | 1 + + tests/networkxml2xmlupdatetest.c | 12 ++++++++++++ + tests/virschematest.c | 11 ++++++++++- + 8 files changed, 61 insertions(+), 6 deletions(-) + create mode 100644 tests/networkxml2confdata/nat-network-dns-srv-record-domain-newline.xml + create mode 100644 tests/networkxml2confdata/nat-network-dns-srv-record-target-newline.xml + copy tests/{networkxml2xmlout/netboot-proxy-network.xml => networkxml2confdata/nat-network-dns-txt-record-newline.xml} (52%) + create mode 100644 tests/networkxml2xmlupdatein/dns-txt-record-newline.xml + create mode 100644 tests/networkxml2xmlupdatein/srv-record-target-newline.xml + +diff --git a/tests/networkxml2confdata/nat-network-dns-srv-record-domain-newline.xml b/tests/networkxml2confdata/nat-network-dns-srv-record-domain-newline.xml +new file mode 100644 +index 0000000..2a1a5e4 +--- /dev/null ++++ b/tests/networkxml2confdata/nat-network-dns-srv-record-domain-newline.xml +@@ -0,0 +1,14 @@ ++<network> ++ <name>default</name> ++ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> ++ <forward dev='eth1' mode='nat'/> ++ <bridge name='virbr0' stp='on' delay='0'/> ++ <dns> ++ <srv service='ldap' protocol='tcp' domain='example.com dhcp-script=/tmp/payload' target='server.example.com'/> ++ </dns> ++ <ip address='192.168.122.1' netmask='255.255.255.0'> ++ <dhcp> ++ <range start='192.168.122.2' end='192.168.122.254'/> ++ </dhcp> ++ </ip> ++</network> +diff --git a/tests/networkxml2confdata/nat-network-dns-srv-record-target-newline.xml b/tests/networkxml2confdata/nat-network-dns-srv-record-target-newline.xml +new file mode 100644 +index 0000000..f3f722a +--- /dev/null ++++ b/tests/networkxml2confdata/nat-network-dns-srv-record-target-newline.xml +@@ -0,0 +1,14 @@ ++<network> ++ <name>default</name> ++ <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> ++ <forward dev='eth1' mode='nat'/> ++ <bridge name='virbr0' stp='on' delay='0'/> ++ <dns> ++ <srv service='ldap' protocol='tcp' domain='example.com' target='server.example.com dhcp-script=/tmp/payload'/> ++ </dns> ++ <ip address='192.168.122.1' netmask='255.255.255.0'> ++ <dhcp> ++ <range start='192.168.122.2' end='192.168.122.254'/> ++ </dhcp> ++ </ip> ++</network> +diff --git a/tests/networkxml2xmlout/netboot-proxy-network.xml b/tests/networkxml2confdata/nat-network-dns-txt-record-newline.xml +similarity index 52% +copy from tests/networkxml2xmlout/netboot-proxy-network.xml +copy to tests/networkxml2confdata/nat-network-dns-txt-record-newline.xml +index a5b7c1e..02408a1 100644 +--- a/tests/networkxml2xmlout/netboot-proxy-network.xml ++++ b/tests/networkxml2confdata/nat-network-dns-txt-record-newline.xml +@@ -1,13 +1,14 @@ + <network> +- <name>netboot</name> ++ <name>default</name> + <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid> +- <forward mode='nat'/> +- <bridge name='virbr1' stp='off' delay='1'/> +- <domain name='example.com'/> ++ <forward dev='eth1' mode='nat'/> ++ <bridge name='virbr0' stp='on' delay='0'/> ++ <dns> ++ <txt name='example' value='example value dhcp-script=/tmp/payload'/> ++ </dns> + <ip address='192.168.122.1' netmask='255.255.255.0'> + <dhcp> + <range start='192.168.122.2' end='192.168.122.254'/> +- <bootp file='pxeboot.img' server='10.20.30.40'/> + </dhcp> + </ip> + </network> +diff --git a/tests/networkxml2xmltest.c b/tests/networkxml2xmltest.c +index 0783d84..c828c72 100644 +--- a/tests/networkxml2xmltest.c ++++ b/tests/networkxml2xmltest.c +@@ -126,7 +126,10 @@ mymain(void) + DO_TEST("netboot-proxy-network"); + DO_TEST("netboot-tftp"); + DO_TEST("nat-network-dns-txt-record"); ++ DO_TEST_PARSE_ERROR("nat-network-dns-txt-record-newline"); + DO_TEST("nat-network-dns-srv-record"); ++ DO_TEST_PARSE_ERROR("nat-network-dns-srv-record-domain-newline"); ++ DO_TEST_PARSE_ERROR("nat-network-dns-srv-record-target-newline"); + DO_TEST("nat-network-dns-srv-records"); + DO_TEST("nat-network-dns-srv-record-minimal"); + DO_TEST("nat-network-dns-hosts"); +diff --git a/tests/networkxml2xmlupdatein/dns-txt-record-newline.xml b/tests/networkxml2xmlupdatein/dns-txt-record-newline.xml +new file mode 100644 +index 0000000..13ed040 +--- /dev/null ++++ b/tests/networkxml2xmlupdatein/dns-txt-record-newline.xml +@@ -0,0 +1 @@ ++<txt name='example' value='example value dhcp-script=/tmp/payload'/> +diff --git a/tests/networkxml2xmlupdatein/srv-record-target-newline.xml b/tests/networkxml2xmlupdatein/srv-record-target-newline.xml +new file mode 100644 +index 0000000..f29385d +--- /dev/null ++++ b/tests/networkxml2xmlupdatein/srv-record-target-newline.xml +@@ -0,0 +1 @@ ++<srv service='ldap' protocol='tcp' target='server.example.com dhcp-script=/tmp/payload'/> +diff --git a/tests/networkxml2xmlupdatetest.c b/tests/networkxml2xmlupdatetest.c +index 60931a2..f579699 100644 +--- a/tests/networkxml2xmlupdatetest.c ++++ b/tests/networkxml2xmlupdatetest.c +@@ -288,6 +288,10 @@ mymain(void) + + + section = VIR_NETWORK_SECTION_DNS_TXT; ++ DO_TEST_FAIL("insert-dns-txt-record-newline", ++ "dns-txt-record-newline", ++ "nat-network-dns-txt-record", ++ VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST); + DO_TEST("insert-dns-txt-record", + "dns-txt-record-snowman", + "nat-network-dns-txt-record", +@@ -311,6 +315,10 @@ mymain(void) + "nat-network-dns-txt-record", + "nat-network-dns-txt-modify-ok", + VIR_NETWORK_UPDATE_COMMAND_MODIFY); ++ DO_TEST_FAIL("modify-dns-txt-record-newline", ++ "dns-txt-record-newline", ++ "nat-network-dns-txt-record", ++ VIR_NETWORK_UPDATE_COMMAND_MODIFY); + DO_TEST_FAIL("modify-missing-dns-txt-record", + "dns-txt-record-modify-fail", + "nat-network-dns-txt-record", +@@ -328,6 +336,10 @@ mymain(void) + "nat-network", + "nat-network-dns-srv-record", + VIR_NETWORK_UPDATE_COMMAND_ADD_LAST); ++ DO_TEST_FAIL("append-srv-record-target-newline", ++ "srv-record-target-newline", ++ "nat-network", ++ VIR_NETWORK_UPDATE_COMMAND_ADD_LAST); + DO_TEST_FAIL("add-existing-dns-srv-record", + "srv-record", + "nat-network-dns-srv-record", +diff --git a/tests/virschematest.c b/tests/virschematest.c +index e08ae21..42a6c5c 100644 +--- a/tests/virschematest.c ++++ b/tests/virschematest.c +@@ -301,11 +301,20 @@ static const struct testSchemaEntry schemaInterface[] = { + { .dir = "tests/interfaceschemadata" }, + }; + ++/* skip tests with completely broken XML */ ++static const char *skip_networkxml2confdata[] = { ++ "nat-network-dns-srv-record-domain-newline.xml", ++ "nat-network-dns-srv-record-target-newline.xml", ++ "nat-network-dns-txt-recor-record-newline.xml", ++ NULL, ++}; ++ + static const struct testSchemaEntry schemaNetwork[] = { + { .dir = "src/network" }, + { .dir = "tests/networkxml2xmlin" }, + { .dir = "tests/networkxml2xmlout" }, +- { .dir = "tests/networkxml2confdata" }, ++ { .dir = "tests/networkxml2confdata", ++ .skip = skip_networkxml2confdata }, + { .dir = "examples/xml/test/", + .dirRegex = "testnet.*" }, + { .dir = "tests/networkxml2xmlupdateout" }, diff -Nru libvirt-11.3.0/debian/patches/backport/util-virFileChownFiles-do-not-follow-symlinks.patch libvirt-11.3.0/debian/patches/backport/util-virFileChownFiles-do-not-follow-symlinks.patch --- libvirt-11.3.0/debian/patches/backport/util-virFileChownFiles-do-not-follow-symlinks.patch 1970-01-01 01:00:00.000000000 +0100 +++ libvirt-11.3.0/debian/patches/backport/util-virFileChownFiles-do-not-follow-symlinks.patch 2026-08-30 15:59:50.000000000 +0200 @@ -0,0 +1,68 @@ +From: =?utf-8?b?SEUgV0VJ77yI44Ku44Kr44Kv77yJ?= <[email protected]> +Date: Tue, 28 Jul 2026 17:49:02 +0100 +Subject: util: virFileChownFiles: do not follow symlinks +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +virFileChownFiles() selected entries with virFileIsRegular() (stat(), follows +symlinks) and changed ownership with chown() (follows symlinks). A component +that owns the target directory at a lower privilege (e.g. the swtpm/tss state +directory) can plant a symlink to an arbitrary regular file and have the root +caller chown that file. Use lstat() to skip non-regular entries and +fchownat(..., AT_SYMLINK_NOFOLLOW) so a symlink final component is never +followed. + +Fixes: CVE-2026-63622 +Signed-off-by: HE WEI(ギカク) <[email protected]> +[DB: use g_lstat instead of stat; use lchown instead of + fchownat for portability; added comment] +Reviewed-by: Ján Tomko <[email protected]> +Signed-off-by: Daniel P. Berrangé <[email protected]> +(cherry picked from commit 801160fd414ca2cc402bc01ead09b7ed4c3b8f5b) + +Forwarded: not-needed +Origin: https://gitlab.com/libvirt/libvirt/-/commits/801160fd414ca2cc402bc01ead09b7ed4c3b8f5b +--- + src/util/virfile.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/src/util/virfile.c b/src/util/virfile.c +index 7cab3d0..7abe901 100644 +--- a/src/util/virfile.c ++++ b/src/util/virfile.c +@@ -3179,6 +3179,12 @@ int virDirIsEmpty(const char *path, + * + * Change ownership of all regular files in a directory. + * ++ * This will NOT follow any symlinks, to avoid security risks. ++ * It is assumed the process using content under @name will ++ * be unprivileged, thus less trusted than libvirt. If it is ++ * compromised it might attempt to create symlinks in @name to ++ * escalate privileges on a subsequent call to virFileChownFiles. ++ * + * Returns -1 on error, with error already reported, 0 on success. + */ + #ifndef WIN32 +@@ -3195,13 +3201,19 @@ int virFileChownFiles(const char *name, + + while ((direrr = virDirRead(dir, &ent, name)) > 0) { + g_autofree char *path = NULL; ++ struct stat sb; + + path = g_build_filename(name, ent->d_name, NULL); + +- if (!virFileIsRegular(path)) ++ if (g_lstat(path, &sb) < 0) { ++ virReportSystemError(errno, _("cannot stat '%1$s'"), path); ++ return -1; ++ } ++ ++ if (!S_ISREG(sb.st_mode)) + continue; + +- if (chown(path, uid, gid) < 0) { ++ if (lchown(path, uid, gid) < 0) { + virReportSystemError(errno, + _("cannot chown '%1$s' to (%2$u, %3$u)"), + ent->d_name, (unsigned int) uid, diff -Nru libvirt-11.3.0/debian/patches/series libvirt-11.3.0/debian/patches/series --- libvirt-11.3.0/debian/patches/series 2025-12-07 16:22:24.000000000 +0100 +++ libvirt-11.3.0/debian/patches/series 2026-08-30 15:59:50.000000000 +0200 @@ -15,6 +15,15 @@ backport/qemu-snapshot-Set-umask-for-qemu-img-when-creating-extern.patch backport/qemuxmlconftest-Improve-coverage-of-disk-detect-zeroes-te.patch backport/qemuDomainPrepareDiskSourceData-Setup-detect_zeroes-for-a.patch +backport/qemuMonitorJSONMigrate-Drop-detach-QMP-option.patch +backport/remote-Fix-integer-overflow-in-RPC-handler-for-virNodeGet.patch +backport/conf-reject-line-breaks-in-DNS-TXT-record-values.patch +backport/conf-reject-line-breaks-in-DNS-SRV-domain-and-target.patch +backport/network-reject-line-breaks-before-writing-dnsmasq-DNS-con.patch +backport/tests-cover-line-break-rejection-in-DNS-TXT-and-SRV-recor.patch +backport/src-fix-crash-searching-for-XML-context-string-on-errors.patch +backport/util-virFileChownFiles-do-not-follow-symlinks.patch +backport/storage-create-images-with-a-private-umask-during-qemu-im.patch debian/Debianize-libvirt-guests.patch debian/apparmor_profiles_local_include.patch debian/Use-sensible-editor-by-default.patch
signature.asc
Description: PGP signature

