diff -Nru libvirt-8.0.0/debian/changelog libvirt-8.0.0/debian/changelog --- libvirt-8.0.0/debian/changelog 2024-03-27 15:47:46.000000000 +0000 +++ libvirt-8.0.0/debian/changelog 2024-04-12 17:48:21.000000000 +0000 @@ -1,3 +1,20 @@ +libvirt (8.0.0-1ubuntu7.10) jammy-security; urgency=medium + + * SECURITY UPDATE: off-by-one in udevListInterfacesByStatus() + - debian/patches/CVE-2024-1441.patch: properly check count in + src/interface/interface_backend_udev.c. + - CVE-2024-1441 + * SECURITY UPDATE: crash in RPC library + - debian/patches/CVE-2024-2494.patch: check values in + src/remote/remote_daemon_dispatch.c, src/rpc/gendispatch.pl. + - CVE-2024-2494 + * SECURITY UPDATE: null pointer deref in udevConnectListAllInterfaces() + - debian/patches/CVE-2024-2496.patch: fix udev_device_get_sysattr_value + return value check in src/interface/interface_backend_udev.c. + - CVE-2024-2496 + + -- Marc Deslauriers Fri, 12 Apr 2024 13:48:21 -0400 + libvirt (8.0.0-1ubuntu7.9) jammy; urgency=medium * d/p/u/lp2059272-qemu-Fix-potential-crash-during-driver-cleanup.patch: diff -Nru libvirt-8.0.0/debian/patches/CVE-2024-1441.patch libvirt-8.0.0/debian/patches/CVE-2024-1441.patch --- libvirt-8.0.0/debian/patches/CVE-2024-1441.patch 1970-01-01 00:00:00.000000000 +0000 +++ libvirt-8.0.0/debian/patches/CVE-2024-1441.patch 2024-04-12 17:44:36.000000000 +0000 @@ -0,0 +1,59 @@ +From c664015fe3a7bf59db26686e9ed69af011c6ebb8 Mon Sep 17 00:00:00 2001 +From: Martin Kletzander +Date: Tue, 27 Feb 2024 16:20:12 +0100 +Subject: [PATCH] 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 +Reported-by: Alexander Kuznetsov +Fixes: 5a33366f5c0b18c93d161bd144f9f079de4ac8ca +Fixes: d6064e2759a24e0802f363e3a810dc5a7d7ebb15 +Reviewed-by: Ján Tomko +--- + NEWS.rst | 15 +++++++++++++++ + src/interface/interface_backend_udev.c | 2 +- + 2 files changed, 16 insertions(+), 1 deletion(-) + +#--- a/NEWS.rst +#+++ b/NEWS.rst +#@@ -312,6 +312,21 @@ v9.2.0 (2023-04-01) +# v9.1.0 (2023-03-01) +# =================== +# +#+ * ``CVE-2024-1441``: Fix off-by-one error leading to a crash +#+ +#+ In **libvirt-1.0.0** there were couple of interface listing APIs +#+ introduced which had an off-by-one error. That error could lead to a +#+ very rare crash if an array was passed to those functions which did +#+ not fit all the interfaces. +#+ +#+ In **libvirt-5.10** a check for non-NULL arrays has been adjusted to +#+ allow for NULL arrays with size 0 instead of rejecting all NULL +#+ arrays. However that made the above issue significantly worse since +#+ that off-by-one error now did not write beyond an array, but +#+ dereferenced said NULL pointer making the crash certain in a +#+ specific scenario in which a NULL array of size 0 was passed to the +#+ aforementioned functions. +#+ +# * **Removed features** +# +# * vbox: removed support for version 5.2 and 6.0 APIs +--- a/src/interface/interface_backend_udev.c ++++ b/src/interface/interface_backend_udev.c +@@ -220,7 +220,7 @@ udevListInterfacesByStatus(virConnectPtr + g_autoptr(virInterfaceDef) def = NULL; + + /* 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); diff -Nru libvirt-8.0.0/debian/patches/CVE-2024-2494.patch libvirt-8.0.0/debian/patches/CVE-2024-2494.patch --- libvirt-8.0.0/debian/patches/CVE-2024-2494.patch 1970-01-01 00:00:00.000000000 +0000 +++ libvirt-8.0.0/debian/patches/CVE-2024-2494.patch 2024-04-12 17:44:44.000000000 +0000 @@ -0,0 +1,209 @@ +From 8a3f8d957507c1f8223fdcf25a3ff885b15557f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Fri, 15 Mar 2024 10:47:50 +0000 +Subject: [PATCH] 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. + +CVE-2024-2494 +Reviewed-by: Michal Privoznik +Found-by: Alexandr Shashkin +Co-developed-by: Alexander Kuznetsov +Signed-off-by: Daniel P. Berrangé +--- + src/remote/remote_daemon_dispatch.c | 65 +++++++++++++++++++++++++++++ + src/rpc/gendispatch.pl | 5 +++ + 2 files changed, 70 insertions(+) + +--- a/src/remote/remote_daemon_dispatch.c ++++ b/src/remote/remote_daemon_dispatch.c +@@ -2306,6 +2306,10 @@ remoteDispatchDomainGetSchedulerParamete + 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; +@@ -2354,6 +2358,10 @@ remoteDispatchDomainGetSchedulerParamete + 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; +@@ -2512,6 +2520,10 @@ remoteDispatchDomainBlockStatsFlags(virN + 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; +@@ -2737,6 +2749,14 @@ remoteDispatchDomainGetVcpuPinInfo(virNe + 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; +@@ -2831,6 +2851,11 @@ remoteDispatchDomainGetEmulatorPinInfo(v + 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) + cpumaps = g_new0(unsigned char, args->maplen); +@@ -2878,6 +2903,14 @@ remoteDispatchDomainGetVcpus(virNetServe + 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; +@@ -3117,6 +3150,10 @@ remoteDispatchDomainGetMemoryParameters( + + 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; +@@ -3177,6 +3214,10 @@ remoteDispatchDomainGetNumaParameters(vi + + 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; +@@ -3237,6 +3278,10 @@ remoteDispatchDomainGetBlkioParameters(v + + 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; +@@ -3298,6 +3343,10 @@ remoteDispatchNodeGetCPUStats(virNetServ + + 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; +@@ -3365,6 +3414,10 @@ remoteDispatchNodeGetMemoryStats(virNetS + + 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; +@@ -3545,6 +3598,10 @@ remoteDispatchDomainGetBlockIoTune(virNe + 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; +@@ -5087,6 +5144,10 @@ remoteDispatchDomainGetInterfaceParamete + + 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; +@@ -5307,6 +5368,10 @@ remoteDispatchNodeGetMemoryParameters(vi + + 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; +--- 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"; diff -Nru libvirt-8.0.0/debian/patches/CVE-2024-2496.patch libvirt-8.0.0/debian/patches/CVE-2024-2496.patch --- libvirt-8.0.0/debian/patches/CVE-2024-2496.patch 1970-01-01 00:00:00.000000000 +0000 +++ libvirt-8.0.0/debian/patches/CVE-2024-2496.patch 2024-04-12 17:47:03.000000000 +0000 @@ -0,0 +1,86 @@ +Backport of: + +From 2ca94317ac642a70921947150ced8acc674ccdc8 Mon Sep 17 00:00:00 2001 +From: Dmitry Frolov +Date: Tue, 12 Sep 2023 15:56:47 +0300 +Subject: [PATCH] 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 +Reviewed-by: Martin Kletzander +--- + src/interface/interface_backend_udev.c | 26 +++++++++++++++++++------- + 1 file changed, 19 insertions(+), 7 deletions(-) + +--- a/src/interface/interface_backend_udev.c ++++ b/src/interface/interface_backend_udev.c +@@ -23,6 +23,7 @@ + #include + #include + ++#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 */ +@@ -355,11 +358,20 @@ udevConnectListAllInterfaces(virConnectP + const char *macaddr; + g_autoptr(virInterfaceDef) def = NULL; + +- 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)) { +@@ -969,9 +981,9 @@ udevGetIfaceDef(struct udev *udev, const + + /* 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 '%1$s'"), NULLSTR(mtu_str)); + goto error; + } + ifacedef->mtu = mtu; +@@ -1094,7 +1106,7 @@ udevInterfaceIsActive(virInterfacePtr if + 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); + diff -Nru libvirt-8.0.0/debian/patches/series libvirt-8.0.0/debian/patches/series --- libvirt-8.0.0/debian/patches/series 2024-03-27 15:46:50.000000000 +0000 +++ libvirt-8.0.0/debian/patches/series 2024-04-12 17:44:47.000000000 +0000 @@ -72,3 +72,6 @@ CVE-2023-2700.patch ubuntu/lp-2024114-Avoid-memleak-in-virNodeDeviceGetPCIVPDDynamicCap.patch ubuntu/lp2059272-qemu-Fix-potential-crash-during-driver-cleanup.patch +CVE-2024-1441.patch +CVE-2024-2494.patch +CVE-2024-2496.patch