From b03b5ee46aa2e613fd502f36810f9a1ed7a898d0 Mon Sep 17 00:00:00 2001 From: Jiabo Feng Date: Wed, 10 Apr 2024 21:35:19 +0800 Subject: [PATCH] libvirt update to version 9.10.0-5: - hotpatch: if hotpatch_path not in qemu.conf,the hotpatch doesn't antoload - remote: check for negative array lengths before allocation - Fix off-by-one error in udevListInterfacesByStatus - Fix warnings found by clang - hotpatch: virsh support autoload mode - domain: add logs for virDomainHotpatchManage - hotpatch: check vm id and pid before using hotpatch api - hotpatch: implement hotpatch virsh api - hotpatch: introduce hotpatch async job flag - hotpatch: Implement qemuDomainHotpatchManage - Hotpatch: introduce DomainHotpatchManage API Signed-off-by: Jiabo Feng (cherry picked from commit f5ca4aa04e62792f0178eb64eb3c769c33435bb3) --- ...-error-in-udevListInterfacesByStatus.patch | 39 ++ Fix-warnings-found-by-clang.patch | 30 ++ ...h-introduce-DomainHotpatchManage-API.patch | 224 ++++++++++ ...add-logs-for-virDomainHotpatchManage.patch | 45 ++ ...h-Implement-qemuDomainHotpatchManage.patch | 387 ++++++++++++++++++ ...m-id-and-pid-before-using-hotpatch-a.patch | 151 +++++++ ...atch_path-not-in-qemu.conf-the-hotpa.patch | 34 ++ hotpatch-implement-hotpatch-virsh-api.patch | 110 +++++ ...ch-introduce-hotpatch-async-job-flag.patch | 161 ++++++++ hotpatch-virsh-support-autoload-mode.patch | 302 ++++++++++++++ libvirt.spec | 26 +- ...-negative-array-lengths-before-alloc.patch | 216 ++++++++++ 12 files changed, 1724 insertions(+), 1 deletion(-) create mode 100644 Fix-off-by-one-error-in-udevListInterfacesByStatus.patch create mode 100644 Fix-warnings-found-by-clang.patch create mode 100644 Hotpatch-introduce-DomainHotpatchManage-API.patch create mode 100644 domain-add-logs-for-virDomainHotpatchManage.patch create mode 100644 hotpatch-Implement-qemuDomainHotpatchManage.patch create mode 100644 hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch create mode 100644 hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch create mode 100644 hotpatch-implement-hotpatch-virsh-api.patch create mode 100644 hotpatch-introduce-hotpatch-async-job-flag.patch create mode 100644 hotpatch-virsh-support-autoload-mode.patch create mode 100644 remote-check-for-negative-array-lengths-before-alloc.patch diff --git a/Fix-off-by-one-error-in-udevListInterfacesByStatus.patch b/Fix-off-by-one-error-in-udevListInterfacesByStatus.patch new file mode 100644 index 0000000..7cf445b --- /dev/null +++ b/Fix-off-by-one-error-in-udevListInterfacesByStatus.patch @@ -0,0 +1,39 @@ +From 0f082f9d3df0b1c2b63c2b5ad3201e08d1ffe449 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 +--- + 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 fb6799ed94..4091483060 100644 +--- a/src/interface/interface_backend_udev.c ++++ b/src/interface/interface_backend_udev.c +@@ -222,7 +222,7 @@ udevListInterfacesByStatus(virConnectPtr conn, + 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); +-- +2.27.0 + diff --git a/Fix-warnings-found-by-clang.patch b/Fix-warnings-found-by-clang.patch new file mode 100644 index 0000000..dd2e7b4 --- /dev/null +++ b/Fix-warnings-found-by-clang.patch @@ -0,0 +1,30 @@ +From f3bee7ca84e0e7f915ad425935e6279b227a00a6 Mon Sep 17 00:00:00 2001 +From: Chenxi Mao +Date: Tue, 4 Apr 2023 14:25:17 +0800 +Subject: [PATCH] Fix warnings found by clang + +Warnings found if build with clang 15: + +[ 257s] ../../src/qemu/qemu_hotpatch.c:217:22: error: unused variable 'libvirtd_conf' [-Werror,-Wunused-variable] +[ 257s] g_autofree char *libvirtd_conf = NULL; + +Signed-off-by: Chenxi Mao +--- + src/qemu/qemu_hotpatch.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c +index 0259ae76c8..29d13db030 100644 +--- a/src/qemu/qemu_hotpatch.c ++++ b/src/qemu/qemu_hotpatch.c +@@ -214,7 +214,6 @@ qemuDomainHotpatchAutoload(virDomainObj *vm, char *hotpatch_path) + g_auto(GStrv) applied_patches = NULL; + g_auto(GStrv) lines = NULL; + g_autofree char *applied_patch = NULL; +- g_autofree char *libvirtd_conf = NULL; + g_autofree char *patch_conf = NULL; + g_autofree char *buf = NULL; + char *ret = NULL; +-- +2.27.0 + diff --git a/Hotpatch-introduce-DomainHotpatchManage-API.patch b/Hotpatch-introduce-DomainHotpatchManage-API.patch new file mode 100644 index 0000000..640f180 --- /dev/null +++ b/Hotpatch-introduce-DomainHotpatchManage-API.patch @@ -0,0 +1,224 @@ +From dd9b8be8f47638f9149f3b577f1c38e36cd3e0db Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Tue, 19 Oct 2021 14:50:32 +0800 +Subject: [PATCH] Hotpatch: introduce DomainHotpatchManage API + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + include/libvirt/libvirt-domain.h | 23 +++++++++++++ + scripts/check-aclrules.py | 1 + + src/driver-hypervisor.h | 8 +++++ + src/libvirt-domain.c | 59 ++++++++++++++++++++++++++++++++ + src/libvirt_public.syms | 5 +++ + src/remote/remote_driver.c | 1 + + src/remote/remote_protocol.x | 19 +++++++++- + 7 files changed, 115 insertions(+), 1 deletion(-) + +diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h +index a1902546bb..f8def59032 100644 +--- a/include/libvirt/libvirt-domain.h ++++ b/include/libvirt/libvirt-domain.h +@@ -6416,6 +6416,29 @@ int virDomainAuthorizedSSHKeysGet(virDomainPtr domain, + char ***keys, + unsigned int flags); + ++/** ++ * virDomainHotpatchAction: ++ * ++ * Since: 6.2.0 ++ */ ++typedef enum { ++ VIR_DOMAIN_HOTPATCH_NONE = 0, /* No action */ ++ VIR_DOMAIN_HOTPATCH_APPLY, /* Apply hotpatch */ ++ VIR_DOMAIN_HOTPATCH_UNAPPLY, /* Unapply hotpatch */ ++ VIR_DOMAIN_HOTPATCH_QUERY, /* Query hotpatch */ ++ ++# ifdef VIR_ENUM_SENTINELS ++ VIR_DOMAIN_HOTPATCH_LAST ++# endif ++} virDomainHotpatchAction; ++ ++char * ++virDomainHotpatchManage(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags); ++ + /** + * virDomainAuthorizedSSHKeysSetFlags: + * +diff --git a/scripts/check-aclrules.py b/scripts/check-aclrules.py +index ed6805058b..e39dbd2ba8 100755 +--- a/scripts/check-aclrules.py ++++ b/scripts/check-aclrules.py +@@ -53,6 +53,7 @@ permitted = { + "connectURIProbe": True, + "localOnly": True, + "domainQemuAttach": True, ++ "domainHotpatchManage": True, + } + + # XXX this vzDomainMigrateConfirm3Params looks +diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h +index 5219344b72..e54af0515f 100644 +--- a/src/driver-hypervisor.h ++++ b/src/driver-hypervisor.h +@@ -1448,6 +1448,13 @@ typedef int + int *fds, + unsigned int flags); + ++typedef char * ++(*virDrvDomainHotpatchManage)(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags); ++ + typedef struct _virHypervisorDriver virHypervisorDriver; + + /** +@@ -1720,4 +1727,5 @@ struct _virHypervisorDriver { + virDrvDomainGetMessages domainGetMessages; + virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc; + virDrvDomainFDAssociate domainFDAssociate; ++ virDrvDomainHotpatchManage domainHotpatchManage; + }; +diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c +index 77a9682ecb..26833efd0e 100644 +--- a/src/libvirt-domain.c ++++ b/src/libvirt-domain.c +@@ -13784,6 +13784,65 @@ virDomainBackupGetXMLDesc(virDomainPtr domain, + return NULL; + } + ++/** ++ * virDomainHotpatchManage: ++ * @domain: a domain object ++ * @action: the action type from virDomainHotpatchAction ++ * @patch: the target hotpatch file ++ * @id: the patch id of the target hotpatch ++ * @flags: extra flags; not used yet, so callers should always pass 0 ++ * ++ * Manage hotpatch for the current domain according to @action. ++ * ++ * If the @action is set to VIR_DOMAIN_HOTPATCH_APPLY, apply hotpatch ++ * @patch to the current domain. ++ * ++ * If the @action is set to VIR_DOMAIN_HOTPATCH_UNAPPLY, unapply the ++ * hotpatch which is matched with @id from the current domain. ++ * ++ * If the @action is set to VIR_DOMAIN_HOTPATCH_QUERY, query infomations ++ * of the applied hotpatch of the current domain. ++ * ++ * Returns success messages in case of success, NULL otherwise. ++ * ++ * Since: 6.10.0 ++ */ ++char * ++virDomainHotpatchManage(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags) ++{ ++ virConnectPtr conn; ++ ++ virResetLastError(); ++ ++ virCheckDomainReturn(domain, NULL); ++ conn = domain->conn; ++ ++ virCheckReadOnlyGoto(conn->flags, error); ++ ++ if (action == VIR_DOMAIN_HOTPATCH_APPLY) ++ virCheckNonNullArgGoto(patch, error); ++ ++ if (action == VIR_DOMAIN_HOTPATCH_UNAPPLY) ++ virCheckNonNullArgGoto(id, error); ++ ++ if (conn->driver->domainHotpatchManage) { ++ char *ret; ++ ret = conn->driver->domainHotpatchManage(domain, action, patch, id, flags); ++ if (!ret) ++ goto error; ++ ++ return ret; ++ } ++ ++ virReportUnsupportedError(); ++ error: ++ virDispatchError(conn); ++ return NULL; ++} + + /** + * virDomainAuthorizedSSHKeysGet: +diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms +index bd1e916d2a..52a5d03240 100644 +--- a/src/libvirt_public.syms ++++ b/src/libvirt_public.syms +@@ -873,6 +873,11 @@ LIBVIRT_6.0.0 { + virDomainBackupGetXMLDesc; + } LIBVIRT_5.10.0; + ++LIBVIRT_6.2.0 { ++ global: ++ virDomainHotpatchManage; ++} LIBVIRT_6.0.0; ++ + LIBVIRT_6.10.0 { + global: + virDomainAuthorizedSSHKeysGet; +diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c +index c4831db6cd..25fae1cad6 100644 +--- a/src/remote/remote_driver.c ++++ b/src/remote/remote_driver.c +@@ -7842,6 +7842,7 @@ static virHypervisorDriver hypervisor_driver = { + .domainAgentSetResponseTimeout = remoteDomainAgentSetResponseTimeout, /* 5.10.0 */ + .domainBackupBegin = remoteDomainBackupBegin, /* 6.0.0 */ + .domainBackupGetXMLDesc = remoteDomainBackupGetXMLDesc, /* 6.0.0 */ ++ .domainHotpatchManage = remoteDomainHotpatchManage, /* 6.2.0 */ + .domainAuthorizedSSHKeysGet = remoteDomainAuthorizedSSHKeysGet, /* 6.10.0 */ + .domainAuthorizedSSHKeysSet = remoteDomainAuthorizedSSHKeysSet, /* 6.10.0 */ + .domainGetMessages = remoteDomainGetMessages, /* 7.1.0 */ +diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x +index e295b0acc3..eea11df2ea 100644 +--- a/src/remote/remote_protocol.x ++++ b/src/remote/remote_protocol.x +@@ -3956,6 +3956,17 @@ struct remote_domain_event_memory_device_size_change_msg { + unsigned hyper size; + }; + ++struct remote_domain_hotpatch_manage_args { ++ remote_nonnull_domain dom; ++ int action; ++ remote_string patch; ++ remote_string id; ++ unsigned int flags; ++}; ++ ++struct remote_domain_hotpatch_manage_ret { ++ remote_string info; ++}; + + struct remote_domain_fd_associate_args { + remote_nonnull_domain dom; +@@ -7021,5 +7032,11 @@ enum remote_procedure { + * @generate: both + * @acl: none + */ +- REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446 ++ REMOTE_PROC_NETWORK_EVENT_CALLBACK_METADATA_CHANGE = 446, ++ ++ /** ++ * @generate: both ++ * @acl: domain:read ++ */ ++ REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800 + }; +-- +2.27.0 + diff --git a/domain-add-logs-for-virDomainHotpatchManage.patch b/domain-add-logs-for-virDomainHotpatchManage.patch new file mode 100644 index 0000000..e0c0621 --- /dev/null +++ b/domain-add-logs-for-virDomainHotpatchManage.patch @@ -0,0 +1,45 @@ +From a7f63f8c85e3bc287920ed83361e4f44ce2e25d7 Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Mon, 12 Jul 2021 21:28:41 +0800 +Subject: [PATCH] domain: add logs for virDomainHotpatchManage + +Add logs for virDomainHotpatchManage to facilitate the location of +issues related to subsequent hotpatch. + +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + src/libvirt-domain.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c +index 21b01110fe..b1c5a8c52c 100644 +--- a/src/libvirt-domain.c ++++ b/src/libvirt-domain.c +@@ -13829,12 +13829,21 @@ virDomainHotpatchManage(virDomainPtr domain, + if (action == VIR_DOMAIN_HOTPATCH_UNAPPLY) + virCheckNonNullArgGoto(id, error); + ++ VIR_INFO("enter virDomainHotpatchManage domainname=%s, action=%d, " ++ "patch=%s, id=%s, flags=%d", ++ NULLSTR(domain->name), action, ++ NULLSTR(patch), NULLSTR(id), flags); ++ + if (conn->driver->domainHotpatchManage) { + char *ret; + ret = conn->driver->domainHotpatchManage(domain, action, patch, id, flags); +- if (!ret) ++ if (!ret) { ++ VIR_ERROR("domain %s managed hotpatch failed", ++ NULLSTR(domain->name)); + goto error; +- ++ } ++ VIR_INFO("domain %s managed hotpatch successfully", ++ NULLSTR(domain->name)); + return ret; + } + +-- +2.27.0 + diff --git a/hotpatch-Implement-qemuDomainHotpatchManage.patch b/hotpatch-Implement-qemuDomainHotpatchManage.patch new file mode 100644 index 0000000..0b3fae0 --- /dev/null +++ b/hotpatch-Implement-qemuDomainHotpatchManage.patch @@ -0,0 +1,387 @@ +From 2721c0ce65045c90e54fcab383d4af83415bd3f3 Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Tue, 19 Oct 2021 14:50:32 +0800 +Subject: [PATCH] hotpatch: Implement qemuDomainHotpatchManage + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + include/libvirt/libvirt-domain.h | 10 +- + src/libvirt-domain.c | 2 +- + src/libvirt_public.syms | 2 +- + src/qemu/meson.build | 1 + + src/qemu/qemu_driver.c | 48 ++++++++ + src/qemu/qemu_hotpatch.c | 182 +++++++++++++++++++++++++++++++ + src/qemu/qemu_hotpatch.h | 36 ++++++ + 7 files changed, 274 insertions(+), 7 deletions(-) + create mode 100644 src/qemu/qemu_hotpatch.c + create mode 100644 src/qemu/qemu_hotpatch.h + +diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h +index f8def59032..e786ecfab2 100644 +--- a/include/libvirt/libvirt-domain.h ++++ b/include/libvirt/libvirt-domain.h +@@ -6422,13 +6422,13 @@ int virDomainAuthorizedSSHKeysGet(virDomainPtr domain, + * Since: 6.2.0 + */ + typedef enum { +- VIR_DOMAIN_HOTPATCH_NONE = 0, /* No action */ +- VIR_DOMAIN_HOTPATCH_APPLY, /* Apply hotpatch */ +- VIR_DOMAIN_HOTPATCH_UNAPPLY, /* Unapply hotpatch */ +- VIR_DOMAIN_HOTPATCH_QUERY, /* Query hotpatch */ ++ VIR_DOMAIN_HOTPATCH_NONE = 0, /* No action (Since: 6.2.0) */ ++ VIR_DOMAIN_HOTPATCH_APPLY, /* Apply hotpatch (Since: 6.2.0) */ ++ VIR_DOMAIN_HOTPATCH_UNAPPLY, /* Unapply hotpatch (Since: 6.2.0) */ ++ VIR_DOMAIN_HOTPATCH_QUERY, /* Query hotpatch (Since: 6.2.0) */ + + # ifdef VIR_ENUM_SENTINELS +- VIR_DOMAIN_HOTPATCH_LAST ++ VIR_DOMAIN_HOTPATCH_LAST /* Last index (Since: 6.2.0) */ + # endif + } virDomainHotpatchAction; + +diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c +index 26833efd0e..21b01110fe 100644 +--- a/src/libvirt-domain.c ++++ b/src/libvirt-domain.c +@@ -13805,7 +13805,7 @@ virDomainBackupGetXMLDesc(virDomainPtr domain, + * + * Returns success messages in case of success, NULL otherwise. + * +- * Since: 6.10.0 ++ * Since: 6.2.0 + */ + char * + virDomainHotpatchManage(virDomainPtr domain, +diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms +index 52a5d03240..8b38fe9a5f 100644 +--- a/src/libvirt_public.syms ++++ b/src/libvirt_public.syms +@@ -882,7 +882,7 @@ LIBVIRT_6.10.0 { + global: + virDomainAuthorizedSSHKeysGet; + virDomainAuthorizedSSHKeysSet; +-} LIBVIRT_6.0.0; ++} LIBVIRT_6.2.0; + + LIBVIRT_7.1.0 { + global: +diff --git a/src/qemu/meson.build b/src/qemu/meson.build +index 2279fef2ca..9d5b4da35d 100644 +--- a/src/qemu/meson.build ++++ b/src/qemu/meson.build +@@ -42,6 +42,7 @@ qemu_driver_sources = [ + 'qemu_vhost_user.c', + 'qemu_vhost_user_gpu.c', + 'qemu_virtiofs.c', ++ 'qemu_hotpatch.c', + ] + + driver_source_files += files(qemu_driver_sources) +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index d00d2a27c6..3dd82d6f12 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -105,6 +105,7 @@ + #include "virdomaincheckpointobjlist.h" + #include "virutil.h" + #include "backup_conf.h" ++#include "qemu_hotpatch.h" + + #define VIR_FROM_THIS VIR_FROM_QEMU + +@@ -19934,6 +19935,52 @@ qemuDomainFDAssociate(virDomainPtr domain, + return ret; + } + ++static char * ++qemuDomainHotpatchManage(virDomainPtr domain, ++ int action, ++ const char *patch, ++ const char *id, ++ unsigned int flags) ++{ ++ virDomainObjPtr vm; ++ char *ret = NULL; ++ size_t len; ++ ++ virCheckFlags(0, NULL); ++ ++ if (!(vm = qemuDomainObjFromDomain(domain))) ++ goto cleanup; ++ ++ switch (action) { ++ case VIR_DOMAIN_HOTPATCH_APPLY: ++ ret = qemuDomainHotpatchApply(vm, patch); ++ break; ++ ++ case VIR_DOMAIN_HOTPATCH_UNAPPLY: ++ ret = qemuDomainHotpatchUnapply(vm, id); ++ break; ++ ++ case VIR_DOMAIN_HOTPATCH_QUERY: ++ ret = qemuDomainHotpatchQuery(vm); ++ break; ++ ++ default: ++ virReportError(VIR_ERR_OPERATION_INVALID, "%s", ++ _("Unknow hotpatch action")); ++ } ++ ++ if (!ret) ++ goto endjob; ++ ++ /* Wipeout redundant empty line */ ++ len = strlen(ret); ++ if (len > 0) ++ ret[len - 1] = '\0'; ++ ++ cleanup: ++ virDomainObjEndAPI(&vm); ++ return ret; ++} + + static virHypervisorDriver qemuHypervisorDriver = { + .name = QEMU_DRIVER_NAME, +@@ -20178,6 +20225,7 @@ static virHypervisorDriver qemuHypervisorDriver = { + .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 5.10.0 */ + .domainBackupBegin = qemuDomainBackupBegin, /* 6.0.0 */ + .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */ ++ .domainHotpatchManage = qemuDomainHotpatchManage, /* 6.2.0 */ + .domainAuthorizedSSHKeysGet = qemuDomainAuthorizedSSHKeysGet, /* 6.10.0 */ + .domainAuthorizedSSHKeysSet = qemuDomainAuthorizedSSHKeysSet, /* 6.10.0 */ + .domainGetMessages = qemuDomainGetMessages, /* 7.1.0 */ +diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c +new file mode 100644 +index 0000000000..c1a4ab7aca +--- /dev/null ++++ b/src/qemu/qemu_hotpatch.c +@@ -0,0 +1,182 @@ ++/* ++ * huawei_qemu_hotpatch.h: huawei qemu hotpatch functions ++ * ++ * Copyright (C) 2021-2021 HUAWEI, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * . ++ * ++ */ ++ ++ ++#include ++#include "viralloc.h" ++#include "virerror.h" ++#include "virfile.h" ++#include "virlog.h" ++#include "vircommand.h" ++#include "qemu/qemu_domain.h" ++#include "qemu_hotpatch.h" ++ ++#define LIBCARE_CTL "libcare-ctl" ++#define LIBCARE_ERROR_NUMBER 255 ++#define MAX_PATCHID_LEN 8 ++ ++#define VIR_FROM_THIS VIR_FROM_QEMU ++ ++VIR_LOG_INIT("qemu_hotpatch"); ++ ++char * ++qemuDomainHotpatchQuery(virDomainObj *vm) ++{ ++ g_autoptr(virCommand) cmd = NULL; ++ g_autofree char *binary = NULL; ++ char *output = NULL; ++ int ret = -1; ++ ++ if (!(binary = virFindFileInPath(LIBCARE_CTL))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to find libcare-ctl command.")); ++ return NULL; ++ } ++ ++ cmd = virCommandNewArgList(binary, "info", "-p", NULL); ++ virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandSetOutputBuffer(cmd, &output); ++ ++ VIR_DEBUG("Querying hotpatch for domain %s. (%s info -p %d)", ++ vm->def->name, binary, vm->pid); ++ ++ if (virCommandRun(cmd, &ret) < 0) ++ goto error; ++ ++ if (ret == LIBCARE_ERROR_NUMBER) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to execute libcare-ctl command.")); ++ goto error; ++ } ++ return output; ++ ++ error: ++ VIR_FREE(output); ++ return NULL; ++} ++ ++char * ++qemuDomainHotpatchApply(virDomainObj *vm, ++ const char *patch) ++{ ++ g_autoptr(virCommand) cmd = NULL; ++ g_autofree char *binary = NULL; ++ char *output = NULL; ++ int ret = -1; ++ ++ if (!patch || !virFileExists(patch)) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ "%s", _("Invalid hotpatch file.")); ++ return NULL; ++ } ++ ++ if (!(binary = virFindFileInPath(LIBCARE_CTL))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ "%s", _("Failed to find libcare-ctl command.")); ++ return NULL; ++ } ++ ++ cmd = virCommandNewArgList(binary, "patch", "-p", NULL); ++ virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgList(cmd, patch, NULL); ++ virCommandSetOutputBuffer(cmd, &output); ++ ++ VIR_DEBUG("Applying hotpatch for domain %s. (%s patch -p %d %s)", ++ vm->def->name, binary, vm->pid, patch); ++ ++ if (virCommandRun(cmd, &ret) < 0) ++ goto error; ++ ++ if (ret == LIBCARE_ERROR_NUMBER) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to execute libcare-ctl command.")); ++ goto error; ++ } ++ return output; ++ ++ error: ++ VIR_FREE(output); ++ return NULL; ++} ++ ++static bool ++qemuDomainHotpatchIsPatchidValid(const char *id) ++{ ++ size_t len, i; ++ ++ if (!id) ++ return false; ++ ++ len = strlen(id); ++ if (len > MAX_PATCHID_LEN - 1) ++ return false; ++ ++ for (i = 0; i < len; i++) { ++ if (!g_ascii_isalnum(*(id + i))) ++ return false; ++ } ++ ++ return true; ++} ++ ++char * ++qemuDomainHotpatchUnapply(virDomainObj *vm, ++ const char *id) ++{ ++ g_autoptr(virCommand) cmd = NULL; ++ g_autofree char *binary = NULL; ++ char *output = NULL; ++ int ret = -1; ++ ++ if (!id || !qemuDomainHotpatchIsPatchidValid(id)) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ "%s", _("Invalid hotpatch id.")); ++ return NULL; ++ } ++ ++ if (!(binary = virFindFileInPath(LIBCARE_CTL))) { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ "%s", _("Failed to find libcare-ctl command.")); ++ return NULL; ++ } ++ ++ cmd = virCommandNewArgList(binary, "unpatch", "-p", NULL); ++ virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgList(cmd, "-i", id, NULL); ++ virCommandSetOutputBuffer(cmd, &output); ++ ++ VIR_DEBUG("Unapplying hotpatch for domain %s. (%s unpatch -p %d -i %s)", ++ vm->def->name, binary, vm->pid, id); ++ ++ if (virCommandRun(cmd, &ret) < 0) ++ goto error; ++ ++ if (ret == LIBCARE_ERROR_NUMBER) { ++ virReportError(VIR_ERR_OPERATION_FAILED, "%s", ++ _("Failed to execute libcare-ctl command.")); ++ goto error; ++ } ++ return output; ++ ++ error: ++ VIR_FREE(output); ++ return NULL; ++} +diff --git a/src/qemu/qemu_hotpatch.h b/src/qemu/qemu_hotpatch.h +new file mode 100644 +index 0000000000..3cf22f7fc4 +--- /dev/null ++++ b/src/qemu/qemu_hotpatch.h +@@ -0,0 +1,36 @@ ++/* ++ * huawei_qemu_hotpatch.h: huawei qemu hotpatch functions ++ * ++ * Copyright (C) 2021-2021 HUAWEI, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library. If not, see ++ * . ++ * ++ */ ++ ++#pragma once ++ ++#include ++#include "qemu/qemu_conf.h" ++ ++char * ++qemuDomainHotpatchQuery(virDomainObj *vm); ++ ++char * ++qemuDomainHotpatchApply(virDomainObj *vm, ++ const char *patch); ++ ++char * ++qemuDomainHotpatchUnapply(virDomainObj *vm, ++ const char *id); +-- +2.27.0 + diff --git a/hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch b/hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch new file mode 100644 index 0000000..a1bb620 --- /dev/null +++ b/hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch @@ -0,0 +1,151 @@ +From ebdf0312a590ba60f3d304f338737155f469dd7a Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Fri, 9 Jul 2021 10:50:07 +0800 +Subject: [PATCH] hotpatch: check vm id and pid before using hotpatch api + +Check if the vm is alive before using hotpatch api by calling +virDomainObjCheckActive() to check vm id and calling +qemuDomainHotpatchCheckPid() to check vm pid. + +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + src/qemu/qemu_driver.c | 9 ++++++--- + src/qemu/qemu_hotpatch.c | 36 ++++++++++++++++++++++++++++++------ + 2 files changed, 36 insertions(+), 9 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 31917ef591..05cc0db3ae 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -19954,11 +19954,14 @@ qemuDomainHotpatchManage(virDomainPtr domain, + if (!(vm = qemuDomainObjFromDomain(domain))) + goto cleanup; + +- if (VirDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_HOTPATCH, ++ if (virDomainObjBeginAsyncJob(vm, VIR_ASYNC_JOB_HOTPATCH, + VIR_DOMAIN_JOB_OPERATION_HOTPATCH, 0) < 0) + goto cleanup; + +- qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_DEFAULT_MASK); ++ if (virDomainObjCheckActive(vm) < 0) ++ goto endjob; ++ ++ qemuDomainObjSetAsyncJobMask(vm, VIR_JOB_DEFAULT_MASK); + + switch (action) { + case VIR_DOMAIN_HOTPATCH_APPLY: +@@ -19987,7 +19990,7 @@ qemuDomainHotpatchManage(virDomainPtr domain, + ret[len - 1] = '\0'; + + endjob: +- qemuDomainObjEndAsyncJob(driver, vm); ++ virDomainObjEndAsyncJob(vm); + + cleanup: + virDomainObjEndAPI(&vm); +diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c +index c1a4ab7aca..31ef5bb7f2 100644 +--- a/src/qemu/qemu_hotpatch.c ++++ b/src/qemu/qemu_hotpatch.c +@@ -37,12 +37,25 @@ + + VIR_LOG_INIT("qemu_hotpatch"); + ++static int ++qemuDomainHotpatchCheckPid(pid_t pid) ++{ ++ if (pid <= 0) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ "%s", _("Invalid pid")); ++ return -1; ++ } ++ ++ return 0; ++} ++ + char * + qemuDomainHotpatchQuery(virDomainObj *vm) + { + g_autoptr(virCommand) cmd = NULL; + g_autofree char *binary = NULL; + char *output = NULL; ++ pid_t pid = vm->pid; + int ret = -1; + + if (!(binary = virFindFileInPath(LIBCARE_CTL))) { +@@ -51,12 +64,15 @@ qemuDomainHotpatchQuery(virDomainObj *vm) + return NULL; + } + ++ if (qemuDomainHotpatchCheckPid(pid) < 0) ++ return NULL; ++ + cmd = virCommandNewArgList(binary, "info", "-p", NULL); +- virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgFormat(cmd, "%d", pid); + virCommandSetOutputBuffer(cmd, &output); + + VIR_DEBUG("Querying hotpatch for domain %s. (%s info -p %d)", +- vm->def->name, binary, vm->pid); ++ vm->def->name, binary, pid); + + if (virCommandRun(cmd, &ret) < 0) + goto error; +@@ -80,6 +96,7 @@ qemuDomainHotpatchApply(virDomainObj *vm, + g_autoptr(virCommand) cmd = NULL; + g_autofree char *binary = NULL; + char *output = NULL; ++ pid_t pid = vm->pid; + int ret = -1; + + if (!patch || !virFileExists(patch)) { +@@ -94,13 +111,16 @@ qemuDomainHotpatchApply(virDomainObj *vm, + return NULL; + } + ++ if (qemuDomainHotpatchCheckPid(pid) < 0) ++ return NULL; ++ + cmd = virCommandNewArgList(binary, "patch", "-p", NULL); +- virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgFormat(cmd, "%d", pid); + virCommandAddArgList(cmd, patch, NULL); + virCommandSetOutputBuffer(cmd, &output); + + VIR_DEBUG("Applying hotpatch for domain %s. (%s patch -p %d %s)", +- vm->def->name, binary, vm->pid, patch); ++ vm->def->name, binary, pid, patch); + + if (virCommandRun(cmd, &ret) < 0) + goto error; +@@ -144,6 +164,7 @@ qemuDomainHotpatchUnapply(virDomainObj *vm, + g_autoptr(virCommand) cmd = NULL; + g_autofree char *binary = NULL; + char *output = NULL; ++ pid_t pid = vm->pid; + int ret = -1; + + if (!id || !qemuDomainHotpatchIsPatchidValid(id)) { +@@ -158,13 +179,16 @@ qemuDomainHotpatchUnapply(virDomainObj *vm, + return NULL; + } + ++ if (qemuDomainHotpatchCheckPid(pid) < 0) ++ return NULL; ++ + cmd = virCommandNewArgList(binary, "unpatch", "-p", NULL); +- virCommandAddArgFormat(cmd, "%d", vm->pid); ++ virCommandAddArgFormat(cmd, "%d", pid); + virCommandAddArgList(cmd, "-i", id, NULL); + virCommandSetOutputBuffer(cmd, &output); + + VIR_DEBUG("Unapplying hotpatch for domain %s. (%s unpatch -p %d -i %s)", +- vm->def->name, binary, vm->pid, id); ++ vm->def->name, binary, pid, id); + + if (virCommandRun(cmd, &ret) < 0) + goto error; +-- +2.27.0 + diff --git a/hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch b/hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch new file mode 100644 index 0000000..f3f1a9e --- /dev/null +++ b/hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch @@ -0,0 +1,34 @@ +From 033b8d177e4512f0ba3af8ed46ee38a4251c7e1c Mon Sep 17 00:00:00 2001 +From: Dawei Jiang +Date: Mon, 8 Apr 2024 19:59:11 +0800 +Subject: [PATCH] hotpatch: if hotpatch_path not in qemu.conf,the hotpatch + doesn't antoload + +Signed-off-by: Dawei Jiang +--- + src/qemu/qemu_process.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 41e9660ecd..348280d9be 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -7929,10 +7929,12 @@ qemuProcessLaunch(virConnectPtr conn, + goto cleanup; + + /* Autoload hotpatch */ +- if ((autoLoadStatus = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath)) == NULL) { +- VIR_WARN("Failed to autoload the hotpatch for %s.", vm->def->name); ++ if (cfg->hotpatchPath != NULL) { ++ autoLoadStatus = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath); ++ if (autoLoadStatus == NULL) { ++ VIR_WARN("Failed to autoload the hotpatch for %s.", vm->def->name); ++ } + } +- + ret = 0; + + cleanup: +-- +2.27.0 + diff --git a/hotpatch-implement-hotpatch-virsh-api.patch b/hotpatch-implement-hotpatch-virsh-api.patch new file mode 100644 index 0000000..30b91a3 --- /dev/null +++ b/hotpatch-implement-hotpatch-virsh-api.patch @@ -0,0 +1,110 @@ +From d56a3df418b90f4a6f303a3830732b5fde8d3a10 Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Wed, 20 Oct 2021 11:07:34 +0800 +Subject: [PATCH] hotpatch: implement hotpatch virsh api + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + tools/virsh-domain.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 78 insertions(+) + +diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c +index 9d22e219f7..d88ac3cca6 100644 +--- a/tools/virsh-domain.c ++++ b/tools/virsh-domain.c +@@ -13556,6 +13556,78 @@ cmdGuestInfo(vshControl *ctl, const vshCmd *cmd) + return ret; + } + ++/* ++ * "hotpatch" command ++ */ ++static const vshCmdInfo info_hotpatch[] = { ++ {.name = "help", ++ .data = N_("Manage hotpatch of a live domain") ++ }, ++ {.name = "desc", ++ .data = N_("Manage hotpatch of a live domain") ++ }, ++ {.name = NULL} ++}; ++ ++static const vshCmdOptDef opts_hotpatch[] = { ++ VIRSH_COMMON_OPT_DOMAIN_FULL(0), ++ {.name = "action", ++ .type = VSH_OT_DATA, ++ .flags = VSH_OFLAG_REQ, ++ .help = N_("hotpatch action, choose from , and ") ++ }, ++ {.name = "patch", ++ .type = VSH_OT_STRING, ++ .help = N_("the absolute path of the hotpatch file, mandatory when action=apply") ++ }, ++ {.name = "id", ++ .type = VSH_OT_STRING, ++ .help = N_("the unique id of the target patch, mandatory when action=unapply") ++ }, ++ {.name = NULL} ++}; ++ ++VIR_ENUM_DECL(virDomainHotpatchAction); ++VIR_ENUM_IMPL(virDomainHotpatchAction, ++ VIR_DOMAIN_HOTPATCH_LAST, ++ "none", ++ "apply", ++ "unapply", ++ "query"); ++ ++static bool ++cmdHotpatch(vshControl *ctl, ++ const vshCmd *cmd) ++{ ++ g_autoptr(virshDomain) dom = NULL; ++ const char *patch = NULL; ++ const char *id = NULL; ++ const char *actionstr = NULL; ++ int action = -1; ++ g_autofree char *ret = NULL; ++ ++ if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) ++ return false; ++ ++ if (vshCommandOptStringReq(ctl, cmd, "action", &actionstr) < 0) ++ return false; ++ ++ if (actionstr) ++ action = virDomainHotpatchActionTypeFromString(actionstr); ++ ++ if (vshCommandOptStringReq(ctl, cmd, "patch", &patch) < 0) ++ return false; ++ ++ if (vshCommandOptStringReq(ctl, cmd, "id", &id) < 0) ++ return false; ++ ++ if (!(ret = virDomainHotpatchManage(dom, action, patch, id, 0))) ++ return false; ++ ++ vshPrint(ctl, _("%s"), ret); ++ return true; ++} ++ + /* + * "get-user-sshkeys" command + */ +@@ -14456,5 +14528,11 @@ const vshCmdDef domManagementCmds[] = { + .info = info_dom_fd_associate, + .flags = 0 + }, ++ {.name = "hotpatch", ++ .handler = cmdHotpatch, ++ .opts = opts_hotpatch, ++ .info = info_hotpatch, ++ .flags = 0 ++ }, + {.name = NULL} + }; +-- +2.27.0 + diff --git a/hotpatch-introduce-hotpatch-async-job-flag.patch b/hotpatch-introduce-hotpatch-async-job-flag.patch new file mode 100644 index 0000000..8e3667b --- /dev/null +++ b/hotpatch-introduce-hotpatch-async-job-flag.patch @@ -0,0 +1,161 @@ +From 180e19162083fb74e9e9cbc676ce42611bb2e496 Mon Sep 17 00:00:00 2001 +From: AlexChen +Date: Tue, 19 Oct 2021 22:41:24 +0800 +Subject: [PATCH] hotpatch: introduce hotpatch async job flag + +Signed-off-by: Hao Wang +Signed-off-by: Bihong Yu +Signed-off-by: AlexChen +--- + include/libvirt/libvirt-domain.h | 1 + + src/conf/virdomainjob.c | 1 + + src/conf/virdomainjob.h | 1 + + src/qemu/qemu_domainjob.c | 2 ++ + src/qemu/qemu_driver.c | 14 +++++++++++++- + src/qemu/qemu_migration.c | 2 ++ + src/qemu/qemu_process.c | 1 + + tools/virsh-domain.c | 1 + + 8 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h +index e786ecfab2..96e62deac3 100644 +--- a/include/libvirt/libvirt-domain.h ++++ b/include/libvirt/libvirt-domain.h +@@ -4201,6 +4201,7 @@ typedef enum { + VIR_DOMAIN_JOB_OPERATION_DUMP = 8, /* (Since: 3.3.0) */ + VIR_DOMAIN_JOB_OPERATION_BACKUP = 9, /* (Since: 6.0.0) */ + VIR_DOMAIN_JOB_OPERATION_SNAPSHOT_DELETE = 10, /* (Since: 9.0.0) */ ++ VIR_DOMAIN_JOB_OPERATION_HOTPATCH = 11, /* (Since: 6.2.0) */ + + # ifdef VIR_ENUM_SENTINELS + VIR_DOMAIN_JOB_OPERATION_LAST /* (Since: 3.3.0) */ +diff --git a/src/conf/virdomainjob.c b/src/conf/virdomainjob.c +index 38f08f1d18..d21fc653a0 100644 +--- a/src/conf/virdomainjob.c ++++ b/src/conf/virdomainjob.c +@@ -51,6 +51,7 @@ VIR_ENUM_IMPL(virDomainAsyncJob, + "snapshot", + "start", + "backup", ++ "hotpatch", + ); + + virDomainJobData * +diff --git a/src/conf/virdomainjob.h b/src/conf/virdomainjob.h +index 0d62bab287..d0f632edad 100644 +--- a/src/conf/virdomainjob.h ++++ b/src/conf/virdomainjob.h +@@ -75,6 +75,7 @@ typedef enum { + VIR_ASYNC_JOB_SNAPSHOT, + VIR_ASYNC_JOB_START, + VIR_ASYNC_JOB_BACKUP, ++ VIR_ASYNC_JOB_HOTPATCH, + + VIR_ASYNC_JOB_LAST + } virDomainAsyncJob; +diff --git a/src/qemu/qemu_domainjob.c b/src/qemu/qemu_domainjob.c +index 245e51f14b..c9753c4f2b 100644 +--- a/src/qemu/qemu_domainjob.c ++++ b/src/qemu/qemu_domainjob.c +@@ -56,6 +56,7 @@ qemuDomainAsyncJobPhaseToString(virDomainAsyncJob job, + case VIR_ASYNC_JOB_START: + case VIR_ASYNC_JOB_NONE: + case VIR_ASYNC_JOB_BACKUP: ++ case VIR_ASYNC_JOB_HOTPATCH: + G_GNUC_FALLTHROUGH; + case VIR_ASYNC_JOB_LAST: + break; +@@ -82,6 +83,7 @@ qemuDomainAsyncJobPhaseFromString(virDomainAsyncJob job, + case VIR_ASYNC_JOB_START: + case VIR_ASYNC_JOB_NONE: + case VIR_ASYNC_JOB_BACKUP: ++ case VIR_ASYNC_JOB_HOTPATCH: + G_GNUC_FALLTHROUGH; + case VIR_ASYNC_JOB_LAST: + break; +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 3dd82d6f12..31917ef591 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -12251,6 +12251,8 @@ qemuDomainAbortJobFlags(virDomainPtr dom, + qemuBackupJobCancelBlockjobs(vm, priv->backup, true, VIR_ASYNC_JOB_NONE); + ret = 0; + break; ++ case VIR_ASYNC_JOB_HOTPATCH: ++ break; + + case VIR_ASYNC_JOB_LAST: + default: +@@ -19942,7 +19944,8 @@ qemuDomainHotpatchManage(virDomainPtr domain, + const char *id, + unsigned int flags) + { +- virDomainObjPtr vm; ++ virDomainObj *vm; ++ virQEMUDriver *driver = domain->conn->privateData; + char *ret = NULL; + size_t len; + +@@ -19951,6 +19954,12 @@ qemuDomainHotpatchManage(virDomainPtr domain, + if (!(vm = qemuDomainObjFromDomain(domain))) + goto cleanup; + ++ if (VirDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_HOTPATCH, ++ VIR_DOMAIN_JOB_OPERATION_HOTPATCH, 0) < 0) ++ goto cleanup; ++ ++ qemuDomainObjSetAsyncJobMask(vm, QEMU_JOB_DEFAULT_MASK); ++ + switch (action) { + case VIR_DOMAIN_HOTPATCH_APPLY: + ret = qemuDomainHotpatchApply(vm, patch); +@@ -19977,6 +19986,9 @@ qemuDomainHotpatchManage(virDomainPtr domain, + if (len > 0) + ret[len - 1] = '\0'; + ++ endjob: ++ qemuDomainObjEndAsyncJob(driver, vm); ++ + cleanup: + virDomainObjEndAPI(&vm); + return ret; +diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c +index f9c34b72e8..73395ce3b2 100644 +--- a/src/qemu/qemu_migration.c ++++ b/src/qemu/qemu_migration.c +@@ -1846,6 +1846,8 @@ qemuMigrationJobName(virDomainObj *vm) + return _("start"); + case VIR_ASYNC_JOB_BACKUP: + return _("backup"); ++ case VIR_ASYNC_JOB_HOTPATCH: ++ return _("hotpatch job"); + case VIR_ASYNC_JOB_NONE: + case VIR_ASYNC_JOB_LAST: + default: +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index fc05b4b24f..318f9f6182 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3758,6 +3758,7 @@ qemuProcessRecoverJob(virQEMUDriver *driver, + JOB_MASK(VIR_JOB_MODIFY))); + break; + ++ case VIR_ASYNC_JOB_HOTPATCH: + case VIR_ASYNC_JOB_NONE: + case VIR_ASYNC_JOB_LAST: + break; +diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c +index 66f933dead..9d22e219f7 100644 +--- a/tools/virsh-domain.c ++++ b/tools/virsh-domain.c +@@ -6152,6 +6152,7 @@ VIR_ENUM_IMPL(virshDomainJobOperation, + N_("Dump"), + N_("Backup"), + N_("Snapshot delete"), ++ N_("Hotpatch"), + ); + + static const char * +-- +2.27.0 + diff --git a/hotpatch-virsh-support-autoload-mode.patch b/hotpatch-virsh-support-autoload-mode.patch new file mode 100644 index 0000000..b844288 --- /dev/null +++ b/hotpatch-virsh-support-autoload-mode.patch @@ -0,0 +1,302 @@ +From 48da26004ea0222cc8819e097a004980662ef3eb Mon Sep 17 00:00:00 2001 +From: jiang-dawei15 +Date: Wed, 26 Jan 2022 15:18:10 +0800 +Subject: [PATCH] hotpatch: virsh support autoload mode + +--- + include/libvirt/libvirt-domain.h | 1 + + src/qemu/qemu_conf.c | 9 +++ + src/qemu/qemu_conf.h | 2 + + src/qemu/qemu_driver.c | 5 ++ + src/qemu/qemu_hotpatch.c | 120 +++++++++++++++++++++++++++++++ + src/qemu/qemu_hotpatch.h | 3 + + src/qemu/qemu_process.c | 7 ++ + tools/virsh-domain.c | 5 +- + 8 files changed, 150 insertions(+), 2 deletions(-) + +diff --git a/include/libvirt/libvirt-domain.h b/include/libvirt/libvirt-domain.h +index 96e62deac3..6120c6cea7 100644 +--- a/include/libvirt/libvirt-domain.h ++++ b/include/libvirt/libvirt-domain.h +@@ -6427,6 +6427,7 @@ typedef enum { + VIR_DOMAIN_HOTPATCH_APPLY, /* Apply hotpatch (Since: 6.2.0) */ + VIR_DOMAIN_HOTPATCH_UNAPPLY, /* Unapply hotpatch (Since: 6.2.0) */ + VIR_DOMAIN_HOTPATCH_QUERY, /* Query hotpatch (Since: 6.2.0) */ ++ VIR_DOMAIN_HOTPATCH_AUTOLOAD, /* Autoload hotpatch (Since: 6.2.0) */ + + # ifdef VIR_ENUM_SENTINELS + VIR_DOMAIN_HOTPATCH_LAST /* Last index (Since: 6.2.0) */ +diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c +index 513b5ebb1e..30343d3d12 100644 +--- a/src/qemu/qemu_conf.c ++++ b/src/qemu/qemu_conf.c +@@ -1064,6 +1064,12 @@ virQEMUDriverConfigLoadCapsFiltersEntry(virQEMUDriverConfig *cfg, + return 0; + } + ++static int ++virQEMUDriverConfigLoadHotpatchPathEntry(virQEMUDriverConfig *cfg, ++ virConf *conf) ++{ ++ return virConfGetValueString(conf, "hotpatch_path", &cfg->hotpatchPath); ++} + + int virQEMUDriverConfigLoadFile(virQEMUDriverConfig *cfg, + const char *filename, +@@ -1136,6 +1142,9 @@ int virQEMUDriverConfigLoadFile(virQEMUDriverConfig *cfg, + if (virQEMUDriverConfigLoadCapsFiltersEntry(cfg, conf) < 0) + return -1; + ++ if (virQEMUDriverConfigLoadHotpatchPathEntry(cfg, conf) < 0) ++ return -1; ++ + return 0; + } + +diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h +index 1a3ba3a0fb..8034ec7885 100644 +--- a/src/qemu/qemu_conf.h ++++ b/src/qemu/qemu_conf.h +@@ -231,6 +231,8 @@ struct _virQEMUDriverConfig { + char *deprecationBehavior; + + virQEMUSchedCore schedCore; ++ ++ char *hotpatchPath; + }; + + G_DEFINE_AUTOPTR_CLEANUP_FUNC(virQEMUDriverConfig, virObjectUnref); +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 05cc0db3ae..6b07bcc8dc 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -19948,6 +19948,7 @@ qemuDomainHotpatchManage(virDomainPtr domain, + virQEMUDriver *driver = domain->conn->privateData; + char *ret = NULL; + size_t len; ++ g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver); + + virCheckFlags(0, NULL); + +@@ -19976,6 +19977,10 @@ qemuDomainHotpatchManage(virDomainPtr domain, + ret = qemuDomainHotpatchQuery(vm); + break; + ++ case VIR_DOMAIN_HOTPATCH_AUTOLOAD: ++ ret = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath); ++ break; ++ + default: + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Unknow hotpatch action")); +diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c +index 31ef5bb7f2..0259ae76c8 100644 +--- a/src/qemu/qemu_hotpatch.c ++++ b/src/qemu/qemu_hotpatch.c +@@ -25,6 +25,8 @@ + #include "virerror.h" + #include "virfile.h" + #include "virlog.h" ++#include "virbuffer.h" ++#include "virstring.h" + #include "vircommand.h" + #include "qemu/qemu_domain.h" + #include "qemu_hotpatch.h" +@@ -32,6 +34,7 @@ + #define LIBCARE_CTL "libcare-ctl" + #define LIBCARE_ERROR_NUMBER 255 + #define MAX_PATCHID_LEN 8 ++#define MAX_FILE_SIZE (1024*1024) + + #define VIR_FROM_THIS VIR_FROM_QEMU + +@@ -204,3 +207,120 @@ qemuDomainHotpatchUnapply(virDomainObj *vm, + VIR_FREE(output); + return NULL; + } ++ ++char * ++qemuDomainHotpatchAutoload(virDomainObj *vm, char *hotpatch_path) ++{ ++ g_auto(GStrv) applied_patches = NULL; ++ g_auto(GStrv) lines = NULL; ++ g_autofree char *applied_patch = NULL; ++ g_autofree char *libvirtd_conf = NULL; ++ g_autofree char *patch_conf = NULL; ++ g_autofree char *buf = NULL; ++ char *ret = NULL; ++ int i, j, len; ++ ++ if (hotpatch_path == NULL) { ++ virReportError(VIR_ERR_INVALID_ARG, "%s", ++ _("Invalid hotpatch path.")); ++ return NULL; ++ } ++ ++ /* get hotpatch info from Patch.conf */ ++ patch_conf = g_strdup_printf("%s/Patch.conf", hotpatch_path); ++ if ((len = virFileReadAll(patch_conf, MAX_FILE_SIZE, &buf)) < 0) { ++ virReportError(VIR_ERR_INVALID_ARG, "%s", ++ _("Failed to read Patch.conf file.")); ++ return NULL; ++ } ++ if (len > 0) ++ buf[len-1] = '\0'; ++ ++ lines = g_strsplit(buf, "\n", 0); ++ if (!lines) ++ return NULL; ++ ++ /* get domain hotpatch infomation */ ++ applied_patch = qemuDomainHotpatchQuery(vm); ++ if (!applied_patch) ++ return NULL; ++ ++ applied_patches = g_strsplit(applied_patch, "\n", 0); ++ if (!applied_patches) ++ return NULL; ++ ++ /* load all hotpatch which are listed in Patch.conf one by one */ ++ for (i = 0; lines[i] != NULL; i++) { ++ g_auto(GStrv) patch_info = NULL; ++ g_autofree char *kpatch_dir = NULL; ++ g_autofree char *file_path = NULL; ++ struct dirent *de; ++ g_autoptr(DIR) dh = NULL; ++ int direrr; ++ ++ if (!strstr(lines[i], "QEMU-")) ++ continue; ++ ++ patch_info = g_strsplit(lines[i], " ", 0); ++ if (!patch_info) ++ continue; ++ ++ /* skip already applied patch */ ++ if (strstr(applied_patch, patch_info[2])) ++ continue; ++ ++ /* get the kpatch file name */ ++ kpatch_dir = g_strdup_printf("%s/%s", hotpatch_path, patch_info[1]); ++ if (!kpatch_dir || !virFileExists(kpatch_dir)) ++ return NULL; ++ ++ if (virDirOpen(&dh, kpatch_dir) < 0) ++ return NULL; ++ if ((direrr = virDirRead(dh, &de, kpatch_dir)) > 0) { ++ GStatBuf sb; ++ ++ file_path = g_strdup_printf("%s/%s", kpatch_dir, de->d_name); ++ if (g_lstat(file_path, &sb) < 0) { ++ virReportSystemError(errno, _("Cannot access '%s'"), ++ file_path); ++ return NULL; ++ } ++ } ++ ++ if (qemuDomainHotpatchApply(vm, file_path) == NULL) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("failed to apply the hotpatch.")); ++ return NULL; ++ } ++ } ++ ++ /* unload the hotpatch which are not listed in Patch.conf */ ++ for (i = 0; applied_patches[i] != NULL; i++) { ++ const char *patch_id = NULL; ++ bool is_need_unload = true; ++ ++ if (!strstr(applied_patches[i], "Patch id")) ++ continue; ++ ++ patch_id = strstr(applied_patches[i], ":") + 1; ++ virSkipSpaces(&patch_id); ++ ++ for (j = 0; lines[j] != NULL; j++) { ++ if (!strstr(lines[j], "QEMU-")) ++ continue; ++ if (strstr(lines[j], patch_id)) { ++ is_need_unload = false; ++ break; ++ } ++ } ++ if (is_need_unload == true) ++ if (qemuDomainHotpatchUnapply(vm, patch_id) == NULL) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("failed to unapply the hotpatch.")); ++ return NULL; ++ } ++ } ++ ++ ret = g_strdup_printf("Hotpatch autoload successfully.\n"); ++ return ret; ++} +diff --git a/src/qemu/qemu_hotpatch.h b/src/qemu/qemu_hotpatch.h +index 3cf22f7fc4..7cab4787c6 100644 +--- a/src/qemu/qemu_hotpatch.h ++++ b/src/qemu/qemu_hotpatch.h +@@ -34,3 +34,6 @@ qemuDomainHotpatchApply(virDomainObj *vm, + char * + qemuDomainHotpatchUnapply(virDomainObj *vm, + const char *id); ++ ++char * ++qemuDomainHotpatchAutoload(virDomainObj *vm, char *path_config); +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 318f9f6182..41e9660ecd 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -61,6 +61,7 @@ + #include "qemu_backup.h" + #include "qemu_dbus.h" + #include "qemu_snapshot.h" ++#include "qemu_hotpatch.h" + + #include "cpu/cpu.h" + #include "cpu/cpu_x86.h" +@@ -7595,6 +7596,7 @@ qemuProcessLaunch(virConnectPtr conn, + g_autofree int *nicindexes = NULL; + unsigned long long maxMemLock = 0; + bool incomingMigrationExtDevices = false; ++ g_autofree char *autoLoadStatus = NULL; + + VIR_DEBUG("conn=%p driver=%p vm=%p name=%s id=%d asyncJob=%d " + "incoming.uri=%s " +@@ -7926,6 +7928,11 @@ qemuProcessLaunch(virConnectPtr conn, + if (qemuProcessDeleteThreadContextHelper(vm, asyncJob) < 0) + goto cleanup; + ++ /* Autoload hotpatch */ ++ if ((autoLoadStatus = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath)) == NULL) { ++ VIR_WARN("Failed to autoload the hotpatch for %s.", vm->def->name); ++ } ++ + ret = 0; + + cleanup: +diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c +index d88ac3cca6..89bd737f19 100644 +--- a/tools/virsh-domain.c ++++ b/tools/virsh-domain.c +@@ -13574,7 +13574,7 @@ static const vshCmdOptDef opts_hotpatch[] = { + {.name = "action", + .type = VSH_OT_DATA, + .flags = VSH_OFLAG_REQ, +- .help = N_("hotpatch action, choose from , and ") ++ .help = N_("hotpatch action, choose from , , and ") + }, + {.name = "patch", + .type = VSH_OT_STRING, +@@ -13593,7 +13593,8 @@ VIR_ENUM_IMPL(virDomainHotpatchAction, + "none", + "apply", + "unapply", +- "query"); ++ "query", ++ "autoload"); + + static bool + cmdHotpatch(vshControl *ctl, +-- +2.27.0 + diff --git a/libvirt.spec b/libvirt.spec index 7e47563..b6b1207 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -262,7 +262,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 9.10.0 -Release: 4 +Release: 5 License: LGPLv2+ URL: https://libvirt.org/ @@ -302,6 +302,17 @@ Patch0028: qemu-Make-monitor-aware-of-CPU-clusters.patch Patch0029: tests-Verify-handling-of-CPU-clusters-in-QMP-data.patch Patch0030: docs-Improve-documentation-for-CPU-topology.patch Patch0031: docs-Document-CPU-clusters.patch +Patch0032: Hotpatch-introduce-DomainHotpatchManage-API.patch +Patch0033: hotpatch-Implement-qemuDomainHotpatchManage.patch +Patch0034: hotpatch-introduce-hotpatch-async-job-flag.patch +Patch0035: hotpatch-implement-hotpatch-virsh-api.patch +Patch0036: hotpatch-check-vm-id-and-pid-before-using-hotpatch-a.patch +Patch0037: domain-add-logs-for-virDomainHotpatchManage.patch +Patch0038: hotpatch-virsh-support-autoload-mode.patch +Patch0039: Fix-warnings-found-by-clang.patch +Patch0040: Fix-off-by-one-error-in-udevListInterfacesByStatus.patch +Patch0041: remote-check-for-negative-array-lengths-before-alloc.patch +Patch0042: hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2595,6 +2606,19 @@ exit 0 %endif %changelog +* Wed Apr 10 2024 JiaboFeng - 9.10.0-5 +- hotpatch: if hotpatch_path not in qemu.conf,the hotpatch doesn't antoload +- remote: check for negative array lengths before allocation +- Fix off-by-one error in udevListInterfacesByStatus +- Fix warnings found by clang +- hotpatch: virsh support autoload mode +- domain: add logs for virDomainHotpatchManage +- hotpatch: check vm id and pid before using hotpatch api +- hotpatch: implement hotpatch virsh api +- hotpatch: introduce hotpatch async job flag +- hotpatch: Implement qemuDomainHotpatchManage +- Hotpatch: introduce DomainHotpatchManage API + * Tue Apr 2 2024 JiaboFeng - 9.10.0-4 - docs: Document CPU clusters - docs: Improve documentation for CPU topology diff --git a/remote-check-for-negative-array-lengths-before-alloc.patch b/remote-check-for-negative-array-lengths-before-alloc.patch new file mode 100644 index 0000000..f8def63 --- /dev/null +++ b/remote-check-for-negative-array-lengths-before-alloc.patch @@ -0,0 +1,216 @@ +From 9085bbfb415baa258f58e79c56454a520c03d91f 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(+) + +diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c +index 7daf503b51..7542caa952 100644 +--- a/src/remote/remote_daemon_dispatch.c ++++ b/src/remote/remote_daemon_dispatch.c +@@ -2291,6 +2291,10 @@ remoteDispatchDomainGetSchedulerParameters(virNetServer *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; +@@ -2339,6 +2343,10 @@ remoteDispatchDomainGetSchedulerParametersFlags(virNetServer *server G_GNUC_UNUS + 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; +@@ -2497,6 +2505,10 @@ remoteDispatchDomainBlockStatsFlags(virNetServer *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; +@@ -2717,6 +2729,14 @@ remoteDispatchDomainGetVcpuPinInfo(virNetServer *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; +@@ -2811,6 +2831,11 @@ remoteDispatchDomainGetEmulatorPinInfo(virNetServer *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) + cpumaps = g_new0(unsigned char, args->maplen); +@@ -2858,6 +2883,14 @@ remoteDispatchDomainGetVcpus(virNetServer *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; +@@ -3096,6 +3129,10 @@ remoteDispatchDomainGetMemoryParameters(virNetServer *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; +@@ -3156,6 +3193,10 @@ remoteDispatchDomainGetNumaParameters(virNetServer *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; +@@ -3216,6 +3257,10 @@ remoteDispatchDomainGetBlkioParameters(virNetServer *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; +@@ -3277,6 +3322,10 @@ remoteDispatchNodeGetCPUStats(virNetServer *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; +@@ -3339,6 +3388,10 @@ remoteDispatchNodeGetMemoryStats(virNetServer *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; +@@ -3514,6 +3567,10 @@ remoteDispatchDomainGetBlockIoTune(virNetServer *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; +@@ -5079,6 +5136,10 @@ remoteDispatchDomainGetInterfaceParameters(virNetServer *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; +@@ -5299,6 +5360,10 @@ remoteDispatchNodeGetMemoryParameters(virNetServer *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 5ce988c5ae..c5842dc796 100755 +--- a/src/rpc/gendispatch.pl ++++ b/src/rpc/gendispatch.pl +@@ -1070,6 +1070,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 + -- Gitee