Compare commits

...

10 Commits

Author SHA1 Message Date
openeuler-ci-bot
19b018f150
!321 fix CVE-2024-4418
From: @jjiacheng 
Reviewed-by: @caozhongwang, @mdsc 
Signed-off-by: @mdsc
2024-05-27 13:08:29 +00:00
jiangjiacheng
797062e4e0 fix CVE-2024-4418
- util: keep track of full GSource object not source ID number
- rpc: mark source returned by virEventGLibAddSocketWatch as unused
- rpc: ensure temporary GSource is removed from client event loop (CVE-2024-4418)
2024-05-24 17:49:22 +08:00
openeuler-ci-bot
96b8edaf60
!289 fix CVE-2024-1441 CVE-2024-2494 CVE-2024-2496 #I97N53 #I9AH6G #I98Z59
From: @caozhongwang 
Reviewed-by: @jjiacheng, @mdsc 
Signed-off-by: @mdsc
2024-04-10 12:18:10 +00:00
caozhongwang
d246bc1314 fix CVE-2024-2496
interface: fix udev_device_get_sysattr_value return value check (CVE-2024-2496)
2024-04-10 15:53:45 +08:00
caozhongwang
696f9590b9 fix CVE-2024-2494
remote: check for negative array lengths before allocation (CVE-2024-2494)
2024-04-10 15:49:38 +08:00
caozhongwang
cda990d1fd fix CVE-2024-1441
vish:Fix off-by-one error in udevListInterfacesByStatus (CVE-2024-1441)
2024-04-10 15:46:18 +08:00
openeuler-ci-bot
e0d5ff1d0d
!195 update the Chinese translation of nwfilter
From: @yezengruan 
Reviewed-by: @kevinzhu1 
Signed-off-by: @kevinzhu1
2022-12-10 09:57:48 +00:00
yezengruan
cdb25f413b update the Chinese translation of nwfilter
Signed-off-by: yezengruan <yezengruan@huawei.com>
2022-12-10 15:26:47 +08:00
openeuler-ci-bot
fd0af4a92a
!168 qemu: Add missing lock in qemuProcessHandleMonitorEOF (CVE-2021-3975)
From: @yezengruan 
Reviewed-by: @kevinzhu1 
Signed-off-by: @kevinzhu1
2022-08-25 09:32:51 +00:00
yezengruan
a03e6f9210 fix CVE-2021-3975 (openeuler !78)
qemu: Add missing lock in qemuProcessHandleMonitorEOF (CVE-2021-3975)

Signed-off-by: yezengruan <yezengruan@huawei.com>
2022-08-25 17:10:49 +08:00
9 changed files with 893 additions and 1 deletions

View File

