public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: linux-kernel@vger.kernel.org, stable@vger.kernel.org
Cc: Herbert Xu <herbert@gondor.apana.org.au>,
	Vladis Dronov <vdronov@redhat.com>,
	Sasha Levin <sashal@kernel.org>,
	Herbert@vger.kernel.org, davem@davemloft.net,
	linux-crypto@vger.kernel.org
Subject: [PATCH AUTOSEL 5.15 030/146] crypto: api - Fix built-in testing dependency failures
Date: Mon,  8 Nov 2021 12:42:57 -0500	[thread overview]
Message-ID: <20211108174453.1187052-30-sashal@kernel.org> (raw)
In-Reply-To: <20211108174453.1187052-1-sashal@kernel.org>

From: Herbert Xu <herbert@gondor.apana.org.au>

[ Upstream commit adad556efcdd42a1d9e060cbe5f6161cccf1fa28 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 crypto/algapi.c   | 73 +++++++++++++++++++++++++++++++++--------------
 crypto/api.c      | 52 +++++++++++++++++++++++++++++----
 crypto/internal.h | 10 +++++++
 3 files changed, 108 insertions(+), 27 deletions(-)

diff --git a/crypto/algapi.c b/crypto/algapi.c
index 43f999dba4dc0..422bdca214e1c 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");
diff --git a/crypto/api.c b/crypto/api.c
index c4eda56cff891..1cf1f03347cc3 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -12,6 +12,7 @@
 
 #include <linux/err.h>
 #include <linux/errno.h>
+#include <linux/jump_label.h>
 #include <linux/kernel.h>
 #include <linux/kmod.h>
 #include <linux/module.h>
@@ -30,6 +31,8 @@ EXPORT_SYMBOL_GPL(crypto_alg_sem);
 BLOCKING_NOTIFIER_HEAD(crypto_chain);
 EXPORT_SYMBOL_GPL(crypto_chain);
 
+DEFINE_STATIC_KEY_FALSE(crypto_boot_test_finished);
+
 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg);
 
 struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
@@ -47,11 +50,6 @@ void crypto_mod_put(struct crypto_alg *alg)
 }
 EXPORT_SYMBOL_GPL(crypto_mod_put);
 
-static inline int crypto_is_test_larval(struct crypto_larval *larval)
-{
-	return larval->alg.cra_driver_name[0];
-}
-
 static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
 					      u32 mask)
 {
@@ -163,11 +161,55 @@ void crypto_larval_kill(struct crypto_alg *alg)
 }
 EXPORT_SYMBOL_GPL(crypto_larval_kill);
 
+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);
+}
+EXPORT_SYMBOL_GPL(crypto_wait_for_test);
+
+static void crypto_start_test(struct crypto_larval *larval)
+{
+	if (!crypto_is_test_larval(larval))
+		return;
+
+	if (larval->test_started)
+		return;
+
+	down_write(&crypto_alg_sem);
+	if (larval->test_started) {
+		up_write(&crypto_alg_sem);
+		return;
+	}
+
+	larval->test_started = true;
+	up_write(&crypto_alg_sem);
+
+	crypto_wait_for_test(larval);
+}
+
 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
 {
 	struct crypto_larval *larval = (void *)alg;
 	long timeout;
 
+	if (!static_branch_likely(&crypto_boot_test_finished))
+		crypto_start_test(larval);
+
 	timeout = wait_for_completion_killable_timeout(
 		&larval->completion, 60 * HZ);
 
diff --git a/crypto/internal.h b/crypto/internal.h
index f00869af689f5..c08385571853e 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -10,6 +10,7 @@
 
 #include <crypto/algapi.h>
 #include <linux/completion.h>
+#include <linux/jump_label.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/notifier.h>
@@ -27,6 +28,7 @@ struct crypto_larval {
 	struct crypto_alg *adult;
 	struct completion completion;
 	u32 mask;
+	bool test_started;
 };
 
 enum {
@@ -45,6 +47,8 @@ extern struct list_head crypto_alg_list;
 extern struct rw_semaphore crypto_alg_sem;
 extern struct blocking_notifier_head crypto_chain;
 
+DECLARE_STATIC_KEY_FALSE(crypto_boot_test_finished);
+
 #ifdef CONFIG_PROC_FS
 void __init crypto_init_proc(void);
 void __exit crypto_exit_proc(void);
@@ -70,6 +74,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask);
 
 struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask);
 void crypto_larval_kill(struct crypto_alg *alg);
+void crypto_wait_for_test(struct crypto_larval *larval);
 void crypto_alg_tested(const char *name, int err);
 
 void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
@@ -156,5 +161,10 @@ static inline void crypto_yield(u32 flags)
 		cond_resched();
 }
 
