diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 5e9c65eec3..4f64f878e5 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -245,7 +245,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST,
"kvm-pit-lost-tick-policy",
"boot-strict", /* 160 */
- "pvpanic", /* 161 */
+ "pvpanic",
+ "enable-fips",
);
struct _virQEMUCaps {
@@ -2630,6 +2631,30 @@ virQEMUCapsInitQMP(virQEMUCapsPtr qemuCaps,
config.data.nix.path = monpath;
config.data.nix.listen = false;
+ /* Qemu 1.2 and later have a binary flag -enable-fips that must be
+ * used for VNC auth to obey FIPS settings; but the flag only
+ * exists on Linux, and with no way to probe for it via QMP. Our
+ * solution: if FIPS mode is required, then unconditionally use
+ * the flag, regardless of qemu version, for the following matrix:
+ *
+ * old QEMU new QEMU
+ * FIPS enabled doesn't start VNC auth disabled
+ * FIPS disabled/missing VNC auth enabled VNC auth enabled
+ *
+ * Setting the flag here instead of in virQEMUCapsInitQMPMonitor
+ * or virQEMUCapsInitHelp also allows the testsuite to be
+ * independent of FIPS setting.
+ */
+ if (virFileExists("/proc/sys/crypto/fips_enabled")) {
+ char *buf = NULL;
+
+ if (virFileReadAll("/proc/sys/crypto/fips_enabled", 10, &buf) < 0)
+ goto cleanup;
+ if (STREQ(buf, "1\n"))
+ virQEMUCapsSet(qemuCaps, QEMU_CAPS_ENABLE_FIPS);
+ VIR_FREE(buf);
+ }
+
VIR_DEBUG("Try to get caps via QMP qemuCaps=%p", qemuCaps);
/*
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index bbf4972cf1..efb3f43783 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -200,6 +200,7 @@ enum virQEMUCapsFlags {
QEMU_CAPS_KVM_PIT_TICK_POLICY = 159, /* kvm-pit.lost_tick_policy */
QEMU_CAPS_BOOT_STRICT = 160, /* -boot strict */
QEMU_CAPS_DEVICE_PANIC = 161, /* -device pvpanic */
+ QEMU_CAPS_ENABLE_FIPS = 162, /* -enable-fips */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index a80559e755..d723dc8d16 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -7747,6 +7747,8 @@ qemuBuildCommandLine(virConnectPtr conn,
}
}
virCommandAddArg(cmd, "-S"); /* freeze CPU */
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ENABLE_FIPS))
+ virCommandAddArg(cmd, "-enable-fips");
if (qemuBuildMachineArgStr(cmd, def, qemuCaps) < 0)
goto error;
diff --git a/tests/qemucapabilitiesdata/caps_1.2.2-1.caps b/tests/qemucapabilitiesdata/caps_1.2.2-1.caps
index 73a561dc74..c3ae814b1c 100644
--- a/tests/qemucapabilitiesdata/caps_1.2.2-1.caps
+++ b/tests/qemucapabilitiesdata/caps_1.2.2-1.caps
@@ -112,4 +112,5 @@
+
diff --git a/tests/qemucapabilitiesdata/caps_1.6.0-1.caps b/tests/qemucapabilitiesdata/caps_1.6.0-1.caps
index c7ce591ca7..2d50cf98fc 100644
--- a/tests/qemucapabilitiesdata/caps_1.6.0-1.caps
+++ b/tests/qemucapabilitiesdata/caps_1.6.0-1.caps
@@ -138,4 +138,5 @@
+
diff --git a/tests/qemucapabilitiestest.c b/tests/qemucapabilitiestest.c
index d9121715e7..3b34f78004 100644
--- a/tests/qemucapabilitiestest.c
+++ b/tests/qemucapabilitiestest.c
@@ -31,6 +31,7 @@ typedef testQemuData *testQemuDataPtr;
struct _testQemuData {
virDomainXMLOptionPtr xmlopt;
const char *base;
+ bool fips;
};
static qemuMonitorTestPtr
@@ -192,6 +193,12 @@ testQemuCaps(const void *opaque)
qemuMonitorTestGetMonitor(mon)) < 0)
goto cleanup;
+ /* So that our test does not depend on the contents of /proc, we
+ * hoisted the setting of ENABLE_FIPS to virQEMUCapsInitQMP. But
+ * we do want to test the effect of that flag. */
+ if (data->fips)
+ virQEMUCapsSet(capsComputed, QEMU_CAPS_ENABLE_FIPS);
+
if (testQemuCapsCompare(capsProvided, capsComputed) < 0)
goto cleanup;
@@ -227,16 +234,19 @@ mymain(void)
data.xmlopt = xmlopt;
-#define DO_TEST(name) \
- data.base = name; \
- if (virtTestRun(name, testQemuCaps, &data) < 0) \
+#define DO_TEST_FULL(name, use_fips) \
+ data.base = name; \
+ data.fips = use_fips; \
+ if (virtTestRun(name, testQemuCaps, &data) < 0) \
ret = -1
- DO_TEST("caps_1.2.2-1");
+#define DO_TEST(name) DO_TEST_FULL(name, false)
+
+ DO_TEST_FULL("caps_1.2.2-1", true);
DO_TEST("caps_1.3.1-1");
DO_TEST("caps_1.4.2-1");
DO_TEST("caps_1.5.3-1");
- DO_TEST("caps_1.6.0-1");
+ DO_TEST_FULL("caps_1.6.0-1", true);
DO_TEST("caps_1.6.50-1");
virObjectUnref(xmlopt);