]> xenbits.xensource.com Git - people/dariof/libvirt.git/commitdiff
qemu: ask for -enable-fips when FIPS is required
authorEric Blake <eblake@redhat.com>
Thu, 5 Dec 2013 21:47:09 +0000 (14:47 -0700)
committerEric Blake <eblake@redhat.com>
Wed, 18 Dec 2013 14:05:29 +0000 (07:05 -0700)
On a system that is enforcing FIPS, most libraries honor the
current mode by default.  Qemu, on the other hand, refused to
honor FIPS mode unless you add the '-enable-fips' command
line option; worse, this option is not discoverable via QMP,
and is only present on binaries built for Linux.  So, if we
detect FIPS mode, then we unconditionally ask for FIPS; either
qemu is new enough to have the option and then correctly
cripple insecure VNC passwords, or it is so old that we are
correctly avoiding a FIPS violation by preventing qemu from
starting.  Meanwhile, if we don't detect FIPS mode, then
omitting the argument is safe whether the qemu has the option
(but it would do nothing because FIPS is disabled) or whether
qemu lacks the option (including in the case where we are not
running on Linux).

The testsuite was a bit interesting: we don't want our test
to depend on whether it is being run in FIPS mode, so I had
to tweak things to set the capability bit outside of our
normal interaction with capability parsing.

This fixes https://bugzilla.redhat.com/show_bug.cgi?id=1035474

* src/qemu/qemu_capabilities.h (QEMU_CAPS_ENABLE_FIPS): New bit.
* src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Conditionally
set capability according to detection of FIPS mode.
* src/qemu/qemu_command.c (qemuBuildCommandLine): Use it.
* tests/qemucapabilitiestest.c (testQemuCaps): Conditionally set
capability to test expected output.
* tests/qemucapabilitiesdata/caps_1.2.2-1.caps: Update list.
* tests/qemucapabilitiesdata/caps_1.6.0-1.caps: Likewise.

Signed-off-by: Eric Blake <eblake@redhat.com>
src/qemu/qemu_capabilities.c
src/qemu/qemu_capabilities.h
src/qemu/qemu_command.c
tests/qemucapabilitiesdata/caps_1.2.2-1.caps
tests/qemucapabilitiesdata/caps_1.6.0-1.caps
tests/qemucapabilitiestest.c

index 5e9c65eec3e0e4c2893b14893c0a23e923d56b61..4f64f878e514e68c2ebcef501a726e055a2010a8 100644 (file)
@@ -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);
 
     /*
index bbf4972cf1c40cbe4c937d2e272f55d9168c624a..efb3f4378335fa9bf3dbbc4c61f7a005072dbc83 100644 (file)
@@ -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 */
 };
index a80559e755b29ae1dae2defad7c089a15021f0df..d723dc8d16f7199fd57d1dc12a249b2091ac72fc 100644 (file)
@@ -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;
index 73a561dc74722ba7eb5f5ca0208b54652a782aee..c3ae814b1c5d7650c0442eccf6af9230357a5f8c 100644 (file)
     <flag name='usb-storage'/>
     <flag name='usb-storage.removable'/>
     <flag name='kvm-pit-lost-tick-policy'/>
+    <flag name='enable-fips'/>
   </qemuCaps>
index c7ce591ca752fa40b0f74fb812bb359397bac959..2d50cf98fc5de4bf79e18fe9d4d297d1d835f51a 100644 (file)
     <flag name='boot-strict'/>
     <flag name='pvpanic'/>
     <flag name='reboot-timeout'/>
+    <flag name='enable-fips'/>
   </qemuCaps>
index d9121715e7bbb963be00e96140fd8ee59c8a2138..3b34f78004cd4df239c3a842f0ed413c1111eeb4 100644 (file)
@@ -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);