From dc2b6e092b3c748ed54423eecc1eb6cf7edf4786 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jan 31 2023 01:24:51 +0000 Subject: import libvirt-8.0.0-14.module+el8.8.0+17806+11a519fc --- diff --git a/SOURCES/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch b/SOURCES/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch new file mode 100644 index 0000000..c02569a --- /dev/null +++ b/SOURCES/libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch @@ -0,0 +1,75 @@ +From b0fb5cbba2e03fbca8471487bf78931b3090b108 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jim Fehlig +Date: Mon, 10 Jan 2022 11:42:58 -0700 +Subject: [PATCH] build: Only install libvirt-guests when building libvirtd + +libvirt-guests was already moved to the libvirt daemon package in commit +d800c50349. It only needs to be installed when building libvirtd. + +Signed-off-by: Jim Fehlig +Reviewed-by: Andrea Bolognani +(cherry picked from commit 3be5ba11a2c6fcb2dfdffa03ab4f847113f36b85) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2153688 +Signed-off-by: Michal Privoznik +--- + tools/meson.build | 38 ++++++++++++++++++++------------------ + 1 file changed, 20 insertions(+), 18 deletions(-) + +diff --git a/tools/meson.build b/tools/meson.build +index 22fa3604ba..2d0aecb90b 100644 +--- a/tools/meson.build ++++ b/tools/meson.build +@@ -297,29 +297,31 @@ if conf.has('WITH_SANLOCK') + ) + endif + +-configure_file( +- input: 'libvirt-guests.sh.in', +- output: '@BASENAME@', +- configuration: tools_conf, +- install: true, +- install_dir: libexecdir, +- install_mode: 'rwxrwxr-x', +-) +- +-if init_script == 'systemd' +- install_data( +- 'libvirt-guests.sysconf', +- install_dir: sysconfdir / 'sysconfig', +- rename: 'libvirt-guests', +- ) +- ++if conf.has('WITH_LIBVIRTD') + configure_file( +- input: 'libvirt-guests.service.in', ++ input: 'libvirt-guests.sh.in', + output: '@BASENAME@', + configuration: tools_conf, + install: true, +- install_dir: prefix / 'lib' / 'systemd' / 'system', ++ install_dir: libexecdir, ++ install_mode: 'rwxrwxr-x', + ) ++ ++ if init_script == 'systemd' ++ install_data( ++ 'libvirt-guests.sysconf', ++ install_dir: sysconfdir / 'sysconfig', ++ rename: 'libvirt-guests', ++ ) ++ ++ configure_file( ++ input: 'libvirt-guests.service.in', ++ output: '@BASENAME@', ++ configuration: tools_conf, ++ install: true, ++ install_dir: prefix / 'lib' / 'systemd' / 'system', ++ ) ++ endif + endif + + if bash_completion_dep.found() +-- +2.39.0 + diff --git a/SOURCES/libvirt-qemu-Ignore-missing-vm.unprivileged_userfaultfd-sysctl.patch b/SOURCES/libvirt-qemu-Ignore-missing-vm.unprivileged_userfaultfd-sysctl.patch new file mode 100644 index 0000000..0113c82 --- /dev/null +++ b/SOURCES/libvirt-qemu-Ignore-missing-vm.unprivileged_userfaultfd-sysctl.patch @@ -0,0 +1,38 @@ +From 08fef741d85ecfb3493c47f5f1334f91c30e3233 Mon Sep 17 00:00:00 2001 +Message-Id: <08fef741d85ecfb3493c47f5f1334f91c30e3233@dist-git> +From: Jiri Denemark +Date: Wed, 9 Feb 2022 11:08:42 +0100 +Subject: [PATCH] qemu: Ignore missing vm.unprivileged_userfaultfd sysctl +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Older kernels did not support this sysctl, but they did not restrict +userfaultfd in any way so everything worked as if +vm.unprivileged_userfaultfd was set to 1. Thus we can safely ignore +errors when setting the value. + +Signed-off-by: Jiri Denemark +Reviewed-by: Ján Tomko +(cherry picked from commit 558f00397a0d46ad22bf53a22a40ed6fc4fdb5eb) + +https://bugzilla.redhat.com/show_bug.cgi?id=2148578 + +Signed-off-by: Jiri Denemark +--- + src/qemu/postcopy-migration.sysctl | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/qemu/postcopy-migration.sysctl b/src/qemu/postcopy-migration.sysctl +index aa8f015ae0..db3f11e49f 100644 +--- a/src/qemu/postcopy-migration.sysctl ++++ b/src/qemu/postcopy-migration.sysctl +@@ -3,4 +3,4 @@ + # privileged processes. + # It can be safely overridden by a file in /etc/sysctl.d/ in case post-copy + # migration is not used on the host. +-vm.unprivileged_userfaultfd = 1 ++-vm.unprivileged_userfaultfd = 1 +-- +2.39.0 + diff --git a/SOURCES/libvirt-qemu-gpu-Get-pid-without-binary-validation.patch b/SOURCES/libvirt-qemu-gpu-Get-pid-without-binary-validation.patch new file mode 100644 index 0000000..9b31b4b --- /dev/null +++ b/SOURCES/libvirt-qemu-gpu-Get-pid-without-binary-validation.patch @@ -0,0 +1,67 @@ +From c70b1a8d8a4bc34bcbf9ef4bccac678257b8c494 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Vasiliy Ulyanov +Date: Wed, 2 Feb 2022 17:28:17 +0100 +Subject: [PATCH] qemu: gpu: Get pid without binary validation + +The binary validation in virPidFileReadPathIfAlive may fail with EACCES +if the calling process does not have CAP_SYS_PTRACE capability. +Therefore instead do only the check that the pidfile is locked by the +correct process. + +Fixes the same issue as with swtpm. + +Signed-off-by: Vasiliy Ulyanov +Signed-off-by: Michal Privoznik +Reviewed-by: Michal Privoznik +(cherry picked from commit e3dfa52d260da8a41a0ec35767d08e37c825824a) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152188 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_vhost_user_gpu.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/src/qemu/qemu_vhost_user_gpu.c b/src/qemu/qemu_vhost_user_gpu.c +index ef198a4820..f7d444e851 100644 +--- a/src/qemu/qemu_vhost_user_gpu.c ++++ b/src/qemu/qemu_vhost_user_gpu.c +@@ -54,7 +54,6 @@ qemuVhostUserGPUCreatePidFilename(const char *stateDir, + + /* + * qemuVhostUserGPUGetPid: +- * @binpath: path of executable associated with the pidfile + * @stateDir: the directory where vhost-user-gpu writes the pidfile into + * @shortName: short name of the domain + * @alias: video device alias +@@ -65,8 +64,7 @@ qemuVhostUserGPUCreatePidFilename(const char *stateDir, + * set to -1; + */ + static int +-qemuVhostUserGPUGetPid(const char *binPath, +- const char *stateDir, ++qemuVhostUserGPUGetPid(const char *stateDir, + const char *shortName, + const char *alias, + pid_t *pid) +@@ -76,7 +74,7 @@ qemuVhostUserGPUGetPid(const char *binPath, + if (!(pidfile = qemuVhostUserGPUCreatePidFilename(stateDir, shortName, alias))) + return -1; + +- if (virPidFileReadPathIfAlive(pidfile, pid, binPath) < 0) ++ if (virPidFileReadPathIfLocked(pidfile, pid) < 0) + return -1; + + return 0; +@@ -253,8 +251,7 @@ qemuExtVhostUserGPUSetupCgroup(virQEMUDriver *driver, + if (!shortname) + return -1; + +- rc = qemuVhostUserGPUGetPid(video->driver->vhost_user_binary, +- cfg->stateDir, shortname, video->info.alias, &pid); ++ rc = qemuVhostUserGPUGetPid(cfg->stateDir, shortname, video->info.alias, &pid); + if (rc < 0 || (rc == 0 && pid == (pid_t)-1)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not get process id of vhost-user-gpu")); +-- +2.39.0 + diff --git a/SOURCES/libvirt-qemu-tpm-Get-swtpm-pid-without-binary-validation.patch b/SOURCES/libvirt-qemu-tpm-Get-swtpm-pid-without-binary-validation.patch new file mode 100644 index 0000000..35c8459 --- /dev/null +++ b/SOURCES/libvirt-qemu-tpm-Get-swtpm-pid-without-binary-validation.patch @@ -0,0 +1,219 @@ +From e3487aab5319df05c5a06a83e4d3e4a87c1e51a9 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Vasiliy Ulyanov +Date: Wed, 2 Feb 2022 17:28:16 +0100 +Subject: [PATCH] qemu: tpm: Get swtpm pid without binary validation + +Access to /proc/[pid]/exe may be restricted in certain environments (e.g. +in containers) and any attempt to stat(2) or readlink(2) the file will +result in 'permission denied' error if the calling process does not have +CAP_SYS_PTRACE capability. According to proc(5) manpage: + +Permission to dereference or read (readlink(2)) this symbolic link is +governed by a ptrace access mode PTRACE_MODE_READ_FSCREDS check; see +ptrace(2). + +The binary validation in virPidFileReadPathIfAlive may fail with EACCES. +Therefore instead do only the check that the pidfile is locked by the +correct process. To ensure this is always the case the daemonization and +pidfile handling of the swtpm command is now controlled by libvirt. + +Signed-off-by: Vasiliy Ulyanov +Signed-off-by: Michal Privoznik +Reviewed-by: Michal Privoznik +(cherry picked from commit a9c500d2b50c5c041a1bb6ae9724402cf1cec8fe) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152188 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_tpm.c | 94 ++++++++++++++++++++++++++------------------- + 1 file changed, 54 insertions(+), 40 deletions(-) + +diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c +index 7e7b01768e..9c5d1ffed4 100644 +--- a/src/qemu/qemu_tpm.c ++++ b/src/qemu/qemu_tpm.c +@@ -44,6 +44,7 @@ + #include "qemu_tpm.h" + #include "virtpm.h" + #include "virsecret.h" ++#include "virtime.h" + + #define VIR_FROM_THIS VIR_FROM_NONE + +@@ -258,13 +259,13 @@ qemuTPMEmulatorGetPid(const char *swtpmStateDir, + const char *shortName, + pid_t *pid) + { +- g_autofree char *swtpm = virTPMGetSwtpm(); + g_autofree char *pidfile = qemuTPMEmulatorCreatePidFilename(swtpmStateDir, + shortName); ++ + if (!pidfile) + return -1; + +- if (virPidFileReadPathIfAlive(pidfile, pid, swtpm) < 0) ++ if (virPidFileReadPathIfLocked(pidfile, pid) < 0) + return -1; + + return 0; +@@ -660,9 +661,6 @@ qemuTPMEmulatorReconfigure(const char *storagepath, + * @privileged: whether we are running in privileged mode + * @swtpm_user: The uid for the swtpm to run as (drop privileges to from root) + * @swtpm_group: The gid for the swtpm to run as +- * @swtpmStateDir: the directory where swtpm writes the pid file and creates the +- * Unix socket +- * @shortName: the short name of the VM + * @incomingMigration: whether we have an incoming migration + * + * Create the virCommand use for starting the emulator +@@ -676,13 +674,10 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, + bool privileged, + uid_t swtpm_user, + gid_t swtpm_group, +- const char *swtpmStateDir, +- const char *shortName, + bool incomingMigration) + { + g_autoptr(virCommand) cmd = NULL; + bool created = false; +- g_autofree char *pidfile = NULL; + g_autofree char *swtpm = virTPMGetSwtpm(); + int pwdfile_fd = -1; + int migpwdfile_fd = -1; +@@ -721,7 +716,7 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, + + virCommandClearCaps(cmd); + +- virCommandAddArgList(cmd, "socket", "--daemon", "--ctrl", NULL); ++ virCommandAddArgList(cmd, "socket", "--ctrl", NULL); + virCommandAddArgFormat(cmd, "type=unixio,path=%s,mode=0600", + tpm->data.emulator.source->data.nix.path); + +@@ -748,12 +743,6 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDef *tpm, + break; + } + +- if (!(pidfile = qemuTPMEmulatorCreatePidFilename(swtpmStateDir, shortName))) +- goto error; +- +- virCommandAddArg(cmd, "--pid"); +- virCommandAddArgFormat(cmd, "file=%s", pidfile); +- + if (tpm->data.emulator.hassecretuuid) { + if (!virTPMSwtpmCapsGet(VIR_TPM_SWTPM_FEATURE_CMDARG_PWD_FD)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, +@@ -904,12 +893,14 @@ qemuExtTPMStartEmulator(virQEMUDriver *driver, + bool incomingMigration) + { + g_autoptr(virCommand) cmd = NULL; +- int exitstatus = 0; +- g_autofree char *errbuf = NULL; ++ VIR_AUTOCLOSE errfd = -1; + g_autoptr(virQEMUDriverConfig) cfg = NULL; + g_autofree char *shortName = virDomainDefGetShortName(vm->def); +- int cmdret = 0, timeout, rc; +- pid_t pid; ++ g_autofree char *pidfile = NULL; ++ virTimeBackOffVar timebackoff; ++ const unsigned long long timeout = 1000; /* ms */ ++ int cmdret = 0; ++ pid_t pid = -1; + + if (!shortName) + return -1; +@@ -923,48 +914,71 @@ qemuExtTPMStartEmulator(virQEMUDriver *driver, + driver->privileged, + cfg->swtpm_user, + cfg->swtpm_group, +- cfg->swtpmStateDir, shortName, + incomingMigration))) + return -1; + + if (qemuExtDeviceLogCommand(driver, vm, cmd, "TPM Emulator") < 0) + return -1; + +- virCommandSetErrorBuffer(cmd, &errbuf); ++ if (!(pidfile = qemuTPMEmulatorCreatePidFilename(cfg->swtpmStateDir, shortName))) ++ return -1; ++ ++ virCommandDaemonize(cmd); ++ virCommandSetPidFile(cmd, pidfile); ++ virCommandSetErrorFD(cmd, &errfd); + + if (qemuSecurityStartTPMEmulator(driver, vm, cmd, + cfg->swtpm_user, cfg->swtpm_group, +- &exitstatus, &cmdret) < 0) ++ NULL, &cmdret) < 0) + return -1; + +- if (cmdret < 0 || exitstatus != 0) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("Could not start 'swtpm'. exitstatus: %d, " +- "error: %s"), exitstatus, errbuf); +- return -1; ++ if (cmdret < 0) { ++ /* virCommandRun() hidden in qemuSecurityStartTPMEmulator() ++ * already reported error. */ ++ goto error; + } + +- /* check that the swtpm has written its pid into the file */ +- timeout = 1000; /* ms */ +- while (timeout > 0) { +- rc = qemuTPMEmulatorGetPid(cfg->swtpmStateDir, shortName, &pid); +- if (rc < 0) { +- timeout -= 50; +- g_usleep(50 * 1000); ++ if (virPidFileReadPath(pidfile, &pid) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("swtpm didn't show up")); ++ goto error; ++ } ++ ++ if (virTimeBackOffStart(&timebackoff, 1, timeout) < 0) ++ goto error; ++ while (virTimeBackOffWait(&timebackoff)) { ++ char errbuf[1024] = { 0 }; ++ ++ if (virFileExists(tpm->data.emulator.source->data.nix.path)) ++ break; ++ ++ if (virProcessKill(pid, 0) == 0) + continue; ++ ++ if (saferead(errfd, errbuf, sizeof(errbuf) - 1) < 0) { ++ virReportSystemError(errno, "%s", ++ _("swtpm died unexpectedly")); ++ } else { ++ virReportError(VIR_ERR_OPERATION_FAILED, ++ _("swtpm died and reported: %s"), errbuf); + } +- if (rc == 0 && pid == (pid_t)-1) +- goto error; +- break; ++ goto error; + } +- if (timeout <= 0) ++ ++ if (!virFileExists(tpm->data.emulator.source->data.nix.path)) { ++ virReportError(VIR_ERR_OPERATION_TIMEOUT, "%s", ++ _("swtpm socket did not show up")); + goto error; ++ } + + return 0; + + error: +- virReportError(VIR_ERR_INTERNAL_ERROR, "%s", +- _("swtpm failed to start")); ++ virCommandAbort(cmd); ++ if (pid >= 0) ++ virProcessKillPainfully(pid, true); ++ if (pidfile) ++ unlink(pidfile); + return -1; + } + +-- +2.39.0 + diff --git a/SOURCES/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch b/SOURCES/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch new file mode 100644 index 0000000..2ed40d8 --- /dev/null +++ b/SOURCES/libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch @@ -0,0 +1,57 @@ +From 1ad707f19e570b76c1f6517194d9cc86b084014d Mon Sep 17 00:00:00 2001 +Message-Id: <1ad707f19e570b76c1f6517194d9cc86b084014d@dist-git> +From: Peter Krempa +Date: Thu, 1 Dec 2022 17:02:42 +0100 +Subject: [PATCH] qemuAgentGetDisks: Don't use virJSONValueObjectGetStringArray + for optional data + +The 'dependencies' field in the return data may be missing in some +cases. Historically 'virJSONValueObjectGetStringArray' didn't report +error in such case, but later refactor (commit 043b50b948ef3c2 ) added +an error in order to use it in other places too. + +Unfortunately this results in the error log being spammed with an +irrelevant error in case when qemuAgentGetDisks is invoked on a VM +running windows. + +Replace the use of virJSONValueObjectGetStringArray by fetching the +array first and calling virJSONValueArrayToStringList only when we have +an array. + +Fixes: 043b50b948ef3c2a4adf5fa32a93ec2589851ac6 +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2149752 +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 3b576601dfb924bb518870a01de5d1a421cbb467) +--- + src/qemu/qemu_agent.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c +index f33cd47078..8a55044c9e 100644 +--- a/src/qemu/qemu_agent.c ++++ b/src/qemu/qemu_agent.c +@@ -2550,6 +2550,7 @@ int qemuAgentGetDisks(qemuAgent *agent, + for (i = 0; i < ndata; i++) { + virJSONValue *addr; + virJSONValue *entry = virJSONValueArrayGet(data, i); ++ virJSONValue *dependencies; + qemuAgentDiskInfo *disk; + + if (!entry) { +@@ -2575,7 +2576,11 @@ int qemuAgentGetDisks(qemuAgent *agent, + goto error; + } + +- disk->dependencies = virJSONValueObjectGetStringArray(entry, "dependencies"); ++ if ((dependencies = virJSONValueObjectGetArray(entry, "dependencies"))) { ++ if (!(disk->dependencies = virJSONValueArrayToStringList(dependencies))) ++ goto error; ++ } ++ + disk->alias = g_strdup(virJSONValueObjectGetString(entry, "alias")); + addr = virJSONValueObjectGetObject(entry, "address"); + if (addr) { +-- +2.39.0 + diff --git a/SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch b/SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch new file mode 100644 index 0000000..8185b76 --- /dev/null +++ b/SOURCES/libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch @@ -0,0 +1,57 @@ +From c5c8bb4aafc8f247e6da146a6683174038611600 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Wed, 28 Sep 2022 10:12:36 +0200 +Subject: [PATCH] qemuProcessReconnect: Don't build memory paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let me take you on a short trip to history. A long time ago, +libvirt would configure all QEMUs to use $hugetlbfs/libvirt/qemu +for their hugepages setup. This was problematic, because it did +not allow enough separation between guests. Therefore in +v3.0.0-rc1~367 the path changed to a per-domain basis: + + $hugetlbfs/libvirt/qemu/$domainShortName + +And to help with migration on daemon restart a call to +qemuProcessBuildDestroyMemoryPaths() was added to +qemuProcessReconnect() (well, it was named +qemuProcessBuildDestroyHugepagesPath() back then, see +v3.10.0-rc1~174). This was desirable then, because the memory +hotplug code did not call the function, it simply assumes +per-domain paths to exist. But this changed in v3.5.0-rc1~92 +after which the per-domain paths are created on memory hotplug +too. + +Therefore, it's no longer necessary to create these paths in +qemuProcessReconnect(). They are created exactly when needed +(domain startup and memory hotplug). + +Signed-off-by: Michal Privoznik +Reviewed-by: Ján Tomko +(cherry picked from commit 3478cca80ea7382cfdbff836d5d0b92aa014297b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 1164340aa9..0fb665bc82 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -8869,9 +8869,6 @@ qemuProcessReconnect(void *opaque) + goto cleanup; + } + +- if (qemuProcessBuildDestroyMemoryPaths(driver, obj, NULL, true) < 0) +- goto error; +- + if ((qemuDomainAssignAddresses(obj->def, priv->qemuCaps, + driver, obj, false)) < 0) { + goto error; +-- +2.38.0 + diff --git a/SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch b/SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch new file mode 100644 index 0000000..3df3a96 --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch @@ -0,0 +1,80 @@ +From 215adedb16aa082d052f84705338de0d77721fe0 Mon Sep 17 00:00:00 2001 +Message-Id: <215adedb16aa082d052f84705338de0d77721fe0@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:43:22 +0200 +Subject: [PATCH] qemu_namespace: Fix a corner case in + qemuDomainGetPreservedMounts() + +When setting up namespace for QEMU we look at mount points under +/dev (like /dev/pts, /dev/mqueue/, etc.) because we want to +preserve those (which is done by moving them to a temp location, +unshare(), and then moving them back). We have a convenience +helper - qemuDomainGetPreservedMounts() - that processes the +mount table and (optionally) moves the other filesystems too. +This helper is also used when attempting to create a path in NS, +because the path, while starting with "/dev/" prefix, may +actually lead to one of those filesystems that we preserved. + +And here comes the corner case: while we require the parent mount +table to be in shared mode (equivalent of `mount --make-rshared /'), +these mount events propagate iff the target path exist inside the +slave mount table (= QEMU's private namespace). And since we +create only a subset of /dev nodes, well, that assumption is not +always the case. + +For instance, assume that a domain is already running, no +hugepages were configured for it nor any hugetlbfs is mounted. +Now, when a hugetlbfs is mounted into '/dev/hugepages', this is +propagated into the QEMU's namespace, but since the target dir +does not exist in the private /dev, the FS is not mounted in the +namespace. + +Fortunately, this difference between namespaces is visible when +comparing /proc/mounts and /proc/$PID/mounts (where PID is the +QEMU's PID). Therefore, if possible we should look at the latter. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 46b03819ae8d833b11c2aaccb2c2a0361727f51b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index 4bff325a2c..fc286ab0be 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -110,6 +110,8 @@ qemuDomainGetPreservedMountPath(virQEMUDriverConfig *cfg, + * b) generate backup path for all the entries in a) + * + * Any of the return pointers can be NULL. Both arrays are NULL-terminated. ++ * Get the mount table either from @vm's PID (if running), or from the ++ * namespace we're in (if @vm's not running). + * + * Returns 0 on success, -1 otherwise (with error reported) + */ +@@ -124,12 +126,18 @@ qemuDomainGetPreservedMounts(virQEMUDriverConfig *cfg, + size_t nmounts = 0; + g_auto(GStrv) paths = NULL; + g_auto(GStrv) savePaths = NULL; ++ g_autofree char *mountsPath = NULL; + size_t i; + + if (ndevPath) + *ndevPath = 0; + +- if (virFileGetMountSubtree(QEMU_PROC_MOUNTS, "/dev", &mounts, &nmounts) < 0) ++ if (vm->pid > 0) ++ mountsPath = g_strdup_printf("/proc/%lld/mounts", (long long) vm->pid); ++ else ++ mountsPath = g_strdup(QEMU_PROC_MOUNTS); ++ ++ if (virFileGetMountSubtree(mountsPath, "/dev", &mounts, &nmounts) < 0) + return -1; + + if (nmounts == 0) +-- +2.38.0 + diff --git a/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch b/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch new file mode 100644 index 0000000..bb83813 --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch @@ -0,0 +1,68 @@ +From d515c964d740274d01bb8de1e5b0351490d6b9d3 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:43:58 +0200 +Subject: [PATCH] qemu_namespace: Introduce qemuDomainNamespaceSetupPath() + +Sometimes it may come handy to just bind mount a directory/file +into domain's namespace. Implement a thin wrapper over +qemuNamespaceMknodPaths() which has all the logic we need. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 5853d707189005a4ea5b2215e80853867b822fd9) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 19 +++++++++++++++++++ + src/qemu/qemu_namespace.h | 4 ++++ + 2 files changed, 23 insertions(+) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index fc286ab0be..74ffd6fb90 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1398,6 +1398,25 @@ qemuNamespaceUnlinkPaths(virDomainObj *vm, + } + + ++int ++qemuDomainNamespaceSetupPath(virDomainObj *vm, ++ const char *path, ++ bool *created) ++{ ++ g_autoptr(virGSListString) paths = NULL; ++ ++ if (!qemuDomainNamespaceEnabled(vm, QEMU_DOMAIN_NS_MOUNT)) ++ return 0; ++ ++ paths = g_slist_prepend(paths, g_strdup(path)); ++ ++ if (qemuNamespaceMknodPaths(vm, paths, created) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++ + int + qemuDomainNamespaceSetupDisk(virDomainObj *vm, + virStorageSource *src, +diff --git a/src/qemu/qemu_namespace.h b/src/qemu/qemu_namespace.h +index 020aca13d8..1ab9322061 100644 +--- a/src/qemu/qemu_namespace.h ++++ b/src/qemu/qemu_namespace.h +@@ -49,6 +49,10 @@ void qemuDomainDestroyNamespace(virQEMUDriver *driver, + + bool qemuDomainNamespaceAvailable(qemuDomainNamespace ns); + ++int qemuDomainNamespaceSetupPath(virDomainObj *vm, ++ const char *path, ++ bool *created); ++ + int qemuDomainNamespaceSetupDisk(virDomainObj *vm, + virStorageSource *src, + bool *created); +-- +2.38.0 + diff --git a/SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch b/SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch new file mode 100644 index 0000000..ceccc0b --- /dev/null +++ b/SOURCES/libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch @@ -0,0 +1,45 @@ +From 7c7ec6e6c20675a99abe8685c715dc95e7e8dbff Mon Sep 17 00:00:00 2001 +Message-Id: <7c7ec6e6c20675a99abe8685c715dc95e7e8dbff@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:37:23 +0200 +Subject: [PATCH] qemu_namespace: Tolerate missing ACLs when creating a path in + namespace + +When creating a path in a domain's mount namespace we try to set +ACLs on it, so that it's a verbatim copy of the path in parent's +namespace. The ACLs are queried upfront (by +qemuNamespaceMknodItemInit()) but this is fault tolerant so the +pointer to ACLs might be NULL (meaning no ACLs were queried, for +instance because the underlying filesystem does not support +them). But then we take this NULL and pass it to virFileSetACLs() +which immediately returns an error because NULL is invalid value. + +Mimic what we do with SELinux label - only set ACLs if they are +non-NULL which includes symlinks. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 687374959e160dc566bd4b6d43c7bf1beb470c59) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_namespace.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_namespace.c b/src/qemu/qemu_namespace.c +index 94453033f5..4bff325a2c 100644 +--- a/src/qemu/qemu_namespace.c ++++ b/src/qemu/qemu_namespace.c +@@ -1023,8 +1023,7 @@ qemuNamespaceMknodOne(qemuNamespaceMknodItem *data) + goto cleanup; + } + +- /* Symlinks don't have ACLs. */ +- if (!isLink && ++ if (data->acl && + virFileSetACLs(data->file, data->acl) < 0 && + errno != ENOTSUP) { + virReportSystemError(errno, +-- +2.38.0 + diff --git a/SOURCES/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch b/SOURCES/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch new file mode 100644 index 0000000..5552bf4 --- /dev/null +++ b/SOURCES/libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch @@ -0,0 +1,50 @@ +From f745b9ae2d12df0c0f2253c295f3d411a8a4165d Mon Sep 17 00:00:00 2001 +Message-Id: +From: Michal Privoznik +Date: Mon, 5 Sep 2022 10:34:44 +0200 +Subject: [PATCH] qemu_process: Don't require a hugetlbfs mount for memfd + +The aim of qemuProcessNeedHugepagesPath() is to determine whether +a hugetlbfs mount point is required for given domain (as in +whether qemuBuildMemoryBackendProps() picks up +memory-backend-file pointing to a hugetlbfs mount point). Well, +when domain is configured to use memfd backend then that +condition can never be true. Therefore, skip creating domain's +private path under hugetlbfs mount points. + +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit f14f8dff9330ed51d817f190a2ee9ac76dfac00b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 5c6657a876..540eee9ff0 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3810,8 +3810,18 @@ qemuProcessNeedHugepagesPath(virDomainDef *def, + const long system_pagesize = virGetSystemPageSizeKB(); + size_t i; + +- if (def->mem.source == VIR_DOMAIN_MEMORY_SOURCE_FILE) ++ switch ((virDomainMemorySource)def->mem.source) { ++ case VIR_DOMAIN_MEMORY_SOURCE_FILE: ++ /* This needs a hugetlbfs mount. */ + return true; ++ case VIR_DOMAIN_MEMORY_SOURCE_MEMFD: ++ /* memfd works without a hugetlbfs mount */ ++ return false; ++ case VIR_DOMAIN_MEMORY_SOURCE_NONE: ++ case VIR_DOMAIN_MEMORY_SOURCE_ANONYMOUS: ++ case VIR_DOMAIN_MEMORY_SOURCE_LAST: ++ break; ++ } + + for (i = 0; i < def->mem.nhugepages; i++) { + if (def->mem.hugepages[i].size != system_pagesize) +-- +2.38.0 + diff --git a/SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch b/SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch new file mode 100644 index 0000000..be102cd --- /dev/null +++ b/SOURCES/libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch @@ -0,0 +1,65 @@ +From 2aeb222d9d61868ef40932b4349af84696415e11 Mon Sep 17 00:00:00 2001 +Message-Id: <2aeb222d9d61868ef40932b4349af84696415e11@dist-git> +From: Michal Privoznik +Date: Tue, 6 Sep 2022 13:45:51 +0200 +Subject: [PATCH] qemu_process.c: Propagate hugetlbfs mounts on reconnect + +When reconnecting to a running QEMU process, we construct the +per-domain path in all hugetlbfs mounts. This is a relict from +the past (v3.4.0-100-g5b24d25062) where we switched to a +per-domain path and we want to create those paths when libvirtd +restarts on upgrade. + +And with namespaces enabled there is one corner case where the +path is not created. In fact an error is reported and the +reconnect fails. Ideally, all mount events are propagated into +the QEMU's namespace. And they probably are, except when the +target path does not exist inside the namespace. Now, it's pretty +common for users to mount hugetlbfs under /dev (e.g. +/dev/hugepages), but if domain is started without hugepages (or +more specifically - private hugetlbfs path wasn't created on +domain startup), then the reconnect code tries to create it. +But it fails to do so, well, it fails to set seclabels on the +path because, because the path does not exist in the private +namespace. And it doesn't exist because we specifically create +only a subset of all possible /dev nodes. Therefore, the mount +event, whilst propagated, is not successful and hence the +filesystem is not mounted. We have to do it ourselves. + +If hugetlbfs is mount anywhere else there's no problem and this +is effectively a dead code. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +Reviewed-by: Martin Kletzander +(cherry picked from commit 0377177c7856bb87a9d8aa1324b54f5fbe9f1e5b) + +Conflicts: +- docs/kbase/qemu-passthrough-security.rst: Well, v8.8.0-rc1~32 + isn't backported, thus we can't remove a paragraph that the + backported commit did. It's a documentation after all, so no + harm. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2123196 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_process.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 540eee9ff0..1164340aa9 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -3906,6 +3906,9 @@ qemuProcessBuildDestroyMemoryPathsImpl(virQEMUDriver *driver, + return -1; + } + ++ if (qemuDomainNamespaceSetupPath(vm, path, NULL) < 0) ++ return -1; ++ + if (qemuSecurityDomainSetPathLabel(driver, vm, path, true) < 0) + return -1; + } else { +-- +2.38.0 + diff --git a/SOURCES/libvirt-qemu_tpm-Do-async-IO-when-starting-swtpm-emulator.patch b/SOURCES/libvirt-qemu_tpm-Do-async-IO-when-starting-swtpm-emulator.patch new file mode 100644 index 0000000..6ee2c59 --- /dev/null +++ b/SOURCES/libvirt-qemu_tpm-Do-async-IO-when-starting-swtpm-emulator.patch @@ -0,0 +1,49 @@ +From 87b0f241db1eba0e9db1fd233c5ab8a8d0115979 Mon Sep 17 00:00:00 2001 +Message-Id: <87b0f241db1eba0e9db1fd233c5ab8a8d0115979@dist-git> +From: Michal Privoznik +Date: Mon, 21 Mar 2022 13:33:06 +0100 +Subject: [PATCH] qemu_tpm: Do async IO when starting swtpm emulator +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When vTPM is secured via virSecret libvirt passes the secret +value via an FD when swtpm is started (arguments --key and +--migration-key). The writing of the secret into the FDs is +handled via virCommand, specifically qemu_tpm calls +virCommandSetSendBuffer()) and then virCommandRunAsync() spawns a +thread to handle writing into the FD via +virCommandDoAsyncIOHelper. But the thread is not created unless +VIR_EXEC_ASYNC_IO flag is set, which it isn't. In order to fix +it, virCommandDoAsyncIO() must be called. + +The credit goes to Marc-André Lureau + who has done all the debugging and +proposed fix in the bugzilla. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2064115 +Fixes: a9c500d2b50c5c041a1bb6ae9724402cf1cec8fe +Signed-off-by: Michal Privoznik +Reviewed-by: Jiri Denemark +(cherry picked from commit 4d7bb0177a33c4e90fd001edfe27bc030354d875) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152188 +Signed-off-by: Michal Privoznik +--- + src/qemu/qemu_tpm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/qemu/qemu_tpm.c b/src/qemu/qemu_tpm.c +index 9c5d1ffed4..29dcb2ac0f 100644 +--- a/src/qemu/qemu_tpm.c ++++ b/src/qemu/qemu_tpm.c +@@ -923,6 +923,7 @@ qemuExtTPMStartEmulator(virQEMUDriver *driver, + if (!(pidfile = qemuTPMEmulatorCreatePidFilename(cfg->swtpmStateDir, shortName))) + return -1; + ++ virCommandDoAsyncIO(cmd); + virCommandDaemonize(cmd); + virCommandSetPidFile(cmd, pidfile); + virCommandSetErrorFD(cmd, &errfd); +-- +2.39.0 + diff --git a/SOURCES/libvirt-tools-Fix-install_mode-for-some-scripts.patch b/SOURCES/libvirt-tools-Fix-install_mode-for-some-scripts.patch new file mode 100644 index 0000000..7cea092 --- /dev/null +++ b/SOURCES/libvirt-tools-Fix-install_mode-for-some-scripts.patch @@ -0,0 +1,65 @@ +From 48f4d21cf73e15e145258bf1d590ca279838168c Mon Sep 17 00:00:00 2001 +Message-Id: <48f4d21cf73e15e145258bf1d590ca279838168c@dist-git> +From: Michal Privoznik +Date: Thu, 8 Dec 2022 08:39:24 +0100 +Subject: [PATCH] tools: Fix install_mode for some scripts + +Scripts from the following list were installed with group write +bit set: virt-xml-validate, virt-pki-validate, +virt-sanlock-cleanup, libvirt-guests.sh. This is very unusual and +in contrast with the way other scripts/binaries are installed. + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2151202 +Signed-off-by: Michal Privoznik +Reviewed-by: Peter Krempa +Reviewed-by: Jiri Denemark +(cherry picked from commit e771e32f15ff2b263ca70306d93080541a96792b) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2153688 +Signed-off-by: Michal Privoznik +--- + tools/meson.build | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tools/meson.build b/tools/meson.build +index 2d0aecb90b..7c6e527939 100644 +--- a/tools/meson.build ++++ b/tools/meson.build +@@ -247,7 +247,7 @@ configure_file( + configuration: tools_conf, + install: true, + install_dir: bindir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + + configure_file( +@@ -256,7 +256,7 @@ configure_file( + configuration: tools_conf, + install: true, + install_dir: bindir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + + executable( +@@ -293,7 +293,7 @@ if conf.has('WITH_SANLOCK') + configuration: tools_conf, + install: true, + install_dir: sbindir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + endif + +@@ -304,7 +304,7 @@ if conf.has('WITH_LIBVIRTD') + configuration: tools_conf, + install: true, + install_dir: libexecdir, +- install_mode: 'rwxrwxr-x', ++ install_mode: 'rwxr-xr-x', + ) + + if init_script == 'systemd' +-- +2.39.0 + diff --git a/SOURCES/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch b/SOURCES/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch new file mode 100644 index 0000000..11146b6 --- /dev/null +++ b/SOURCES/libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch @@ -0,0 +1,124 @@ +From b7d9527c9d9cc782933a5b852869cbd10e370a3a Mon Sep 17 00:00:00 2001 +Message-Id: +From: Peter Krempa +Date: Thu, 1 Dec 2022 13:32:07 +0100 +Subject: [PATCH] util: json: Split out array->strinlist conversion from + virJSONValueObjectGetStringArray + +Introduce virJSONValueArrayToStringList which does only the conversion +from an array to a stringlist. + +This will allow refactoring the callers to be more careful in case when +they want to handle the existance of the member in the parent object +differently. + +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 6765bdeaf7e9cbdb4c39d47f3b77fb28a498408a) +https://bugzilla.redhat.com/show_bug.cgi?id=2149752 +--- + src/libvirt_private.syms | 1 + + src/util/virjson.c | 43 ++++++++++++++++++++++------------------ + src/util/virjson.h | 2 ++ + 3 files changed, 27 insertions(+), 19 deletions(-) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 5b7a056151..fa734dfd33 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -2513,6 +2513,7 @@ virJSONValueArrayForeachSteal; + virJSONValueArrayGet; + virJSONValueArraySize; + virJSONValueArraySteal; ++virJSONValueArrayToStringList; + virJSONValueCopy; + virJSONValueFree; + virJSONValueFromString; +diff --git a/src/util/virjson.c b/src/util/virjson.c +index 6e13e97e15..5f1565107d 100644 +--- a/src/util/virjson.c ++++ b/src/util/virjson.c +@@ -1312,10 +1312,7 @@ virJSONValueObjectStealObject(virJSONValue *object, + char ** + virJSONValueObjectGetStringArray(virJSONValue *object, const char *key) + { +- g_auto(GStrv) ret = NULL; + virJSONValue *data; +- size_t n; +- size_t i; + + data = virJSONValueObjectGetArray(object, key); + if (!data) { +@@ -1325,32 +1322,40 @@ virJSONValueObjectGetStringArray(virJSONValue *object, const char *key) + return NULL; + } + +- n = virJSONValueArraySize(data); +- ret = g_new0(char *, n + 1); ++ return virJSONValueArrayToStringList(data); ++} ++ ++ ++/** ++ * virJSONValueArrayToStringList: ++ * @data: a JSON array containing strings to convert ++ * ++ * Converts @data a JSON array containing strings to a NULL-terminated string ++ * list. @data must be a JSON array. In case @data is doesn't contain only ++ * strings an error is reported. ++ */ ++char ** ++virJSONValueArrayToStringList(virJSONValue *data) ++{ ++ size_t n = virJSONValueArraySize(data); ++ g_auto(GStrv) ret = g_new0(char *, n + 1); ++ size_t i; ++ + for (i = 0; i < n; i++) { + virJSONValue *child = virJSONValueArrayGet(data, i); +- const char *tmp; + +- if (!child) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("%s array element is missing item %zu"), +- key, i); ++ if (!child || ++ !(ret[i] = g_strdup(virJSONValueGetString(child)))) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("JSON string array contains non-string element")); + return NULL; + } +- +- if (!(tmp = virJSONValueGetString(child))) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("%s array element does not contain a string"), +- key); +- return NULL; +- } +- +- ret[i] = g_strdup(tmp); + } + + return g_steal_pointer(&ret); + } + ++ + /** + * virJSONValueObjectForeachKeyValue: + * @object: JSON object to iterate +diff --git a/src/util/virjson.h b/src/util/virjson.h +index aced48a538..c9f83ab2bc 100644 +--- a/src/util/virjson.h ++++ b/src/util/virjson.h +@@ -172,6 +172,8 @@ virJSONValueObjectGetString(virJSONValue *object, + char ** + virJSONValueObjectGetStringArray(virJSONValue *object, + const char *key); ++char ** ++virJSONValueArrayToStringList(virJSONValue *data); + const char * + virJSONValueObjectGetStringOrNumber(virJSONValue *object, + const char *key); +-- +2.39.0 + diff --git a/SOURCES/libvirt-virpidfile-Add-virPidFileReadPathIfLocked-func.patch b/SOURCES/libvirt-virpidfile-Add-virPidFileReadPathIfLocked-func.patch new file mode 100644 index 0000000..b3b154f --- /dev/null +++ b/SOURCES/libvirt-virpidfile-Add-virPidFileReadPathIfLocked-func.patch @@ -0,0 +1,96 @@ +From 9d0247153a70ab1909d0690ec9b7f4d20e8cb602 Mon Sep 17 00:00:00 2001 +Message-Id: <9d0247153a70ab1909d0690ec9b7f4d20e8cb602@dist-git> +From: Vasiliy Ulyanov +Date: Wed, 2 Feb 2022 17:28:15 +0100 +Subject: [PATCH] virpidfile: Add virPidFileReadPathIfLocked func + +The function will attempt to read a pid from @path, and store it in +@pid. The @pid will only be set, however, if @path is locked by +virFileLock() at byte 0 and the pid in @path is running. + +Signed-off-by: Vasiliy Ulyanov +Signed-off-by: Michal Privoznik +Reviewed-by: Michal Privoznik +(cherry picked from commit 013ab22f79d1345daf6b2778ca498acb16939011) +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2152188 +Signed-off-by: Michal Privoznik +--- + src/libvirt_private.syms | 1 + + src/util/virpidfile.c | 35 +++++++++++++++++++++++++++++++++++ + src/util/virpidfile.h | 2 ++ + 3 files changed, 38 insertions(+) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index fa734dfd33..568b0f34a1 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -3061,6 +3061,7 @@ virPidFileRead; + virPidFileReadIfAlive; + virPidFileReadPath; + virPidFileReadPathIfAlive; ++virPidFileReadPathIfLocked; + virPidFileRelease; + virPidFileReleasePath; + virPidFileWrite; +diff --git a/src/util/virpidfile.c b/src/util/virpidfile.c +index 7069f8343d..9d194f7336 100644 +--- a/src/util/virpidfile.c ++++ b/src/util/virpidfile.c +@@ -302,6 +302,41 @@ int virPidFileReadIfAlive(const char *dir, + return 0; + } + ++/** ++ * virPidFileReadPathIfLocked: ++ * @path: path to pidfile ++ * @pid: variable to return pid in ++ * ++ * This will attempt to read a pid from @path, and store it in ++ * @pid. The @pid will only be set, however, if the pid in @path ++ * is running, and @path is locked by virFileLock() at byte 0 ++ * (which is exactly what virCommandSetPidFile() results in). ++ * This adds protection against returning a stale pid. ++ * ++ * Returns -1 upon error, or zero on successful ++ * reading of the pidfile. If @path is not locked ++ * or if the PID was not still alive, zero will ++ * be returned, but @pid will be set to -1. ++ */ ++int virPidFileReadPathIfLocked(const char *path, pid_t *pid) ++{ ++ VIR_AUTOCLOSE fd = -1; ++ ++ if ((fd = open(path, O_RDWR)) < 0) ++ return -1; ++ ++ if (virFileLock(fd, false, 0, 1, false) >= 0) { ++ /* The file isn't locked. PID is stale. */ ++ *pid = -1; ++ return 0; ++ } ++ ++ if (virPidFileReadPathIfAlive(path, pid, NULL) < 0) ++ return -1; ++ ++ return 0; ++} ++ + + int virPidFileDeletePath(const char *pidfile) + { +diff --git a/src/util/virpidfile.h b/src/util/virpidfile.h +index fd8013c41e..e84542f298 100644 +--- a/src/util/virpidfile.h ++++ b/src/util/virpidfile.h +@@ -48,6 +48,8 @@ int virPidFileReadIfAlive(const char *dir, + const char *name, + pid_t *pid, + const char *binpath) G_GNUC_WARN_UNUSED_RESULT; ++int virPidFileReadPathIfLocked(const char *path, ++ pid_t *pid) G_GNUC_WARN_UNUSED_RESULT; + + int virPidFileDeletePath(const char *path); + int virPidFileDelete(const char *dir, +-- +2.39.0 + diff --git a/SPECS/libvirt.spec b/SPECS/libvirt.spec index 530b2cb..23a9567 100644 --- a/SPECS/libvirt.spec +++ b/SPECS/libvirt.spec @@ -210,7 +210,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 8.0.0 -Release: 10%{?dist}%{?extra_release} +Release: 14%{?dist}%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -267,6 +267,21 @@ Patch44: libvirt-virsh-Add-support-for-VIR_MIGRATE_ZEROCOPY-flag.patch Patch45: libvirt-qemu_migration-Implement-VIR_MIGRATE_ZEROCOPY-flag.patch Patch46: libvirt-security_selinux.c-Relabel-existing-mode-bind-UNIX-sockets.patch Patch47: libvirt-RHEL-qemu_migration-Fix-restoring-memlock-limit-on-destination.patch +Patch48: libvirt-qemu_process-Don-t-require-a-hugetlbfs-mount-for-memfd.patch +Patch49: libvirt-qemu_namespace-Tolerate-missing-ACLs-when-creating-a-path-in-namespace.patch +Patch50: libvirt-qemu_namespace-Fix-a-corner-case-in-qemuDomainGetPreservedMounts.patch +Patch51: libvirt-qemu_namespace-Introduce-qemuDomainNamespaceSetupPath.patch +Patch52: libvirt-qemu_process.c-Propagate-hugetlbfs-mounts-on-reconnect.patch +Patch53: libvirt-qemuProcessReconnect-Don-t-build-memory-paths.patch +Patch54: libvirt-util-json-Split-out-array-strinlist-conversion-from-virJSONValueObjectGetStringArray.patch +Patch55: libvirt-qemuAgentGetDisks-Don-t-use-virJSONValueObjectGetStringArray-for-optional-data.patch +Patch56: libvirt-virpidfile-Add-virPidFileReadPathIfLocked-func.patch +Patch57: libvirt-qemu-tpm-Get-swtpm-pid-without-binary-validation.patch +Patch58: libvirt-qemu_tpm-Do-async-IO-when-starting-swtpm-emulator.patch +Patch59: libvirt-qemu-gpu-Get-pid-without-binary-validation.patch +Patch60: libvirt-build-Only-install-libvirt-guests-when-building-libvirtd.patch +Patch61: libvirt-tools-Fix-install_mode-for-some-scripts.patch +Patch62: libvirt-qemu-Ignore-missing-vm.unprivileged_userfaultfd-sysctl.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -447,6 +462,12 @@ Summary: Server side daemon and supporting files for libvirt library # The client side, i.e. shared libs are in a subpackage Requires: %{name}-libs = %{version}-%{release} +# The libvirt-guests.sh script requires virsh from libvirt-client subpackage, +# but not every deployment wants to use libvirt-guests service. Using +# Recommends here will install libvirt-client by default (if available), but +# RPM won't complain if the package is unavailable, masked, or removed later. +Recommends: %{name}-client = %{version}-%{release} + # netcat is needed on the server side so that clients that have # libvirt < 6.9.0 can connect, but newer versions will prefer # virt-ssh-helper. Making this a Recommends means that it gets @@ -2140,6 +2161,30 @@ exit 0 %changelog +* Wed Jan 11 2023 Jiri Denemark - 8.0.0-14 +- qemu: Ignore missing vm.unprivileged_userfaultfd sysctl (rhbz#2148578) + +* Wed Jan 4 2023 Jiri Denemark - 8.0.0-13 +- build: Only install libvirt-guests when building libvirtd (rhbz#2153688) +- tools: Fix install_mode for some scripts (rhbz#2153688) + +* Tue Dec 13 2022 Jiri Denemark - 8.0.0-12 +- util: json: Split out array->strinlist conversion from virJSONValueObjectGetStringArray (rhbz#2149752) +- qemuAgentGetDisks: Don't use virJSONValueObjectGetStringArray for optional data (rhbz#2149752) +- virpidfile: Add virPidFileReadPathIfLocked func (rhbz#2152188) +- qemu: tpm: Get swtpm pid without binary validation (rhbz#2152188) +- qemu_tpm: Do async IO when starting swtpm emulator (rhbz#2152188) +- qemu: gpu: Get pid without binary validation (rhbz#2152188) +- spec: libvirt-daemon: Add optional dependency on *-client (rhbz#2136591) + +* Fri Oct 7 2022 Jiri Denemark - 8.0.0-11 +- qemu_process: Don't require a hugetlbfs mount for memfd (rhbz#2123196) +- qemu_namespace: Tolerate missing ACLs when creating a path in namespace (rhbz#2123196) +- qemu_namespace: Fix a corner case in qemuDomainGetPreservedMounts() (rhbz#2123196) +- qemu_namespace: Introduce qemuDomainNamespaceSetupPath() (rhbz#2123196) +- qemu_process.c: Propagate hugetlbfs mounts on reconnect (rhbz#2123196) +- qemuProcessReconnect: Don't build memory paths (rhbz#2123196) + * Mon Jul 25 2022 Jiri Denemark - 8.0.0-10 - security_selinux.c: Relabel existing mode="bind" UNIX sockets (rhbz#2101575) - RHEL: qemu_migration: Fix restoring memlock limit on destination (rhbz#2107954)