Nicolai Stange 267194
From 3c65e45d809ab7d58fd87dfbaef307992ae7d403 Mon Sep 17 00:00:00 2001
Nicolai Stange 267194
From: Nicolai Stange <nstange@suse.de>
Nicolai Stange 267194
Date: Sun, 28 Nov 2021 20:45:56 +0100
Nicolai Stange 267194
Subject: [PATCH 1/2] crypto: implement downstream solution for disabling
Nicolai Stange 267194
 drivers in FIPS mode
Nicolai Stange 3bec27
References: jsc#SLE-21132,bsc#1191270,bsc#1193976
Nicolai Stange 267194
Patch-mainline: Never, downstream solution to block unapproved crypto drivers
Nicolai Stange 267194
Nicolai Stange 267194
Non-verified crypto implementations from drivers/crypto must not be used in
Nicolai Stange 267194
FIPS mode and this has to be enforced from the crypto API.
Nicolai Stange 267194
Nicolai Stange 267194
The most reasonable way of achieving this is to make the testmgr to force
Nicolai Stange 267194
these algorithm instances' tests to fail: the crypto API's lookup
Nicolai Stange 267194
primitives only return algorithm implementations which have successfully
Nicolai Stange 267194
completed their associated tests. From the resp. driver's perspective, the
Nicolai Stange 267194
algorithm registrations would still succeed, so no errors would get thrown
Nicolai Stange 267194
e.g. during boot and potential services outside the scope of FIPS could
Nicolai Stange 267194
still be provided.
Nicolai Stange 267194
Nicolai Stange 267194
Implement the new suse_fips_is_driver_unapproved() for searching a given
Nicolai Stange 267194
driver name on a to-be-populated list of unapproved implementations to be
Nicolai Stange 267194
rejected in FIPS mode. Make alg_test() query it in FIPS mode if the
Nicolai Stange 267194
algorithm has not been determined to be disallowed by some other means
Nicolai Stange 267194
already, i.e. if no matching test with ->fips_allowed == 0 has been found.
Nicolai Stange 267194
Nicolai Stange 267194
Now that it's more common to have driver algorithm instances in failed
Nicolai Stange 267194
state potentially aliasing with approved implementations around, there's
Nicolai Stange 267194
one subtlety in the crypto API's lookup code which needs to get addressed.
Nicolai Stange 267194
A lot of those crypto drivers register "fused" implementations of certain
Nicolai Stange 267194
algorithm constructions, which would otherwise get served by some generic
Nicolai Stange 267194
templates. However, these instances are kept on the global algorithms list
Nicolai Stange 267194
and crypto_alg_lookup() would return -ELIBBAD upon encountering a matching
Nicolai Stange 267194
such one in forced-fail state, c.f. commit eb02c38f0197 ("crypto: api -
Nicolai Stange 267194
Keep failed instances alive"). This would then subsequently prevent the
Nicolai Stange 267194
calling code from attempting to construct an (approved) instantiation of
Nicolai Stange 267194
the generic templates. Make crypto_alg_lookup()'s caller,
Nicolai Stange 267194
crypto_larval_lookup(), pass on the -ELIBBAD only if it had been caused by
Nicolai Stange 267194
some generic template instantiation in failed state, i.e. by a real test
Nicolai Stange 267194
failure rather by than some unapproved driver.
Nicolai Stange 267194
Nicolai Stange 267194
Finally, due to the asynchronous nature of the testmgr execution, the
Nicolai Stange 267194
algorithm registration code always keeps a placeholder test larval on the
Nicolai Stange 267194
global algorithm list until alg_test() eventually gets to run and has a
Nicolai Stange 267194
chance to force-fail the test for unapproved drivers. Until that has
Nicolai Stange 267194
happened, any matching request coming in through crypto_alg_mod_lookup()
Nicolai Stange 267194
would end up waiting on this test larval in crypto_larval_wait().
Nicolai Stange 267194
crypto_larval_wait() would return -EAGAIN once the test has been
Nicolai Stange 267194
force-failed asynchronously and the whole lookup would then subsequently
Nicolai Stange 267194
fail. As failing test larvals are much more common in FIPS mode now, make
Nicolai Stange 267194
crypto_larval_lookup() to retry the whole operation when any of its two
Nicolai Stange 267194
descendant crypto_larval_wait() invocations return -EAGAIN.
Nicolai Stange 267194
Nicolai Stange 267194
Signed-off-by: Nicolai Stange <nstange@suse.de>
Nicolai Stange 267194
---
Nicolai Stange 3bec27
 crypto/api.c                          |   46 +++++++++++++++++++++++++++
Nicolai Stange 267194
 crypto/suse_fips_unapproved_drivers.h |    1 
Nicolai Stange 592d0e
 crypto/testmgr.c                      |   57 ++++++++++++++++++++++++++++++++++
Nicolai Stange 592d0e
 3 files changed, 104 insertions(+)
Nicolai Stange 267194
 create mode 100644 crypto/suse_fips_unapproved_drivers.h
Nicolai Stange 267194
Nicolai Stange 267194
--- a/crypto/api.c
Nicolai Stange 267194
+++ b/crypto/api.c
Nicolai Stange 267194
@@ -20,6 +20,7 @@
Nicolai Stange 267194
 #include <linux/slab.h>
Nicolai Stange 267194
 #include <linux/string.h>
Nicolai Stange 267194
 #include <linux/completion.h>
Nicolai Stange 267194
+#include <linux/fips.h>
Nicolai Stange 267194
 #include "internal.h"
Nicolai Stange 267194
 
Nicolai Stange 267194
 LIST_HEAD(crypto_alg_list);
Nicolai Stange 3bec27
@@ -128,6 +129,15 @@ static struct crypto_alg *crypto_larval_
Nicolai Stange 3bec27
 	struct crypto_alg *alg;
Nicolai Stange 3bec27
 	struct crypto_larval *larval;
Nicolai Stange 3bec27
 
Nicolai Stange 3bec27
+	if (fips_enabled && !((type | mask) & CRYPTO_ALG_TESTED)) {
Nicolai Stange 3bec27
+		/*
Nicolai Stange 3bec27
+		 * Make sure the __crypto_alg_lookup() below won't return
Nicolai Stange 3bec27
+		 * any untested algorithm.
Nicolai Stange 3bec27
+		 */
Nicolai Stange 3bec27
+		mask |= CRYPTO_ALG_TESTED;
Nicolai Stange 3bec27
+		type |= CRYPTO_ALG_TESTED;
Nicolai Stange 3bec27
+	}
Nicolai Stange 3bec27
+
Nicolai Stange 3bec27
 	larval = crypto_larval_alloc(name, type, mask);
Nicolai Stange 3bec27
 	if (IS_ERR(larval))
Nicolai Stange 3bec27
 		return ERR_CAST(larval);
Nicolai Stange 592d0e
@@ -240,6 +250,7 @@ static struct crypto_alg *crypto_larval_
Nicolai Stange 267194
 	type &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
Nicolai Stange 267194
 	mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
Nicolai Stange 267194
 
Nicolai Stange 267194
+again:
Nicolai Stange 267194
 	alg = crypto_alg_lookup(name, type, mask);
Nicolai Stange 267194
 	if (!alg && !(mask & CRYPTO_NOLOAD)) {
Nicolai Stange 267194
 		request_module("crypto-%s", name);
Nicolai Stange 592d0e
@@ -251,11 +262,46 @@ static struct crypto_alg *crypto_larval_
Nicolai Stange 267194
 		alg = crypto_alg_lookup(name, type, mask);
Nicolai Stange 267194
 	}
Nicolai Stange 267194
 
Nicolai Stange 267194
+	/*
Nicolai Stange 267194
+	 * As a downstream solution, unapproved crypto driver
Nicolai Stange 267194
+	 * instances' tests are forced to fail in FIPS mode from
Nicolai Stange 267194
+	 * testmgr. A lot of those register "fused" implementations of
Nicolai Stange 267194
+	 * certain algorithm constructions, which would otherwise get
Nicolai Stange 267194
+	 * served by some generic templates. However, those driver
Nicolai Stange 267194
+	 * instances are kept on the global algorithms list in failed
Nicolai Stange 267194
+	 * state and crypto_alg_lookup() would return -ELIBBAD upon
Nicolai Stange 267194
+	 * encountering a matching such one. In order to still allow
Nicolai Stange 267194
+	 * the generic template implementations to serve the request,
Nicolai Stange 267194
+	 * check if the the ELIBBAD had been coming from a matching
Nicolai Stange 267194
+	 * template instantiation in failed state and ignore it if
Nicolai Stange 267194
+	 * not.
Nicolai Stange 267194
+	 */
Nicolai Stange 267194
+	if (fips_enabled && IS_ERR(alg) && PTR_ERR(alg) == -ELIBBAD &&
Nicolai Stange 267194
+	    strchr(name, '(')) {
Nicolai Stange 267194
+		alg = crypto_alg_lookup(name,
Nicolai Stange 267194
+					type | CRYPTO_ALG_INSTANCE,
Nicolai Stange 267194
+					mask | CRYPTO_ALG_INSTANCE);
Nicolai Stange 267194
+	}
Nicolai Stange 267194
+
Nicolai Stange 267194
 	if (!IS_ERR_OR_NULL(alg) && crypto_is_larval(alg))
Nicolai Stange 267194
 		alg = crypto_larval_wait(alg);
Nicolai Stange 267194
 	else if (!alg)
Nicolai Stange 267194
 		alg = crypto_larval_add(name, type, mask);
Nicolai Stange 267194
 
Nicolai Stange 267194
+	/*
Nicolai Stange 267194
+	 * As outlined above, unapproved crypto driver instances'
Nicolai Stange 267194
+	 * tests are forced to fail in FIPS mode from testmgr. If
Nicolai Stange 267194
+	 * crypto_larval_wait() returned -EAGAIN, chances are the wait
Nicolai Stange 267194
+	 * had been on such a driver instance's failed test larval.
Nicolai Stange 267194
+	 * Retry the search in this case.
Nicolai Stange 267194
+	 */
Nicolai Stange 267194
+	if (fips_enabled && IS_ERR(alg) && PTR_ERR(alg) == -EAGAIN) {
Nicolai Stange 3bec27
+		if (fatal_signal_pending(current))
Nicolai Stange 3bec27
+			return ERR_PTR(-EINTR);
Nicolai Stange 267194
+		cond_resched();
Nicolai Stange 267194
+		goto again;
Nicolai Stange 267194
+	}
Nicolai Stange 267194
+
Nicolai Stange 267194
 	return alg;
Nicolai Stange 267194
 }