+static inline int crypto_is_test_larval(struct crypto_larval *larval)
+{
+	return larval->alg.cra_driver_name[0];
+}
+
 #endif	/* _CRYPTO_INTERNAL_H */
 
-- 
2.33.0


  parent reply	other threads:[~2021-11-09  1:01 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-08 17:42 [PATCH AUTOSEL 5.15 001/146] dma-buf: WARN on dmabuf release with pending attachments Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 002/146] drm: panel-orientation-quirks: Update the Lenovo Ideapad D330 quirk (v2) Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 003/146] drm: panel-orientation-quirks: Add quirk for KD Kurio Smart C15200 2-in-1 Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 004/146] drm: panel-orientation-quirks: Add quirk for the Samsung Galaxy Book 10.6 Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 005/146] Bluetooth: sco: Fix lock_sock() blockage by memcpy_from_msg() Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 006/146] Bluetooth: fix use-after-free error in lock_sock_nested() Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 007/146] Bluetooth: call sock_hold earlier in sco_conn_del Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 008/146] drm/panel-orientation-quirks: add Valve Steam Deck Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 009/146] rcutorture: Avoid problematic critical section nesting on PREEMPT_RT Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 010/146] platform/x86: wmi: do not fail if disabling fails Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 011/146] drm/amdgpu: move iommu_resume before ip init/resume Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 012/146] MIPS: lantiq: dma: add small delay after reset Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 013/146] MIPS: lantiq: dma: reset correct number of channel Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 014/146] locking/lockdep: Avoid RCU-induced noinstr fail Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 015/146] net: sched: update default qdisc visibility after Tx queue cnt changes Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 016/146] ACPI: resources: Add DMI-based legacy IRQ override quirk Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 017/146] rcu-tasks: Move RTGS_WAIT_CBS to beginning of rcu_tasks_kthread() loop Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 018/146] smackfs: Fix use-after-free in netlbl_catmap_walk() Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 019/146] ath11k: Align bss_chan_info structure with firmware Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 020/146] crypto: aesni - check walk.nbytes instead of err Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 021/146] NET: IPV4: fix error "do not initialise globals to 0" Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 022/146] x86/mm/64: Improve stack overflow warnings Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 023/146] x86: Increase exception stack sizes Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 024/146] mwifiex: Run SET_BSS_MODE when changing from P2P to STATION vif-type Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 025/146] mwifiex: Properly initialize private structure on interface type changes Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 026/146] spi: Check we have a spi_device_id for each DT compatible Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 027/146] fscrypt: allow 256-bit master keys with AES-256-XTS Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 028/146] drm/amdgpu: Fix MMIO access page fault Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 029/146] drm/amd/display: Fix null pointer dereference for encoders Sasha Levin
2021-11-08 17:42 ` Sasha Levin [this message]
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 031/146] selftests: net: fib_nexthops: Wait before checking reported idle time Sasha Levin
2021-11-08 17:42 ` [PATCH AUTOSEL 5.15 032/146] leds: trigger: use RCU to protect the led_cdevs list Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 033/146] ath11k: Avoid reg rules update during firmware recovery Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 034/146] ath11k: add handler for scan event WMI_SCAN_EVENT_DEQUEUED Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 035/146] ath11k: Change DMA_FROM_DEVICE to DMA_TO_DEVICE when map reinjected packets Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 036/146] ath10k: high latency fixes for beacon buffer Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 037/146] octeontx2-pf: Enable promisc/allmulti match MCAM entries Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 038/146] media: mt9p031: Fix corrupted frame after restarting stream Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 039/146] media: netup_unidvb: handle interrupt properly according to the firmware Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 040/146] media: atomisp: Fix error handling in probe Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 041/146] media: stm32: Potential NULL pointer dereference in dcmi_irq_thread() Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 042/146] media: uvcvideo: Set capability in s_param Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 043/146] media: uvcvideo: Return -EIO for control errors Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 044/146] media: uvcvideo: Set unique vdev name based in type Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 045/146] media: vidtv: Fix memory leak in remove Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 046/146] media: s5p-mfc: fix possible null-pointer dereference in s5p_mfc_probe() Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 047/146] media: s5p-mfc: Add checking to s5p_mfc_probe() Sasha Levin
2021-11-08 17:43 ` [PATCH AUTOSEL 5.15 048/146] media: videobuf2: rework vb2_mem_ops API Sasha Levin
2021-11-09  7:54 ` AUTOSEL series truncated was -- Re: [PATCH AUTOSEL 5.15 001/146] dma-buf: WARN on dmabuf release with pending attachments Pavel Machek
2021-11-09  8:07   ` Christian König
2021-11-09 16:05   ` Randy Dunlap
2021-11-14 14:25     ` Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211108174453.1187052-30-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=Herbert@vger.kernel.org \
    --cc=davem@davemloft.net \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@vger.kernel.org \
    --cc=vdronov@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox