summaryrefslogtreecommitdiff
path: root/crypto/algapi.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2021-09-17 08:26:19 +0800
committerHerbert Xu <herbert@gondor.apana.org.au>2021-09-24 16:03:05 +0800
commitadad556efcdd42a1d9e060cbe5f6161cccf1fa28 (patch)
tree5f23acffb6cbaf9a1d46feba04c13d1e407d197b /crypto/algapi.c
parent7c5329697ed4e0e1bf9a4e4fc9f0053f2f58935d (diff)
crypto: api - Fix built-in testing dependency failures
When complex algorithms that depend on other algorithms are built into the kernel, the order of registration must be done such that the underlying algorithms are ready before the ones on top are registered. As otherwise they would fail during the self-test which is required during registration. In the past we have used subsystem initialisation ordering to guarantee this. The number of such precedence levels are limited and they may cause ripple effects in other subsystems. This patch solves this problem by delaying all self-tests during boot-up for built-in algorithms. They will be tested either when something else in the kernel requests for them, or when we have finished registering all built-in algorithms, whichever comes earlier. Reported-by: Vladis Dronov <vdronov@redhat.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r--crypto/algapi.c73
1 files changed, 51 insertions, 22 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 43f999dba4dc..422bdca214e1 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -389,29 +389,10 @@ void crypto_remove_final(struct list_head *list)
}
EXPORT_SYMBOL_GPL(crypto_remove_final);
-static void crypto_wait_for_test(struct crypto_larval *larval)
-{
- int err;
-
- err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
- if (err != NOTIFY_STOP) {
- if (WARN_ON(err != NOTIFY_DONE))
- goto out;
- crypto_alg_tested(larval->alg.cra_driver_name, 0);
- }
-
- err = wait_for_completion_killable(&larval->completion);
- WARN_ON(err);
- if (!err)
- crypto_notify(CRYPTO_MSG_ALG_LOADED, larval);
-
-out:
- crypto_larval_kill(&larval->alg);
-}
-
int crypto_register_alg(struct crypto_alg *alg)
{
struct crypto_larval *larval;
+ bool test_started;
int err;
alg->cra_flags &= ~CRYPTO_ALG_DEAD;
@@ -421,12 +402,15 @@ int crypto_register_alg(struct crypto_alg *alg)
down_write(&crypto_alg_sem);
larval = __crypto_register_alg(alg);
+ test_started = static_key_enabled(&crypto_boot_test_finished);
+ larval->test_started = test_started;
up_write(&crypto_alg_sem);
if (IS_ERR(larval))
return PTR_ERR(larval);
- crypto_wait_for_test(larval);
+ if (test_started)
+ crypto_wait_for_test(larval);
return 0;
}
EXPORT_SYMBOL_GPL(crypto_register_alg);
@@ -633,6 +617,8 @@ int crypto_register_instance(struct crypto_template *tmpl,
if (IS_ERR(larval))
goto unlock;
+ larval->test_started = true;
+
hlist_add_head(&inst->list, &tmpl->instances);
inst->tmpl = tmpl;
@@ -1261,9 +1247,48 @@ void crypto_stats_skcipher_decrypt(unsigned int cryptlen, int ret,
EXPORT_SYMBOL_GPL(crypto_stats_skcipher_decrypt);
#endif
+static void __init crypto_start_tests(void)
+{
+ for (;;) {
+ struct crypto_larval *larval = NULL;
+ struct crypto_alg *q;
+
+ down_write(&crypto_alg_sem);
+
+ list_for_each_entry(q, &crypto_alg_list, cra_list) {
+ struct crypto_larval *l;
+
+ if (!crypto_is_larval(q))
+ continue;
+
+ l = (void *)q;
+
+ if (!crypto_is_test_larval(l))
+ continue;
+
+ if (l->test_started)
+ continue;
+
+ l->test_started = true;
+ larval = l;
+ break;
+ }
+
+ up_write(&crypto_alg_sem);
+
+ if (!larval)
+ break;
+
+ crypto_wait_for_test(larval);
+ }
+
+ static_branch_enable(&crypto_boot_test_finished);
+}
+
static int __init crypto_algapi_init(void)
{
crypto_init_proc();
+ crypto_start_tests();
return 0;
}
@@ -1272,7 +1297,11 @@ static void __exit crypto_algapi_exit(void)
crypto_exit_proc();
}
-module_init(crypto_algapi_init);
+/*
+ * We run this at late_initcall so that all the built-in algorithms
+ * have had a chance to register themselves first.
+ */
+late_initcall(crypto_algapi_init);
module_exit(crypto_algapi_exit);
MODULE_LICENSE("GPL");