]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: capabilities: Apply 'capability_filters' configration option on all capabilities
authorPeter Krempa <pkrempa@redhat.com>
Thu, 11 Jun 2026 09:33:36 +0000 (11:33 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 18 Jun 2026 09:03:35 +0000 (11:03 +0200)
The 'capability_filters' allows admins to globally disable some qemu
capabilities via the config file.

Until now it was applied only directly when starting the VM, but that is
too late as the capability is still present when e.g. the post-parse
code is picking defaults.

Rework the code so that 'capability_filters' is applied directly after
probing qemu so all existing capabilities will lack the filtered out
ones.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
src/qemu/qemu_capabilities.c
src/qemu/qemu_capabilities.h
src/qemu/qemu_capspriv.h
src/qemu/qemu_driver.c
src/qemu/qemu_process.c
tests/qemucapsprobe.c
tests/testutilsqemu.c

index 1c89c0a1de56ad01a82109f4f5e70b7f9c283f8a..961fbfc336e0f4a07534f8fe5438ab071db684a5 100644 (file)
@@ -4551,6 +4551,11 @@ struct _virQEMUCapsCachePriv {
     /* cache whether /dev/kvm is usable as runUid:runGuid */
     virTristateBool kvmUsable;
     time_t kvmCtime;
+
+    /* qemu.conf allows masking out supported capabilities via
+     * 'capabilities_filter' configuration. 'maskedCaps' if non-NULL
+     * maps out which bits are to be removed */
+    virBitmap *maskedCaps;
 };
 typedef struct _virQEMUCapsCachePriv virQEMUCapsCachePriv;
 
@@ -4564,6 +4569,7 @@ virQEMUCapsCachePrivFree(void *privData)
     g_free(priv->kernelVersion);
     virCPUDataFree(priv->cpuData);
     g_free(priv->hostCPUSignature);
+    virBitmapFree(priv->maskedCaps);
     g_free(priv);
 }
 
@@ -6123,7 +6129,8 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
                                 const char *hostCPUSignature,
                                 unsigned int microcodeVersion,
                                 const char *kernelVersion,
-                                virCPUData* cpuData)
+                                virCPUData* cpuData,
+                                virBitmap *maskedCaps)
 {
     g_autoptr(virQEMUCaps) qemuCaps = virQEMUCapsNewBinary(binary);
     struct stat sb;
@@ -6162,6 +6169,10 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
     qemuCaps->libvirtCtime = virGetSelfLastChanged();
     qemuCaps->libvirtVersion = LIBVIR_VERSION_NUMBER;
 
+    /* If we have capabilities masked out via qemu.conf apply them here */
+    if (maskedCaps)
+        virBitmapSubtract(qemuCaps->flags, maskedCaps);
+
     if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_KVM))
         virQEMUCapsInitHostCPUModel(qemuCaps, hostArch, VIR_DOMAIN_VIRT_KVM);
     if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_HVF))
@@ -6202,7 +6213,8 @@ virQEMUCapsNewData(const char *binary,
                                            priv->hostCPUSignature,
                                            virHostCPUGetMicrocodeVersion(priv->hostArch),
                                            priv->kernelVersion,
-                                           priv->cpuData);
+                                           priv->cpuData,
+                                           priv->maskedCaps);
 }
 
 