Nicolai Stange 267194
 
Nicolai Stange 267194
--- /dev/null
Nicolai Stange 267194
+++ b/crypto/suse_fips_unapproved_drivers.h
Nicolai Stange 267194
@@ -0,0 +1 @@
Nicolai Stange 267194
+
Nicolai Stange 267194
--- a/crypto/testmgr.c
Nicolai Stange 267194
+++ b/crypto/testmgr.c
Nicolai Stange 592d0e
@@ -5559,6 +5559,50 @@ static void testmgr_onetime_init(void)
Nicolai Stange 267194
 #endif
Nicolai Stange 267194
 }
Nicolai Stange 267194
 
Nicolai Stange 267194
+#ifdef CONFIG_CRYPTO_FIPS
Nicolai Stange 267194
+static bool suse_fips_is_driver_unapproved(const char *driver)
Nicolai Stange 267194
+{
Nicolai Stange 267194
+	/*
Nicolai Stange 267194
+	 * unapproved_drivers[] contains a sorted list of
Nicolai Stange 267194
+	 * cra_driver_name's to reject in FIPS mode.
Nicolai Stange 267194
+	 */
Nicolai Stange 267194
+	static const char *unapproved_drivers[] = {
Nicolai Stange 267194
+#include "suse_fips_unapproved_drivers.h"
Nicolai Stange 267194
+	};
Nicolai Stange 267194
+	int start = 0;
Nicolai Stange 267194
+	int end = ARRAY_SIZE(unapproved_drivers);
Nicolai Stange 267194
+
Nicolai Stange 267194
+	if (!fips_enabled)
Nicolai Stange 267194
+		return false;
Nicolai Stange 267194
+
Nicolai Stange 267194
+	while (start < end) {
Nicolai Stange 267194
+		int i = (start + end) / 2;
Nicolai Stange 267194
+		int diff = strcmp(unapproved_drivers[i], driver);
Nicolai Stange 267194
+
Nicolai Stange 267194
+		if (diff > 0) {
Nicolai Stange 267194
+			end = i;
Nicolai Stange 267194
+			continue;
Nicolai Stange 267194
+		}
Nicolai Stange 267194
+
Nicolai Stange 267194
+		if (diff < 0) {
Nicolai Stange 267194
+			start = i + 1;
Nicolai Stange 267194
+			continue;
Nicolai Stange 267194
+		}
Nicolai Stange 267194
+
Nicolai Stange 267194
+		pr_info("alg: disabling driver '%s' in FIPS mode\n", driver);
Nicolai Stange 267194
+
Nicolai Stange 267194
+		return true;
Nicolai Stange 267194
+	}
Nicolai Stange 267194
+
Nicolai Stange 267194
+	return false;
Nicolai Stange 267194
+}
Nicolai Stange 267194
+#else /* !CONFIG_CRYPTO_FIPS */
Nicolai Stange 267194
+static bool suse_fips_is_driver_unapproved(const char *driver)
Nicolai Stange 267194
+{
Nicolai Stange 267194
+	return false;
Nicolai Stange 267194
+}
Nicolai Stange 267194
+#endif /* CONFIG_CRYPTO_FIPS */
Nicolai Stange 267194
+
Nicolai Stange 267194
 static int alg_find_test(const char *alg)
