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 <fengjiabo1@huawei.com>
This commit is contained in:
Jiabo Feng 2024-04-10 21:35:19 +08:00
parent 307ea8abab
commit f5ca4aa04e
12 changed files with 1724 additions and 1 deletions

View File

@ -0,0 +1,39 @@
From 0f082f9d3df0b1c2b63c2b5ad3201e08d1ffe449 Mon Sep 17 00:00:00 2001
From: Martin Kletzander <mkletzan@redhat.com>
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 <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 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

View File

@ -0,0 +1,30 @@
From f3bee7ca84e0e7f915ad425935e6279b227a00a6 Mon Sep 17 00:00:00 2001
From: Chenxi Mao <chenxi.mao@suse.com>
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 <chenxi.mao@suse.com>
---
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

View File

@ -0,0 +1,224 @@
From dd9b8be8f47638f9149f3b577f1c38e36cd3e0db Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Tue, 19 Oct 2021 14:50:32 +0800
Subject: [PATCH] Hotpatch: introduce DomainHotpatchManage API
Signed-off-by: Hao Wang <wanghao232@huawei.com>
Signed-off-by: Bihong Yu <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
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

View File

@ -0,0 +1,45 @@
From a7f63f8c85e3bc287920ed83361e4f44ce2e25d7 Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
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 <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
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

View File

@ -0,0 +1,387 @@
From 2721c0ce65045c90e54fcab383d4af83415bd3f3 Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Tue, 19 Oct 2021 14:50:32 +0800
Subject: [PATCH] hotpatch: Implement qemuDomainHotpatchManage
Signed-off-by: Hao Wang <wanghao232@huawei.com>
Signed-off-by: Bihong Yu <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include <unistd.h>
+#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
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <unistd.h>
+#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

View File

@ -0,0 +1,151 @@
From ebdf0312a590ba60f3d304f338737155f469dd7a Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
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 <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
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

View File

@ -0,0 +1,34 @@
From 033b8d177e4512f0ba3af8ed46ee38a4251c7e1c Mon Sep 17 00:00:00 2001
From: Dawei Jiang <jiangdawei15@huawei.com>
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 <jiangdawei15@huawei.com>
---
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

View File

@ -0,0 +1,110 @@
From d56a3df418b90f4a6f303a3830732b5fde8d3a10 Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Wed, 20 Oct 2021 11:07:34 +0800
Subject: [PATCH] hotpatch: implement hotpatch virsh api
Signed-off-by: Hao Wang <wanghao232@huawei.com>
Signed-off-by: Bihong Yu <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
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 <apply>, <unapply> and <query>")
+ },
+ {.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

View File

@ -0,0 +1,161 @@
From 180e19162083fb74e9e9cbc676ce42611bb2e496 Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Tue, 19 Oct 2021 22:41:24 +0800
Subject: [PATCH] hotpatch: introduce hotpatch async job flag
Signed-off-by: Hao Wang <wanghao232@huawei.com>
Signed-off-by: Bihong Yu <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
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

View File

@ -0,0 +1,302 @@
From 48da26004ea0222cc8819e097a004980662ef3eb Mon Sep 17 00:00:00 2001
From: jiang-dawei15 <jiangdawei15@huawei.com>
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 <apply>, <unapply> and <query>")
+ .help = N_("hotpatch action, choose from <apply>, <unapply>, <query> and <autoload>")
},
{.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

View File

@ -262,7 +262,7 @@
Summary: Library providing a simple virtualization API Summary: Library providing a simple virtualization API
Name: libvirt Name: libvirt
Version: 9.10.0 Version: 9.10.0
Release: 4 Release: 5
License: LGPLv2+ License: LGPLv2+
URL: https://libvirt.org/ 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 Patch0029: tests-Verify-handling-of-CPU-clusters-in-QMP-data.patch
Patch0030: docs-Improve-documentation-for-CPU-topology.patch Patch0030: docs-Improve-documentation-for-CPU-topology.patch
Patch0031: docs-Document-CPU-clusters.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 = %{version}-%{release}
Requires: libvirt-daemon-config-network = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release}
@ -2595,6 +2606,19 @@ exit 0
%endif %endif
%changelog %changelog
* Wed Apr 10 2024 JiaboFeng <fengjiabo1@huawei.com> - 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 <fengjiabo1@huawei.com> - 9.10.0-4 * Tue Apr 2 2024 JiaboFeng <fengjiabo1@huawei.com> - 9.10.0-4
- docs: Document CPU clusters - docs: Document CPU clusters
- docs: Improve documentation for CPU topology - docs: Improve documentation for CPU topology

View File

@ -0,0 +1,216 @@
From 9085bbfb415baa258f58e79c56454a520c03d91f 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] 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 <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 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