@@ -6241,7 +6253,8 @@ virFileCache *
 virQEMUCapsCacheNew(const char *libDir,
                     const char *cacheDir,
                     uid_t runUid,
-                    gid_t runGid)
+                    gid_t runGid,
+                    virBitmap *maskedCaps)
 {
     g_autofree char *capsCacheDir = NULL;
     virFileCache *cache = NULL;
@@ -6271,9 +6284,11 @@ virQEMUCapsCacheNew(const char *libDir,
         priv->kernelVersion = g_strdup_printf("%s %s", uts.release, uts.version);
 
     priv->cpuData = virCPUDataGetHost();
+    priv->maskedCaps = maskedCaps;
     return cache;
 
  error:
+    virBitmapFree(maskedCaps);
     virObjectUnref(cache);
     return NULL;
 }
index b027d37bf3058a9aed9b8454fad3eb20fd40c1d9..71ae8514d5d9bf92f35e46e78f6d82e342c60274 100644 (file)
@@ -868,7 +868,8 @@ char * virQEMUCapsGetDefaultEmulator(virArch hostarch,
 virFileCache *virQEMUCapsCacheNew(const char *libDir,
                                     const char *cacheDir,
                                     uid_t uid,
-                                    gid_t gid);
+                                    gid_t gid,
+                                    virBitmap *maskedCaps);
 virQEMUCaps *virQEMUCapsCacheLookup(virFileCache *cache,
                                       const char *binary);
 virQEMUCaps *virQEMUCapsCacheLookupCopy(virFileCache *cache,
index 55286d7d290941623a2ba6ec325391b356b32bd1..9dca15d09ba6d0653eee05954454fc00f59b1c71 100644 (file)
@@ -36,7 +36,8 @@ virQEMUCapsNewForBinaryInternal(virArch hostArch,
                                 const char *hostCPUSignature,
                                 unsigned int microcodeVersion,
                                 const char *kernelVersion,
-                                virCPUData* cpuData);
+                                virCPUData* cpuData,
+                                virBitmap *maskedCaps);
 
 int virQEMUCapsLoadCache(virArch hostArch,
                          virQEMUCaps *qemuCaps,
index 544955ecf907a14bf214ba9192befbd19d56fe3f..b4cc09c81a01649c907b5b98c30c9ad819dcc542 100644 (file)
@@ -539,6 +539,7 @@ qemuStateInitialize(bool privileged,
     const char *defsecmodel = NULL;
     g_autoptr(virIdentity) identity = virIdentityGetCurrent();
     virDomainDriverAutoStartConfig autostartCfg;
+    g_autoptr(virBitmap) maskedCaps = NULL;
 
     qemu_driver = g_new0(virQEMUDriver, 1);
 
@@ -848,10 +849,30 @@ qemuStateInitialize(bool privileged,
         run_gid = cfg->group;
     }
 
+    if (cfg->capabilityfilters) {
+        int tmp;
+        char **next;
+
+        maskedCaps = virBitmapNew(0);
+
+        for (next = cfg->capabilityfilters; *next; next++) {
+            if ((tmp = virQEMUCapsTypeFromString(*next)) < 0) {
+                virReportError(VIR_ERR_CONF_SYNTAX,
+                               _("invalid capability_filters capability '%1$s'"),
+                               *next);
+                return -1;
+            }
+
+            virBitmapSetBitExpand(maskedCaps, tmp);
+        }
+    }
+
+
     qemu_driver->qemuCapsCache = virQEMUCapsCacheNew(cfg->libDir,
                                                      cfg->cacheDir,
                                                      run_uid,
-                                                     run_gid);
+                                                     run_gid,
+                                                     g_steal_pointer(&maskedCaps));
     if (!qemu_driver->qemuCapsCache)
         goto error;
 
index 530cd442a57d8558a839a5353fe849183db920f6..019f1a0c217052ca98a54db8cebd3dbfa156c71d 100644 (file)
@@ -5915,25 +5915,12 @@ static int
 qemuProcessStartUpdateCustomCaps(virDomainObj *vm)
 {
     qemuDomainObjPrivate *priv = vm->privateData;
-    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(priv->driver);
     qemuDomainXmlNsDef *nsdef = vm->def->namespaceData;
-    char **next;
-    int tmp;
-
-    if (cfg->capabilityfilters) {
-        for (next = cfg->capabilityfilters; *next; next++) {
-            if ((tmp = virQEMUCapsTypeFromString(*next)) < 0) {
-                virReportError(VIR_ERR_INTERNAL_ERROR,
-                               _("invalid capability_filters capability '%1$s'"),
-                               *next);
-                return -1;
-            }
-
-            virQEMUCapsClear(priv->qemuCaps, tmp);
-        }
-    }
 
     if (nsdef) {
+        char **next;
+        int tmp;
+
         for (next = nsdef->capsadd; next && *next; next++) {
             if ((tmp = virQEMUCapsTypeFromString(*next)) < 0) {
                 virReportError(VIR_ERR_INTERNAL_ERROR,
index cd117170ab6a580431d4a5122cbd4be5a9d09e2d..8ce5c10dece494934d4d15b6d5ce098ec11d76e1 100644 (file)
@@ -79,7 +79,8 @@ main(int argc, char **argv)
         return EXIT_FAILURE;
 
     if (!(caps = virQEMUCapsNewForBinaryInternal(VIR_ARCH_NONE, argv[1], "/tmp",
-                                                 -1, -1, NULL, 0, NULL, NULL)))
+                                                 -1, -1, NULL, 0, NULL, NULL,
+                                                 NULL)))
         return EXIT_FAILURE;
 
     host = virArchFromHost();
index 11097dbb3e5353e5a515ec996c13f600ee8fa4a2..e5e3342b5381713dbe83675b1853af23d5ec7435 100644 (file)
@@ -373,7 +373,8 @@ int qemuTestDriverInit(virQEMUDriver *driver)
 
     /* Using /dev/null for libDir and cacheDir automatically produces errors
      * upon attempt to use any of them */
-    driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null", 0, 0);
+    driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null",
+                                                0, 0, NULL);
     if (!driver->qemuCapsCache)
         goto error;