From c64b17866390b4e4972bb08376b0869db19a1028 Mon Sep 17 00:00:00 2001 From: Jiri Denemark Date: Thu, 6 Jun 2024 16:27:11 +0200 Subject: [PATCH] libvirt-8.0.0-23.2.el8 --- .libvirt.metadata | 1 + ...ce-is-removed-from-client-event-loop.patch | 101 ++++++++++++++++++ ...urn-for-virProcessKillPainfullyDelay.patch | 39 +++++++ libvirt.spec | 8 +- 4 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 .libvirt.metadata create mode 100644 libvirt-rpc-ensure-temporary-GSource-is-removed-from-client-event-loop.patch create mode 100644 libvirt-util-Fix-error-return-for-virProcessKillPainfullyDelay.patch diff --git a/.libvirt.metadata b/.libvirt.metadata new file mode 100644 index 0000000..7d771a9 --- /dev/null +++ b/.libvirt.metadata @@ -0,0 +1 @@ +e440412e9b45d7e24f0ef492d8edf5cf2cbd3f4c libvirt-8.0.0.tar.xz diff --git a/libvirt-rpc-ensure-temporary-GSource-is-removed-from-client-event-loop.patch b/libvirt-rpc-ensure-temporary-GSource-is-removed-from-client-event-loop.patch new file mode 100644 index 0000000..ce6135f --- /dev/null +++ b/libvirt-rpc-ensure-temporary-GSource-is-removed-from-client-event-loop.patch @@ -0,0 +1,101 @@ +From b84d0a699f3976644d3090562ce62ede55335fbc Mon Sep 17 00:00:00 2001 +Message-ID: +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Tue, 30 Apr 2024 11:51:15 +0100 +Subject: [PATCH] rpc: ensure temporary GSource is removed from client event + loop +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Users are seeing periodic segfaults from libvirt client apps, +especially thread heavy ones like virt-manager. A typical +stack trace would end up in the virNetClientIOEventFD method, +with illegal access to stale stack data. eg + +==238721==ERROR: AddressSanitizer: stack-use-after-return on address 0x75cd18709788 at pc 0x75cd3111f907 bp 0x75cd181ff550 sp 0x75cd181ff548 +WRITE of size 4 at 0x75cd18709788 thread T11 + #0 0x75cd3111f906 in virNetClientIOEventFD /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/rpc/virnetclient.c:1634:15 + #1 0x75cd3210d198 (/usr/lib/libglib-2.0.so.0+0x5a198) (BuildId: 0a2311dfbbc6c215dc36f4b6bdd2b4b6fbae55a2) + #2 0x75cd3216c3be (/usr/lib/libglib-2.0.so.0+0xb93be) (BuildId: 0a2311dfbbc6c215dc36f4b6bdd2b4b6fbae55a2) + #3 0x75cd3210ddc6 in g_main_loop_run (/usr/lib/libglib-2.0.so.0+0x5adc6) (BuildId: 0a2311dfbbc6c215dc36f4b6bdd2b4b6fbae55a2) + #4 0x75cd3111a47c in virNetClientIOEventLoop /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/rpc/virnetclient.c:1722:9 + #5 0x75cd3111a47c in virNetClientIO /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/rpc/virnetclient.c:2002:10 + #6 0x75cd3111a47c in virNetClientSendInternal /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/rpc/virnetclient.c:2170:11 + #7 0x75cd311198a8 in virNetClientSendWithReply /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/rpc/virnetclient.c:2198:11 + #8 0x75cd31111653 in virNetClientProgramCall /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/rpc/virnetclientprogram.c:318:9 + #9 0x75cd31241c8f in callFull /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/remote/remote_driver.c:6054:10 + #10 0x75cd31241c8f in call /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/remote/remote_driver.c:6076:12 + #11 0x75cd31241c8f in remoteNetworkGetXMLDesc /usr/src/debug/libvirt/libvirt-10.2.0/build/src/remote/remote_client_bodies.h:5959:9 + #12 0x75cd31410ff7 in virNetworkGetXMLDesc /usr/src/debug/libvirt/libvirt-10.2.0/build/../src/libvirt-network.c:952:15 + +The root cause is a bad assumption in the virNetClientIOEventLoop +method. This method is run by whichever thread currently owns the +buck, and is responsible for handling I/O. Inside a for(;;) loop, +this method creates a temporary GSource, adds it to the event loop +and runs g_main_loop_run(). When I/O is ready, the GSource callback +(virNetClientIOEventFD) will fire and call g_main_loop_quit(), and +return G_SOURCE_REMOVE which results in the temporary GSource being +destroyed. A g_autoptr() will then remove the last reference. + +What was overlooked, is that a second thread can come along and +while it can't enter virNetClientIOEventLoop, it will register an +idle source that uses virNetClientIOWakeup to interrupt the +original thread's 'g_main_loop_run' call. When this happens the +virNetClientIOEventFD callback never runs, and so the temporary +GSource is not destroyed. The g_autoptr() will remove a reference, +but by virtue of still being attached to the event context, there +is an extra reference held causing GSource to be leaked. The +next time 'g_main_loop_run' is called, the original GSource will +trigger its callback, and access data that was allocated on the +stack by the previous thread, and likely SEGV. + +To solve this, the thread calling 'g_main_loop_run' must call +g_source_destroy, immediately upon return, to guarantee that +the temporary GSource is removed. + +CVE-2024-4418 +Reviewed-by: Ján Tomko +Reported-by: Martin Shirokov +Tested-by: Martin Shirokov +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 8074d64dc2eca846d6a61efe1a9b7428a0ce1dd1) +Signed-off-by: Jiri Denemark +--- + src/rpc/virnetclient.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c +index f526ad89ec..b9490072c3 100644 +--- a/src/rpc/virnetclient.c ++++ b/src/rpc/virnetclient.c +@@ -1664,7 +1664,7 @@ static int virNetClientIOEventLoop(virNetClient *client, + #endif /* !WIN32 */ + int timeout = -1; + virNetMessage *msg = NULL; +- g_autoptr(GSource) G_GNUC_UNUSED source = NULL; ++ g_autoptr(GSource) source = NULL; + GIOCondition ev = 0; + struct virNetClientIOEventData data = { + .client = client, +@@ -1728,6 +1728,18 @@ static int virNetClientIOEventLoop(virNetClient *client, + + g_main_loop_run(client->eventLoop); + ++ /* ++ * If virNetClientIOEventFD ran, this GSource will already be ++ * destroyed due to G_SOURCE_REMOVE. It is harmless to re-destroy ++ * it, since we still own a reference. ++ * ++ * If virNetClientIOWakeup ran, it will have interrupted the ++ * g_main_loop_run call, before virNetClientIOEventFD could ++ * run, and thus the GSource is still registered, and we need ++ * to destroy it since it is referencing stack memory for 'data' ++ */ ++ g_source_destroy(source); ++ + #ifndef WIN32 + ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL)); + #endif /* !WIN32 */ +-- +2.45.1 diff --git a/libvirt-util-Fix-error-return-for-virProcessKillPainfullyDelay.patch b/libvirt-util-Fix-error-return-for-virProcessKillPainfullyDelay.patch new file mode 100644 index 0000000..a67483d --- /dev/null +++ b/libvirt-util-Fix-error-return-for-virProcessKillPainfullyDelay.patch @@ -0,0 +1,39 @@ +From ffbae27bd15ae9475fd4f0e79b492a7e03bca93e Mon Sep 17 00:00:00 2001 +Message-ID: +From: Jonathon Jongsma +Date: Fri, 22 Sep 2023 14:23:10 -0500 +Subject: [PATCH] util: Fix error return for virProcessKillPainfullyDelay() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 93af79fb removed a cleanup label in favor of returning error +values directly in certain cases. But the final return value was changed +from -1 to 0. If we get to the end of the function, that means that +we've waited for the process to exit but it still exists. So we should +return -1. The error message was still being set correctly, but we were +returning a success status (0). + +Signed-off-by: Jonathon Jongsma +Reviewed-by: Ján Tomko +(cherry picked from commit 51a074e74c6ef2fb95e6f53d41315e3f1e00be77) +https://issues.redhat.com/browse/RHEL-36064 +--- + src/util/virprocess.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/util/virprocess.c b/src/util/virprocess.c +index b559a4257e..f3933a2d16 100644 +--- a/src/util/virprocess.c ++++ b/src/util/virprocess.c +@@ -471,7 +471,7 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay, boo + _("Failed to terminate process %lld with SIG%s"), + (long long)pid, signame); + +- return 0; ++ return -1; + } + + +-- +2.45.1 diff --git a/libvirt.spec b/libvirt.spec index 75ccaeb..01ab965 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -210,7 +210,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 8.0.0 -Release: 23.1%{?dist}%{?extra_release} +Release: 23.2%{?dist}%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -319,6 +319,8 @@ Patch96: libvirt-nodedev-update-transient-mdevs.patch Patch97: libvirt-lib-Set-up-cpuset-controller-for-restrictive-numatune.patch Patch98: libvirt-virnuma-Avoid-integer-overflow-in-virNumaGetPages.patch Patch99: libvirt-remote-check-for-negative-array-lengths-before-allocation.patch +Patch100: libvirt-util-Fix-error-return-for-virProcessKillPainfullyDelay.patch +Patch101: libvirt-rpc-ensure-temporary-GSource-is-removed-from-client-event-loop.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2198,6 +2200,10 @@ exit 0 %changelog +* Thu Jun 6 2024 Jiri Denemark - 8.0.0-23.2.el8 +- util: Fix error return for virProcessKillPainfullyDelay() (RHEL-36064) +- rpc: ensure temporary GSource is removed from client event loop (CVE-2024-4418) + * Tue Apr 9 2024 Jiri Denemark - 8.0.0-23.1.el8 - remote: check for negative array lengths before allocation (CVE-2024-2494)