Nicolai Stange 267194
 {
Nicolai Stange 267194
 	int start = 0;
Nicolai Stange 592d0e
@@ -5615,6 +5659,9 @@ int alg_test(const char *driver, const c
Nicolai Stange 592d0e
 		if (i < 0)
Nicolai Stange 592d0e
 			goto notest;
Nicolai Stange 267194
 
Nicolai Stange 592d0e
+		if (suse_fips_is_driver_unapproved(driver))
Nicolai Stange 592d0e
+			return -EINVAL;
Nicolai Stange 592d0e
+
Nicolai Stange 267194
 		if (fips_enabled && !alg_test_descs[i].fips_allowed)
Nicolai Stange 267194
 			goto non_fips_alg;
Nicolai Stange 267194
 
Nicolai Stange 592d0e
@@ -5630,6 +5677,8 @@ int alg_test(const char *driver, const c
Nicolai Stange 592d0e
 	if (fips_enabled) {
Nicolai Stange 592d0e
 		if (j >= 0 && !alg_test_descs[j].fips_allowed)
Nicolai Stange 592d0e
 			return -EINVAL;
Nicolai Stange 592d0e
+		else if (suse_fips_is_driver_unapproved(driver))
Nicolai Stange 592d0e
+			return -EINVAL;
Nicolai Stange 267194
 
Nicolai Stange 592d0e
 		if (i >= 0 && !alg_test_descs[i].fips_allowed)
Nicolai Stange 592d0e
 			goto non_fips_alg;
Nicolai Stange 592d0e
@@ -5662,6 +5711,14 @@ test_done:
Nicolai Stange 267194
 	return rc;
Nicolai Stange 267194
 
Nicolai Stange 267194
 notest:
Nicolai Stange 267194
+	/*
Nicolai Stange 267194
+	 * Unapproved drivers can register constructions for which
Nicolai Stange 267194
+	 * there is no matching test with ->fips_allowed == 0, check
Nicolai Stange 267194
+	 * for this.
Nicolai Stange 267194
+	 */
Nicolai Stange 267194
+	if (suse_fips_is_driver_unapproved(driver))
Nicolai Stange 592d0e
+		return -EINVAL;
Nicolai Stange 267194
+
Nicolai Stange 267194
 	printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver);
Nicolai Stange 592d0e
 
Nicolai Stange 592d0e
 	if (type & CRYPTO_ALG_FIPS_INTERNAL)