@ -0,0 +1,89 @@
From 0d5c04534f0e041e9923da1cb37a431ae0d463a8 Mon Sep 17 00:00:00 2001
From: Dmitry Frolov <frolov@swemel.ru>
Date: Tue, 12 Sep 2023 15:56:47 +0300
Subject: [PATCH 8/8] interface: fix udev_device_get_sysattr_value return value
check
Reviewing the code I found that return value of function
udev_device_get_sysattr_value() is dereferenced without a check.
udev_device_get_sysattr_value() may return NULL by number of reasons.
v2: VIR_DEBUG added, replaced STREQ(NULLSTR()) with STREQ_NULLABLE()
v3: More checks added, to skip earlier. More verbose VIR_DEBUG.
Signed-off-by: Dmitry Frolov <frolov@swemel.ru>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
---
src/interface/interface_backend_udev.c | 26 +++++++++++++++++++-------
1 file changed, 19 insertions(+), 7 deletions(-)
diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c
index dde88860d3..00eeee6cc4 100644
--- a/src/interface/interface_backend_udev.c
+++ b/src/interface/interface_backend_udev.c
@@ -23,6 +23,7 @@
#include <dirent.h>
#include <libudev.h>
+#include "virlog.h"
#include "virerror.h"
#include "virfile.h"
#include "datatypes.h"
@@ -41,6 +42,8 @@
#define VIR_FROM_THIS VIR_FROM_INTERFACE
+VIR_LOG_INIT("interface.interface_backend_udev");
+
struct udev_iface_driver {
struct udev *udev;
/* pid file FD, ensures two copies of the driver can't use the same root */
@@ -371,11 +374,20 @@ udevConnectListAllInterfaces(virConnectPtr conn,
const char *macaddr;
virInterfaceDefPtr def;
- path = udev_list_entry_get_name(dev_entry);
- dev = udev_device_new_from_syspath(udev, path);
- name = udev_device_get_sysname(dev);
+ if (!(path = udev_list_entry_get_name(dev_entry))) {
+ VIR_DEBUG("Skipping interface, path == NULL");
+ continue;
+ }
+ if (!(dev = udev_device_new_from_syspath(udev, path))) {
+ VIR_DEBUG("Skipping interface '%s', dev == NULL", path);
+ continue;
+ }
+ if (!(name = udev_device_get_sysname(dev))) {
+ VIR_DEBUG("Skipping interface '%s', name == NULL", path);
+ continue;
+ }
macaddr = udev_device_get_sysattr_value(dev, "address");
- status = STREQ(udev_device_get_sysattr_value(dev, "operstate"), "up");
+ status = STREQ_NULLABLE(udev_device_get_sysattr_value(dev, "operstate"), "up");
def = udevGetMinimalDefForDevice(dev);
if (!virConnectListAllInterfacesCheckACL(conn, def)) {
@@ -1000,9 +1012,9 @@ udevGetIfaceDef(struct udev *udev, const char *name)
/* MTU */
mtu_str = udev_device_get_sysattr_value(dev, "mtu");
- if (virStrToLong_ui(mtu_str, NULL, 10, &mtu) < 0) {
+ if (!mtu_str || virStrToLong_ui(mtu_str, NULL, 10, &mtu) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("Could not parse MTU value '%s'"), mtu_str);
+ _("Could not parse MTU value '%s'"), NULLSTR(mtu_str));
goto error;
}
ifacedef->mtu = mtu;
@@ -1129,7 +1141,7 @@ udevInterfaceIsActive(virInterfacePtr ifinfo)
goto cleanup;
/* Check if it's active or not */
- status = STREQ(udev_device_get_sysattr_value(dev, "operstate"), "up");
+ status = STREQ_NULLABLE(udev_device_get_sysattr_value(dev, "operstate"), "up");
udev_device_unref(dev);
--
2.27.0

View File

@ -101,7 +101,7 @@
Summary: Library providing a simple virtualization API
Name: libvirt
Version: 6.2.0
Release: 19
Release: 25
License: LGPLv2+
URL: https://libvirt.org/
@ -154,6 +154,14 @@ Patch0041: virdevmapper-Don-t-cache-device-mapper-major.patch
Patch0042: virdevmapper-Handle-kernel-without-device-mapper-sup.patch
Patch0043: virsh-Display-vhostuser-socket-path-in-domblklist.patch
Patch0044: nwfilter-fix-crash-when-counting-number-of-network-f.patch
Patch0045: qemu-Add-missing-lock-in-qemuProcessHandleMonitorEOF.patch
Patch0046: update-the-Chinese-translation-of-nwfilter.patch
Patch0047: virsh-Fix-off-by-one-error-in-udevListInterfacesBySt.patch
Patch0048: remote-check-for-negative-array-lengths-before-alloc.patch
Patch0049: interface-fix-udev_device_get_sysattr_value-return-v.patch
Patch0050: util-keep-track-of-full-GSource-object-not-source-ID.patch
Patch0051: rpc-mark-source-returned-by-virEventGLibAddSocketWat.patch
Patch0052: rpc-ensure-temporary-GSource-is-removed-from-client-.patch
Requires: libvirt-daemon = %{version}-%{release}
Requires: libvirt-daemon-config-network = %{version}-%{release}
@ -1888,6 +1896,26 @@ exit 0
%changelog
* Fri May 24 2024 jiangjiacheng <jiangjiacheng@huawei.com>
- util: keep track of full GSource object not source ID number
- rpc: mark source returned by virEventGLibAddSocketWatch as unused
- rpc: ensure temporary GSource is removed from client event loop (CVE-2024-4418)
* Wed Apr 10 2024 caozhongwang <caozhongwang1@huawei.com>
- interface: fix udev_device_get_sysattr_value return value check (CVE-2024-2496)
* Wed Apr 10 2024 caozhongwang <caozhongwang1@huawei.com>
- remote: check for negative array lengths before allocation (CVE-2024-2494)
* Wed Apr 10 2024 caozhongwang <caozhongwang1@huawei.com>
- vish:Fix off-by-one error in udevListInterfacesByStatus (CVE-2024-1441)
* Sat Dec 10 2022 yezengruan <yezengruan@huawei.com>
- update the Chinese translation of nwfilter
* Thu Aug 25 2022 yezengruan <yezengruan@huawei.com>
- qemu: Add missing lock in qemuProcessHandleMonitorEOF (CVE-2021-3975)
* Mon Jun 20 2022 yezengruan <yezengruan@huawei.com>
- nwfilter: fix crash when counting number of network filters (CVE-2022-0897)

View File

@ -0,0 +1,38 @@
From baaf85d9c8b304c6cc95a892fc23962e8175a817 Mon Sep 17 00:00:00 2001
From: Peng Liang <liangpeng10@huawei.com>
Date: Wed, 24 Feb 2021 19:28:23 +0800
Subject: [PATCH] qemu: Add missing lock in qemuProcessHandleMonitorEOF
qemuMonitorUnregister will be called in multiple threads (e.g. threads
in rpc worker pool and the vm event thread). In some cases, it isn't
protected by the monitor lock, which may lead to call g_source_unref
more than one time and a use-after-free problem eventually.
Add the missing lock in qemuProcessHandleMonitorEOF (which is the only
position missing lock of monitor I found).
Suggested-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Peng Liang <liangpeng10@huawei.com>
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
---
src/qemu/qemu_process.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 6b9f6fb860..9701bb398b 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -315,7 +315,9 @@ qemuProcessHandleMonitorEOF(qemuMonitorPtr mon,
/* We don't want this EOF handler to be called over and over while the
* thread is waiting for a job.
*/
+ virObjectLock(mon);
qemuMonitorUnregister(mon);
+ virObjectUnlock(mon);
/* We don't want any cleanup from EOF handler (or any other
* thread) to enter qemu namespace. */
--
2.27.0

View File

@ -0,0 +1,216 @@
From e8245ba93fe1d7d345d10ff9a189b6f5188682b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Fri, 15 Mar 2024 10:47:50 +0000
Subject: [PATCH 7/8] remote: check for negative array lengths before
allocation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
While the C API entry points will validate non-negative lengths
for various parameters, the RPC server de-serialization code
will need to allocate memory for arrays before entering the C
API. These allocations will thus happen before the non-negative
length check is performed.
Passing a negative length to the g_new0 function will usually
result in a crash due to the negative length being treated as
a huge positive number.
This was found and diagnosed by ALT Linux Team with AFLplusplus.
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Found-by: Alexandr Shashkin <dutyrok@altlinux.org>
Co-developed-by: Alexander Kuznetsov <kuznetsovam@altlinux.org>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
src/remote/remote_daemon_dispatch.c | 65 +++++++++++++++++++++++++++++
src/rpc/gendispatch.pl | 5 +++
2 files changed, 70 insertions(+)
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index c5506c2e11..5a1a317452 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -2307,6 +2307,10 @@ remoteDispatchDomainGetSchedulerParameters(virNetServerPtr server G_GNUC_UNUSED,
if (!conn)
goto cleanup;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -2355,6 +2359,10 @@ remoteDispatchDomainGetSchedulerParametersFlags(virNetServerPtr server G_GNUC_UN
if (!conn)
goto cleanup;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -2516,6 +2524,10 @@ remoteDispatchDomainBlockStatsFlags(virNetServerPtr server G_GNUC_UNUSED,
goto cleanup;
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_BLOCK_STATS_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -2750,6 +2762,14 @@ remoteDispatchDomainGetVcpuPinInfo(virNetServerPtr server G_GNUC_UNUSED,
if (!(dom = get_nonnull_domain(conn, args->dom)))
goto cleanup;
+ if (args->ncpumaps < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps must be non-negative"));
+ goto cleanup;
+ }
+ if (args->maplen < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maplen must be non-negative"));
+ goto cleanup;
+ }
if (args->ncpumaps > REMOTE_VCPUINFO_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("ncpumaps > REMOTE_VCPUINFO_MAX"));
goto cleanup;
@@ -2845,6 +2865,11 @@ remoteDispatchDomainGetEmulatorPinInfo(virNetServerPtr server G_GNUC_UNUSED,
if (!(dom = get_nonnull_domain(conn, args->dom)))
goto cleanup;
+ if (args->maplen < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maplen must be non-negative"));
+ goto cleanup;
+ }
+
/* Allocate buffers to take the results */
if (args->maplen > 0 &&
VIR_ALLOC_N(cpumaps, args->maplen) < 0)
@@ -2893,6 +2918,14 @@ remoteDispatchDomainGetVcpus(virNetServerPtr server G_GNUC_UNUSED,
if (!(dom = get_nonnull_domain(conn, args->dom)))
goto cleanup;
+ if (args->maxinfo < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo must be non-negative"));
+ goto cleanup;
+ }
+ if (args->maplen < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo must be non-negative"));
+ goto cleanup;
+ }
if (args->maxinfo > REMOTE_VCPUINFO_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("maxinfo > REMOTE_VCPUINFO_MAX"));
goto cleanup;
@@ -3140,6 +3173,10 @@ remoteDispatchDomainGetMemoryParameters(virNetServerPtr server G_GNUC_UNUSED,
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -3200,6 +3237,10 @@ remoteDispatchDomainGetNumaParameters(virNetServerPtr server G_GNUC_UNUSED,
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_NUMA_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -3260,6 +3301,10 @@ remoteDispatchDomainGetBlkioParameters(virNetServerPtr server G_GNUC_UNUSED,
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -3321,6 +3366,10 @@ remoteDispatchNodeGetCPUStats(virNetServerPtr server G_GNUC_UNUSED,
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_NODE_CPU_STATS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -3389,6 +3438,10 @@ remoteDispatchNodeGetMemoryStats(virNetServerPtr server G_GNUC_UNUSED,
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_NODE_MEMORY_STATS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -3570,6 +3623,10 @@ remoteDispatchDomainGetBlockIoTune(virNetServerPtr server G_GNUC_UNUSED,
if (!conn)
goto cleanup;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_BLOCK_IO_TUNE_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -5128,6 +5185,10 @@ remoteDispatchDomainGetInterfaceParameters(virNetServerPtr server G_GNUC_UNUSED,
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_DOMAIN_INTERFACE_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
@@ -5350,6 +5411,10 @@ remoteDispatchNodeGetMemoryParameters(virNetServerPtr server G_GNUC_UNUSED,
flags = args->flags;
+ if (args->nparams < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams must be non-negative"));
+ goto cleanup;
+ }
if (args->nparams > REMOTE_NODE_MEMORY_PARAMETERS_MAX) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
goto cleanup;
diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
index 590a46ef66..02612f1856 100755
--- a/src/rpc/gendispatch.pl
+++ b/src/rpc/gendispatch.pl
@@ -1074,6 +1074,11 @@ elsif ($mode eq "server") {
print "\n";
if ($single_ret_as_list) {
+ print " if (args->$single_ret_list_max_var < 0) {\n";
+ print " virReportError(VIR_ERR_RPC,\n";
+ print " \"%s\", _(\"max$single_ret_list_name must be non-negative\"));\n";
+ print " goto cleanup;\n";
+ print " }\n";
print " if (args->$single_ret_list_max_var > $single_ret_list_max_define) {\n";
print " virReportError(VIR_ERR_RPC,\n";
print " \"%s\", _(\"max$single_ret_list_name > $single_ret_list_max_define\"));\n";
--
2.27.0

View File

@ -0,0 +1,94 @@
From 351dc443b1c6718b999cc40250ef0b210bcef118 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Tue, 30 Apr 2024 11:51:15 +0100
Subject: [PATCH 3/3] 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
==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 <jtomko@redhat.com>
Reported-by: Martin Shirokov <shirokovmartin@gmail.com>
Tested-by: Martin Shirokov <shirokovmartin@gmail.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
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 f4bb537d50..969c624ae5 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -1619,7 +1619,7 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
#endif /* !WIN32 */
int timeout = -1;
virNetMessagePtr msg = NULL;
- g_autoptr(GSource) G_GNUC_UNUSED source = NULL;
+ g_autoptr(GSource) source = NULL;
GIOCondition ev = 0;
struct virNetClientIOEventData data = {
.client = client,
@@ -1683,6 +1683,18 @@ static int virNetClientIOEventLoop(virNetClientPtr 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.33.0

View File

@ -0,0 +1,57 @@
From 5ab53ff977e17d20b0bf01010f2c3168781a659e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
Date: Fri, 3 Sep 2021 16:36:54 +0200
Subject: [PATCH 2/3] rpc: mark source returned by virEventGLibAddSocketWatch
as unused
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Two users of virEventGLibAddSocketWatch care about the GSource
it returns.
The other three free it by assigning it to an autofreed variable.
Mark them with G_GNUC_UNUSED to make this obvious to the reader
and the compiler.
Signed-off-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
---
src/rpc/virnetclient.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 0a413f0153..f4bb537d50 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -826,7 +826,7 @@ virNetClientIOEventTLS(int fd,
static gboolean
virNetClientTLSHandshake(virNetClientPtr client)
{
- g_autoptr(GSource) source = NULL;
+ g_autoptr(GSource) G_GNUC_UNUSED source = NULL;
GIOCondition ev;
int ret;
@@ -883,7 +883,7 @@ int virNetClientSetTLSSession(virNetClientPtr client,
int ret;
char buf[1];
int len;
- g_autoptr(GSource) source = NULL;
+ g_autoptr(GSource) G_GNUC_UNUSED source = NULL;
#ifndef WIN32
sigset_t oldmask, blockedsigs;
@@ -1619,7 +1619,7 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
#endif /* !WIN32 */
int timeout = -1;
virNetMessagePtr msg = NULL;
- g_autoptr(GSource) source = NULL;
+ g_autoptr(GSource) G_GNUC_UNUSED source = NULL;
GIOCondition ev = 0;
struct virNetClientIOEventData data = {
.client = client,
--
2.33.0

View File

@ -0,0 +1,28 @@
From 0af67000d77afbc4c843709d8119010957855660 Mon Sep 17 00:00:00 2001
From: yezengruan <yezengruan@huawei.com>
Date: Sat, 10 Dec 2022 15:00:48 +0800
Subject: [PATCH] update the Chinese translation of nwfilter
commit e9fd6de8f from upstream.
Signed-off-by: yezengruan <yezengruan@huawei.com>
---
po/zh_CN.mini.po | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/po/zh_CN.mini.po b/po/zh_CN.mini.po
index 3d588abcbe..cd899a429c 100644
--- a/po/zh_CN.mini.po
+++ b/po/zh_CN.mini.po
@@ -18301,7 +18301,7 @@ msgid "nvram device is only supported for PPC64"
msgstr "只为 PPC64 支持 nvram 设备"
msgid "nwfilter is in use"
-msgstr "nwfilter 未使用"
+msgstr "nwfilter 使用中"
msgid "occupied"
msgstr "已占用"
--
2.27.0

View File

@ -0,0 +1,303 @@
From 4160ede0261dfccd8156721a22fa48d9cd3c448a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
Date: Tue, 28 Jul 2020 15:54:13 +0100
Subject: [PATCH 1/3] util: keep track of full GSource object not source ID
number
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The source ID number is an alternative way to identify a source that has
been added to a GMainContext. Internally when a source ID is given, glib
will lookup the corresponding GSource and use that. The use of a source
ID is racy in some cases though, because it is invalid to continue to
use an ID number after the GSource has been removed. It is thus safer
to use the GSource object directly and have full control over the ref
counting and thus cleanup.
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
src/rpc/virnetclient.c | 27 +++++++------
src/util/vireventglib.c | 73 +++++++++++++++++++++++-------------
src/util/vireventglibwatch.c | 19 ++++++----
src/util/vireventglibwatch.h | 13 ++++---
4 files changed, 79 insertions(+), 53 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 1c5bef86a1..0a413f0153 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -826,6 +826,7 @@ virNetClientIOEventTLS(int fd,
static gboolean
virNetClientTLSHandshake(virNetClientPtr client)
{
+ g_autoptr(GSource) source = NULL;
GIOCondition ev;
int ret;
@@ -840,10 +841,10 @@ virNetClientTLSHandshake(virNetClientPtr client)
else
ev = G_IO_OUT;
- virEventGLibAddSocketWatch(virNetSocketGetFD(client->sock),
- ev,
- client->eventCtx,
- virNetClientIOEventTLS, client, NULL);
+ source = virEventGLibAddSocketWatch(virNetSocketGetFD(client->sock),
+ ev,
+ client->eventCtx,
+ virNetClientIOEventTLS, client, NULL);
return TRUE;
}
@@ -882,6 +883,7 @@ int virNetClientSetTLSSession(virNetClientPtr client,
int ret;
char buf[1];
int len;
+ g_autoptr(GSource) source = NULL;
#ifndef WIN32
sigset_t oldmask, blockedsigs;
@@ -934,10 +936,10 @@ int virNetClientSetTLSSession(virNetClientPtr client,
* etc. If we make the grade, it will send us a '\1' byte.
*/
- virEventGLibAddSocketWatch(virNetSocketGetFD(client->sock),
- G_IO_IN,
- client->eventCtx,
- virNetClientIOEventTLSConfirm, client, NULL);
+ source = virEventGLibAddSocketWatch(virNetSocketGetFD(client->sock),
+ G_IO_IN,
+ client->eventCtx,
+ virNetClientIOEventTLSConfirm, client, NULL);
#ifndef WIN32
/* Block SIGWINCH from interrupting poll in curses programs */
@@ -1617,6 +1619,7 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
#endif /* !WIN32 */
int timeout = -1;
virNetMessagePtr msg = NULL;
+ g_autoptr(GSource) source = NULL;
GIOCondition ev = 0;
struct virNetClientIOEventData data = {
.client = client,
@@ -1651,10 +1654,10 @@ static int virNetClientIOEventLoop(virNetClientPtr client,
if (client->nstreams)
ev |= G_IO_IN;
- virEventGLibAddSocketWatch(virNetSocketGetFD(client->sock),
- ev,
- client->eventCtx,
- virNetClientIOEventFD, &data, NULL);
+ source = virEventGLibAddSocketWatch(virNetSocketGetFD(client->sock),
+ ev,
+ client->eventCtx,
+ virNetClientIOEventFD, &data, NULL);
/* Release lock while poll'ing so other threads
* can stuff themselves on the queue */
diff --git a/src/util/vireventglib.c b/src/util/vireventglib.c
index 803332a6f8..6e334b3398 100644
--- a/src/util/vireventglib.c
+++ b/src/util/vireventglib.c
@@ -45,7 +45,7 @@ struct virEventGLibHandle
int fd;
int events;
int removed;
- guint source;
+ GSource *source;
virEventHandleCallback cb;
void *opaque;
virFreeCallback ff;
@@ -56,7 +56,7 @@ struct virEventGLibTimeout
int timer;
int interval;
int removed;
- guint source;
+ GSource *source;
virEventTimeoutCallback cb;
void *opaque;
virFreeCallback ff;
@@ -210,23 +210,25 @@ virEventGLibHandleUpdate(int watch,
if (events == data->events)
goto cleanup;
- if (data->source != 0) {
- VIR_DEBUG("Removed old handle watch=%d", data->source);
- g_source_remove(data->source);
+ if (data->source != NULL) {
+ VIR_DEBUG("Removed old handle source=%p", data->source);
+ g_source_destroy(data->source);
+ g_source_unref(data->source);
}
data->source = virEventGLibAddSocketWatch(
data->fd, cond, NULL, virEventGLibHandleDispatch, data, NULL);
data->events = events;
- VIR_DEBUG("Added new handle watch=%d", data->source);
+ VIR_DEBUG("Added new handle source=%p", data->source);
} else {
- if (data->source == 0)
+ if (data->source == NULL)
goto cleanup;
- VIR_DEBUG("Removed old handle watch=%d", data->source);
- g_source_remove(data->source);
- data->source = 0;
+ VIR_DEBUG("Removed old handle source=%p", data->source);
+ g_source_destroy(data->source);
+ g_source_unref(data->source);
+ data->source = NULL;
data->events = 0;
}
@@ -272,9 +274,10 @@ virEventGLibHandleRemove(int watch)
VIR_DEBUG("Remove handle data=%p watch=%d fd=%d",
data, watch, data->fd);
- if (data->source != 0) {
- g_source_remove(data->source);
- data->source = 0;
+ if (data->source != NULL) {
+ g_source_destroy(data->source);
+ g_source_unref(data->source);
+ data->source = NULL;
data->events = 0;
}
@@ -309,6 +312,22 @@ virEventGLibTimeoutDispatch(void *opaque)
return TRUE;
}
+
+static GSource *
+virEventGLibTimeoutCreate(int interval,
+ struct virEventGLibTimeout *data)
+{
+ GSource *source = g_timeout_source_new(interval);
+
+ g_source_set_callback(source,
+ virEventGLibTimeoutDispatch,
+ data, NULL);
+ g_source_attach(source, NULL);
+
+ return source;
+}
+
+
static int
virEventGLibTimeoutAdd(int interval,
virEventTimeoutCallback cb,
@@ -327,9 +346,7 @@ virEventGLibTimeoutAdd(int interval,
data->opaque = opaque;
data->ff = ff;
if (interval >= 0)
- data->source = g_timeout_add(interval,
- virEventGLibTimeoutDispatch,
- data);
+ data->source = virEventGLibTimeoutCreate(interval, data);
g_ptr_array_add(timeouts, data);
@@ -390,19 +407,20 @@ virEventGLibTimeoutUpdate(int timer,
VIR_DEBUG("Update timeout data=%p timer=%d interval=%d ms", data, timer, interval);
if (interval >= 0) {
- if (data->source != 0)
- g_source_remove(data->source);
+ if (data->source != NULL) {
+ g_source_destroy(data->source);
+ g_source_unref(data->source);
+ }
data->interval = interval;
- data->source = g_timeout_add(data->interval,
- virEventGLibTimeoutDispatch,
- data);
+ data->source = virEventGLibTimeoutCreate(interval, data);
} else {
- if (data->source == 0)
+ if (data->source == NULL)
goto cleanup;
- g_source_remove(data->source);
- data->source = 0;
+ g_source_destroy(data->source);
+ g_source_unref(data->source);
+ data->source = NULL;
}
cleanup:
@@ -448,9 +466,10 @@ virEventGLibTimeoutRemove(int timer)
VIR_DEBUG("Remove timeout data=%p timer=%d",
data, timer);
- if (data->source != 0) {
- g_source_remove(data->source);
- data->source = 0;
+ if (data->source != NULL) {
+ g_source_destroy(data->source);
+ g_source_unref(data->source);
+ data->source = NULL;
}
/* since the actual timeout deletion is done asynchronously, a timeoutUpdate call may
diff --git a/src/util/vireventglibwatch.c b/src/util/vireventglibwatch.c
index 178707f6b7..b7f3a8786a 100644
--- a/src/util/vireventglibwatch.c
+++ b/src/util/vireventglibwatch.c
@@ -233,17 +233,20 @@ GSource *virEventGLibCreateSocketWatch(int fd,
#endif /* WIN32 */
-guint virEventGLibAddSocketWatch(int fd,
- GIOCondition condition,
- GMainContext *context,
- virEventGLibSocketFunc func,
- gpointer opaque,
- GDestroyNotify notify)
+GSource *
+virEventGLibAddSocketWatch(int fd,
+ GIOCondition condition,
+ GMainContext *context,
+ virEventGLibSocketFunc func,
+ gpointer opaque,
+ GDestroyNotify notify)
{
- g_autoptr(GSource) source = NULL;
+ GSource *source = NULL;
source = virEventGLibCreateSocketWatch(fd, condition);
g_source_set_callback(source, (GSourceFunc)func, opaque, notify);
- return g_source_attach(source, context);
+ g_source_attach(source, context);
+
+ return source;
}
diff --git a/src/util/vireventglibwatch.h b/src/util/vireventglibwatch.h
index 2f7e61cfba..f57be1f503 100644
--- a/src/util/vireventglibwatch.h
+++ b/src/util/vireventglibwatch.h
@@ -40,9 +40,10 @@ typedef gboolean (*virEventGLibSocketFunc)(int fd,
GIOCondition condition,
gpointer data);
-guint virEventGLibAddSocketWatch(int fd,
- GIOCondition condition,
- GMainContext *context,
- virEventGLibSocketFunc func,
- gpointer opaque,
- GDestroyNotify notify);
+GSource *virEventGLibAddSocketWatch(int fd,
+ GIOCondition condition,
+ GMainContext *context,
+ virEventGLibSocketFunc func,
+ gpointer opaque,
+ GDestroyNotify notify)
+ G_GNUC_WARN_UNUSED_RESULT;
--
2.33.0

View File

@ -0,0 +1,39 @@
From 001ede185f96d359481495a4016fcd0cffb2e1b0 Mon Sep 17 00:00:00 2001
From: Martin Kletzander <mkletzan@redhat.com>
Date: Tue, 27 Feb 2024 16:20:12 +0100
Subject: [PATCH 6/8] virsh:Fix off-by-one error in udevListInterfacesByStatus
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Ever since this function was introduced in 2012 it could've tried
filling in an extra interface name. That was made worse in 2019 when
the caller functions started accepting NULL arrays of size 0.
This is assigned CVE-2024-1441.
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
Reported-by: Alexander Kuznetsov <kuznetsovam@altlinux.org>
Fixes: 5a33366f5c0b18c93d161bd144f9f079de4ac8ca
Fixes: d6064e2759a24e0802f363e3a810dc5a7d7ebb15
Reviewed-by: Ján Tomko <jtomko@redhat.com>
---
src/interface/interface_backend_udev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/interface/interface_backend_udev.c b/src/interface/interface_backend_udev.c
index e388f98536..dde88860d3 100644
--- a/src/interface/interface_backend_udev.c
+++ b/src/interface/interface_backend_udev.c
@@ -221,7 +221,7 @@ udevListInterfacesByStatus(virConnectPtr conn,
virInterfaceDefPtr def;
/* Ensure we won't exceed the size of our array */
- if (count > names_len)
+ if (count >= names_len)
break;
path = udev_list_entry_get_name(dev_entry);
--
2.27.0