xref: /openbmc/linux/crypto/algapi.c (revision 9464bf9762a8b16f4fbd05b115dcde51b339ac58)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2cce9e06dSHerbert Xu /*
3cce9e06dSHerbert Xu  * Cryptographic API for algorithms (i.e., low-level API).
4cce9e06dSHerbert Xu  *
5cce9e06dSHerbert Xu  * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
6cce9e06dSHerbert Xu  */
7cce9e06dSHerbert Xu 
813c935bbSSalvatore Mesoraca #include <crypto/algapi.h>
98fc5f2adSHerbert Xu #include <crypto/internal/simd.h>
106bfd4809SHerbert Xu #include <linux/err.h>
11cce9e06dSHerbert Xu #include <linux/errno.h>
123133d76fSHerbert Xu #include <linux/fips.h>
13cce9e06dSHerbert Xu #include <linux/init.h>
14cce9e06dSHerbert Xu #include <linux/kernel.h>
154cc7720cSHerbert Xu #include <linux/list.h>
16cce9e06dSHerbert Xu #include <linux/module.h>
177fed0bf2SHerbert Xu #include <linux/rtnetlink.h>
185a0e3ad6STejun Heo #include <linux/slab.h>
19cce9e06dSHerbert Xu #include <linux/string.h>
209ae4577bSHerbert Xu #include <linux/workqueue.h>
21cce9e06dSHerbert Xu 
22cce9e06dSHerbert Xu #include "internal.h"
23cce9e06dSHerbert Xu 
244cc7720cSHerbert Xu static LIST_HEAD(crypto_template_list);
254cc7720cSHerbert Xu 
268fc5f2adSHerbert Xu #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
278fc5f2adSHerbert Xu DEFINE_PER_CPU(bool, crypto_simd_disabled_for_test);
288fc5f2adSHerbert Xu EXPORT_PER_CPU_SYMBOL_GPL(crypto_simd_disabled_for_test);
298fc5f2adSHerbert Xu #endif
308fc5f2adSHerbert Xu 
crypto_check_module_sig(struct module * mod)31002c77a4SJarod Wilson static inline void crypto_check_module_sig(struct module *mod)
32002c77a4SJarod Wilson {
3359afdc7bSHerbert Xu 	if (fips_enabled && mod && !module_sig_ok(mod))
34002c77a4SJarod Wilson 		panic("Module %s signature verification failed in FIPS mode\n",
35bd4a7c69SHerbert Xu 		      module_name(mod));
36002c77a4SJarod Wilson }
37002c77a4SJarod Wilson 
crypto_check_alg(struct crypto_alg * alg)384cc7720cSHerbert Xu static int crypto_check_alg(struct crypto_alg *alg)
39cce9e06dSHerbert Xu {
40002c77a4SJarod Wilson 	crypto_check_module_sig(alg->cra_module);
41002c77a4SJarod Wilson 
42177f87d0SEric Biggers 	if (!alg->cra_name[0] || !alg->cra_driver_name[0])
43177f87d0SEric Biggers 		return -EINVAL;
44177f87d0SEric Biggers 
45cce9e06dSHerbert Xu 	if (alg->cra_alignmask & (alg->cra_alignmask + 1))
46cce9e06dSHerbert Xu 		return -EINVAL;
47cce9e06dSHerbert Xu 
48a9f7f88aSKees Cook 	/* General maximums for all algs. */
49a9f7f88aSKees Cook 	if (alg->cra_alignmask > MAX_ALGAPI_ALIGNMASK)
50cce9e06dSHerbert Xu 		return -EINVAL;
51cce9e06dSHerbert Xu 
52a9f7f88aSKees Cook 	if (alg->cra_blocksize > MAX_ALGAPI_BLOCKSIZE)
53a9f7f88aSKees Cook 		return -EINVAL;
54a9f7f88aSKees Cook 
55a9f7f88aSKees Cook 	/* Lower maximums for specific alg types. */
5613c935bbSSalvatore Mesoraca 	if (!alg->cra_type && (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
5713c935bbSSalvatore Mesoraca 			       CRYPTO_ALG_TYPE_CIPHER) {
5813c935bbSSalvatore Mesoraca 		if (alg->cra_alignmask > MAX_CIPHER_ALIGNMASK)
5913c935bbSSalvatore Mesoraca 			return -EINVAL;
6013c935bbSSalvatore Mesoraca 
6113c935bbSSalvatore Mesoraca 		if (alg->cra_blocksize > MAX_CIPHER_BLOCKSIZE)
6213c935bbSSalvatore Mesoraca 			return -EINVAL;
6313c935bbSSalvatore Mesoraca 	}
6413c935bbSSalvatore Mesoraca 
65cce9e06dSHerbert Xu 	if (alg->cra_priority < 0)
66cce9e06dSHerbert Xu 		return -EINVAL;
67cce9e06dSHerbert Xu 
68ce8614a3SEric Biggers 	refcount_set(&alg->cra_refcnt, 1);
69e9b8e5beSHerbert Xu 
70177f87d0SEric Biggers 	return 0;
714cc7720cSHerbert Xu }
72cce9e06dSHerbert Xu 
crypto_free_instance(struct crypto_instance * inst)73319382a6SHerbert Xu static void crypto_free_instance(struct crypto_instance *inst)
74319382a6SHerbert Xu {
75319382a6SHerbert Xu 	inst->alg.cra_type->free(inst);
76319382a6SHerbert Xu }
77319382a6SHerbert Xu 
crypto_destroy_instance_workfn(struct work_struct * w)789ae4577bSHerbert Xu static void crypto_destroy_instance_workfn(struct work_struct *w)
796bfd4809SHerbert Xu {
809ae4577bSHerbert Xu 	struct crypto_instance *inst = container_of(w, struct crypto_instance,
819ae4577bSHerbert Xu 						    free_work);
826bfd4809SHerbert Xu 	struct crypto_template *tmpl = inst->tmpl;
836bfd4809SHerbert Xu 
84319382a6SHerbert Xu 	crypto_free_instance(inst);
856bfd4809SHerbert Xu 	crypto_tmpl_put(tmpl);
866bfd4809SHerbert Xu }
876bfd4809SHerbert Xu 
crypto_destroy_instance(struct crypto_alg * alg)889ae4577bSHerbert Xu static void crypto_destroy_instance(struct crypto_alg *alg)
899ae4577bSHerbert Xu {
909ae4577bSHerbert Xu 	struct crypto_instance *inst = container_of(alg,
919ae4577bSHerbert Xu 						    struct crypto_instance,
929ae4577bSHerbert Xu 						    alg);
939ae4577bSHerbert Xu 
949ae4577bSHerbert Xu 	INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
959ae4577bSHerbert Xu 	schedule_work(&inst->free_work);
969ae4577bSHerbert Xu }
979ae4577bSHerbert Xu 
9802244ba4SHerbert Xu /*
9902244ba4SHerbert Xu  * This function adds a spawn to the list secondary_spawns which
10002244ba4SHerbert Xu  * will be used at the end of crypto_remove_spawns to unregister
10102244ba4SHerbert Xu  * instances, unless the spawn happens to be one that is depended
10202244ba4SHerbert Xu  * on by the new algorithm (nalg in crypto_remove_spawns).
10302244ba4SHerbert Xu  *
10402244ba4SHerbert Xu  * This function is also responsible for resurrecting any algorithms
10502244ba4SHerbert Xu  * in the dependency chain of nalg by unsetting n->dead.
10602244ba4SHerbert Xu  */
crypto_more_spawns(struct crypto_alg * alg,struct list_head * stack,struct list_head * top,struct list_head * secondary_spawns)1072bf29016SHerbert Xu static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
1082bf29016SHerbert Xu 					    struct list_head *stack,
1092bf29016SHerbert Xu 					    struct list_head *top,
110a73e6996SHerbert Xu 					    struct list_head *secondary_spawns)
1116bfd4809SHerbert Xu {
1122bf29016SHerbert Xu 	struct crypto_spawn *spawn, *n;
1132bf29016SHerbert Xu 
114304e4818SGeliang Tang 	spawn = list_first_entry_or_null(stack, struct crypto_spawn, list);
115304e4818SGeliang Tang 	if (!spawn)
1162bf29016SHerbert Xu 		return NULL;
1172bf29016SHerbert Xu 
1184f87ee11SHerbert Xu 	n = list_prev_entry(spawn, list);
1192bf29016SHerbert Xu 	list_move(&spawn->list, secondary_spawns);
1202bf29016SHerbert Xu 
1214f87ee11SHerbert Xu 	if (list_is_last(&n->list, stack))
1224f87ee11SHerbert Xu 		return top;
1234f87ee11SHerbert Xu 
1244f87ee11SHerbert Xu 	n = list_next_entry(n, list);
1254f87ee11SHerbert Xu 	if (!spawn->dead)
1264f87ee11SHerbert Xu 		n->dead = false;
1274f87ee11SHerbert Xu 
1284f87ee11SHerbert Xu 	return &n->inst->alg.cra_users;
1292bf29016SHerbert Xu }
1302bf29016SHerbert Xu 
crypto_remove_instance(struct crypto_instance * inst,struct list_head * list)1311f723710SHerbert Xu static void crypto_remove_instance(struct crypto_instance *inst,
1322bf29016SHerbert Xu 				   struct list_head *list)
1332bf29016SHerbert Xu {
1346bfd4809SHerbert Xu 	struct crypto_template *tmpl = inst->tmpl;
1356bfd4809SHerbert Xu 
1366bfd4809SHerbert Xu 	if (crypto_is_dead(&inst->alg))
137a73e6996SHerbert Xu 		return;
1386bfd4809SHerbert Xu 
1396bfd4809SHerbert Xu 	inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
14038cb2419SHerbert Xu 
1416bfd4809SHerbert Xu 	if (!tmpl || !crypto_tmpl_get(tmpl))
142a73e6996SHerbert Xu 		return;
1436bfd4809SHerbert Xu 
1446bfd4809SHerbert Xu 	list_move(&inst->alg.cra_list, list);
1456bfd4809SHerbert Xu 	hlist_del(&inst->list);
1466bfd4809SHerbert Xu 	inst->alg.cra_destroy = crypto_destroy_instance;
1476bfd4809SHerbert Xu 
1482bf29016SHerbert Xu 	BUG_ON(!list_empty(&inst->alg.cra_users));
1496bfd4809SHerbert Xu }
150a73e6996SHerbert Xu 
15102244ba4SHerbert Xu /*
15202244ba4SHerbert Xu  * Given an algorithm alg, remove all algorithms that depend on it
15302244ba4SHerbert Xu  * through spawns.  If nalg is not null, then exempt any algorithms
15402244ba4SHerbert Xu  * that is depended on by nalg.  This is useful when nalg itself
15502244ba4SHerbert Xu  * depends on alg.
15602244ba4SHerbert Xu  */
crypto_remove_spawns(struct crypto_alg * alg,struct list_head * list,struct crypto_alg * nalg)15789b596baSSteffen Klassert void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
1582bf29016SHerbert Xu 			  struct crypto_alg *nalg)
159a73e6996SHerbert Xu {
1602bf29016SHerbert Xu 	u32 new_type = (nalg ?: alg)->cra_flags;
161a73e6996SHerbert Xu 	struct crypto_spawn *spawn, *n;
162a73e6996SHerbert Xu 	LIST_HEAD(secondary_spawns);
1632bf29016SHerbert Xu 	struct list_head *spawns;
1642bf29016SHerbert Xu 	LIST_HEAD(stack);
1652bf29016SHerbert Xu 	LIST_HEAD(top);
166a73e6996SHerbert Xu 
1672bf29016SHerbert Xu 	spawns = &alg->cra_users;
168a73e6996SHerbert Xu 	list_for_each_entry_safe(spawn, n, spawns, list) {
169a73e6996SHerbert Xu 		if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
170a73e6996SHerbert Xu 			continue;
171a73e6996SHerbert Xu 
1722bf29016SHerbert Xu 		list_move(&spawn->list, &top);
173a73e6996SHerbert Xu 	}
174a73e6996SHerbert Xu 
17502244ba4SHerbert Xu 	/*
17602244ba4SHerbert Xu 	 * Perform a depth-first walk starting from alg through
17702244ba4SHerbert Xu 	 * the cra_users tree.  The list stack records the path
17802244ba4SHerbert Xu 	 * from alg to the current spawn.
17902244ba4SHerbert Xu 	 */
1802bf29016SHerbert Xu 	spawns = &top;
1812bf29016SHerbert Xu 	do {
1822bf29016SHerbert Xu 		while (!list_empty(spawns)) {
1832bf29016SHerbert Xu 			struct crypto_instance *inst;
1842bf29016SHerbert Xu 
1852bf29016SHerbert Xu 			spawn = list_first_entry(spawns, struct crypto_spawn,
1862bf29016SHerbert Xu 						 list);
1872bf29016SHerbert Xu 			inst = spawn->inst;
1882bf29016SHerbert Xu 
1892bf29016SHerbert Xu 			list_move(&spawn->list, &stack);
1905f567fffSHerbert Xu 			spawn->dead = !spawn->registered || &inst->alg != nalg;
1915f567fffSHerbert Xu 
1925f567fffSHerbert Xu 			if (!spawn->registered)
1935f567fffSHerbert Xu 				break;
1945f567fffSHerbert Xu 
1955f567fffSHerbert Xu 			BUG_ON(&inst->alg == alg);
1962bf29016SHerbert Xu 
1972bf29016SHerbert Xu 			if (&inst->alg == nalg)
1982bf29016SHerbert Xu 				break;
1992bf29016SHerbert Xu 
2002bf29016SHerbert Xu 			spawns = &inst->alg.cra_users;
2019a006742SEric Biggers 
2029a006742SEric Biggers 			/*
2035f567fffSHerbert Xu 			 * Even if spawn->registered is true, the
2045f567fffSHerbert Xu 			 * instance itself may still be unregistered.
2055f567fffSHerbert Xu 			 * This is because it may have failed during
2065f567fffSHerbert Xu 			 * registration.  Therefore we still need to
2075f567fffSHerbert Xu 			 * make the following test.
2085f567fffSHerbert Xu 			 *
2099a006742SEric Biggers 			 * We may encounter an unregistered instance here, since
2109a006742SEric Biggers 			 * an instance's spawns are set up prior to the instance
2119a006742SEric Biggers 			 * being registered.  An unregistered instance will have
2129a006742SEric Biggers 			 * NULL ->cra_users.next, since ->cra_users isn't
2139a006742SEric Biggers 			 * properly initialized until registration.  But an
2149a006742SEric Biggers 			 * unregistered instance cannot have any users, so treat
2159a006742SEric Biggers 			 * it the same as ->cra_users being empty.
2169a006742SEric Biggers 			 */
2179a006742SEric Biggers 			if (spawns->next == NULL)
2189a006742SEric Biggers 				break;
2192bf29016SHerbert Xu 		}
2202bf29016SHerbert Xu 	} while ((spawns = crypto_more_spawns(alg, &stack, &top,
2212bf29016SHerbert Xu 					      &secondary_spawns)));
2222bf29016SHerbert Xu 
22302244ba4SHerbert Xu 	/*
22402244ba4SHerbert Xu 	 * Remove all instances that are marked as dead.  Also
22502244ba4SHerbert Xu 	 * complete the resurrection of the others by moving them
22602244ba4SHerbert Xu 	 * back to the cra_users list.
22702244ba4SHerbert Xu 	 */
2282bf29016SHerbert Xu 	list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
2294f87ee11SHerbert Xu 		if (!spawn->dead)
2302bf29016SHerbert Xu 			list_move(&spawn->list, &spawn->alg->cra_users);
2315f567fffSHerbert Xu 		else if (spawn->registered)
2321f723710SHerbert Xu 			crypto_remove_instance(spawn->inst, list);
2336bfd4809SHerbert Xu 	}
2346bfd4809SHerbert Xu }
23589b596baSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_spawns);
2366bfd4809SHerbert Xu 
crypto_alg_finish_registration(struct crypto_alg * alg,bool fulfill_requests,struct list_head * algs_to_put)237a7008584SEric Biggers static void crypto_alg_finish_registration(struct crypto_alg *alg,
238a7008584SEric Biggers 					   bool fulfill_requests,
239a7008584SEric Biggers 					   struct list_head *algs_to_put)
240a7008584SEric Biggers {
241a7008584SEric Biggers 	struct crypto_alg *q;
242a7008584SEric Biggers 
243a7008584SEric Biggers 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
244a7008584SEric Biggers 		if (q == alg)
245a7008584SEric Biggers 			continue;
246a7008584SEric Biggers 
247a7008584SEric Biggers 		if (crypto_is_moribund(q))
248a7008584SEric Biggers 			continue;
249a7008584SEric Biggers 
250a7008584SEric Biggers 		if (crypto_is_larval(q)) {
251a7008584SEric Biggers 			struct crypto_larval *larval = (void *)q;
252a7008584SEric Biggers 
253a7008584SEric Biggers 			/*
254a7008584SEric Biggers 			 * Check to see if either our generic name or
255a7008584SEric Biggers 			 * specific name can satisfy the name requested
256a7008584SEric Biggers 			 * by the larval entry q.
257a7008584SEric Biggers 			 */
258a7008584SEric Biggers 			if (strcmp(alg->cra_name, q->cra_name) &&
259a7008584SEric Biggers 			    strcmp(alg->cra_driver_name, q->cra_name))
260a7008584SEric Biggers 				continue;
261a7008584SEric Biggers 
262a7008584SEric Biggers 			if (larval->adult)
263a7008584SEric Biggers 				continue;
264a7008584SEric Biggers 			if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
265a7008584SEric Biggers 				continue;
266a7008584SEric Biggers 
267a7008584SEric Biggers 			if (fulfill_requests && crypto_mod_get(alg))
268a7008584SEric Biggers 				larval->adult = alg;
269a7008584SEric Biggers 			else
270a7008584SEric Biggers 				larval->adult = ERR_PTR(-EAGAIN);
271a7008584SEric Biggers 
272a7008584SEric Biggers 			continue;
273a7008584SEric Biggers 		}
274a7008584SEric Biggers 
275a7008584SEric Biggers 		if (strcmp(alg->cra_name, q->cra_name))
276a7008584SEric Biggers 			continue;
277a7008584SEric Biggers 
278a7008584SEric Biggers 		if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
279a7008584SEric Biggers 		    q->cra_priority > alg->cra_priority)
280a7008584SEric Biggers 			continue;
281a7008584SEric Biggers 
282a7008584SEric Biggers 		crypto_remove_spawns(q, algs_to_put, alg);
283a7008584SEric Biggers 	}
284a7008584SEric Biggers 
285a7008584SEric Biggers 	crypto_notify(CRYPTO_MSG_ALG_LOADED, alg);
286a7008584SEric Biggers }
287a7008584SEric Biggers 
crypto_alloc_test_larval(struct crypto_alg * alg)288cad439fcSHerbert Xu static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg)
289cad439fcSHerbert Xu {
290cad439fcSHerbert Xu 	struct crypto_larval *larval;
291cad439fcSHerbert Xu 
292a7008584SEric Biggers 	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER) ||
2939cadd73aSEric Biggers 	    IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) ||
2949cadd73aSEric Biggers 	    (alg->cra_flags & CRYPTO_ALG_INTERNAL))
295a7008584SEric Biggers 		return NULL; /* No self-test needed */
296cad439fcSHerbert Xu 
297cad439fcSHerbert Xu 	larval = crypto_larval_alloc(alg->cra_name,
298cad439fcSHerbert Xu 				     alg->cra_flags | CRYPTO_ALG_TESTED, 0);
299cad439fcSHerbert Xu 	if (IS_ERR(larval))
300cad439fcSHerbert Xu 		return larval;
301cad439fcSHerbert Xu 
302cad439fcSHerbert Xu 	larval->adult = crypto_mod_get(alg);
303cad439fcSHerbert Xu 	if (!larval->adult) {
304cad439fcSHerbert Xu 		kfree(larval);
305cad439fcSHerbert Xu 		return ERR_PTR(-ENOENT);
306cad439fcSHerbert Xu 	}
307cad439fcSHerbert Xu 
308cad439fcSHerbert Xu 	refcount_set(&larval->alg.cra_refcnt, 1);
309cad439fcSHerbert Xu 	memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
310cad439fcSHerbert Xu 	       CRYPTO_MAX_ALG_NAME);
311cad439fcSHerbert Xu 	larval->alg.cra_priority = alg->cra_priority;
312cad439fcSHerbert Xu 
313cad439fcSHerbert Xu 	return larval;
314cad439fcSHerbert Xu }
315cad439fcSHerbert Xu 
316a7008584SEric Biggers static struct crypto_larval *
__crypto_register_alg(struct crypto_alg * alg,struct list_head * algs_to_put)317a7008584SEric Biggers __crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_put)
3184cc7720cSHerbert Xu {
3194cc7720cSHerbert Xu 	struct crypto_alg *q;
32073d3864aSHerbert Xu 	struct crypto_larval *larval;
3216bfd4809SHerbert Xu 	int ret = -EAGAIN;
3226bfd4809SHerbert Xu 
3236bfd4809SHerbert Xu 	if (crypto_is_dead(alg))
32473d3864aSHerbert Xu 		goto err;
3256bfd4809SHerbert Xu 
3266bfd4809SHerbert Xu 	INIT_LIST_HEAD(&alg->cra_users);
3276bfd4809SHerbert Xu 
3286bfd4809SHerbert Xu 	ret = -EEXIST;
329cce9e06dSHerbert Xu 
330cce9e06dSHerbert Xu 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
3314cc7720cSHerbert Xu 		if (q == alg)
33273d3864aSHerbert Xu 			goto err;
33373d3864aSHerbert Xu 
334b8e15992SHerbert Xu 		if (crypto_is_moribund(q))
335b8e15992SHerbert Xu 			continue;
336b8e15992SHerbert Xu 
33773d3864aSHerbert Xu 		if (crypto_is_larval(q)) {
33873d3864aSHerbert Xu 			if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
33973d3864aSHerbert Xu 				goto err;
34073d3864aSHerbert Xu 			continue;
34173d3864aSHerbert Xu 		}
34273d3864aSHerbert Xu 
34373d3864aSHerbert Xu 		if (!strcmp(q->cra_driver_name, alg->cra_name) ||
344b1a67a0dSHerbert Xu 		    !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
34573d3864aSHerbert Xu 		    !strcmp(q->cra_name, alg->cra_driver_name))
34673d3864aSHerbert Xu 			goto err;
34773d3864aSHerbert Xu 	}
34873d3864aSHerbert Xu 
349cad439fcSHerbert Xu 	larval = crypto_alloc_test_larval(alg);
35073d3864aSHerbert Xu 	if (IS_ERR(larval))
351cce9e06dSHerbert Xu 		goto out;
3526bfd4809SHerbert Xu 
35373d3864aSHerbert Xu 	list_add(&alg->cra_list, &crypto_alg_list);
354cad439fcSHerbert Xu 
355a7008584SEric Biggers 	if (larval) {
356a7008584SEric Biggers 		/* No cheating! */
357a7008584SEric Biggers 		alg->cra_flags &= ~CRYPTO_ALG_TESTED;
358a7008584SEric Biggers 
359a7008584SEric Biggers 		list_add(&larval->alg.cra_list, &crypto_alg_list);
360a7008584SEric Biggers 	} else {
361a7008584SEric Biggers 		alg->cra_flags |= CRYPTO_ALG_TESTED;
362a7008584SEric Biggers 		crypto_alg_finish_registration(alg, true, algs_to_put);
363a7008584SEric Biggers 	}
364a7008584SEric Biggers 
36573d3864aSHerbert Xu out:
36673d3864aSHerbert Xu 	return larval;
36773d3864aSHerbert Xu 
36873d3864aSHerbert Xu err:
36973d3864aSHerbert Xu 	larval = ERR_PTR(ret);
37073d3864aSHerbert Xu 	goto out;
37173d3864aSHerbert Xu }
37273d3864aSHerbert Xu 
crypto_alg_tested(const char * name,int err)37373d3864aSHerbert Xu void crypto_alg_tested(const char *name, int err)
37473d3864aSHerbert Xu {
37573d3864aSHerbert Xu 	struct crypto_larval *test;
37673d3864aSHerbert Xu 	struct crypto_alg *alg;
37773d3864aSHerbert Xu 	struct crypto_alg *q;
37873d3864aSHerbert Xu 	LIST_HEAD(list);
3792bbb3375SHerbert Xu 	bool best;
38073d3864aSHerbert Xu 
38173d3864aSHerbert Xu 	down_write(&crypto_alg_sem);
38273d3864aSHerbert Xu 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
383b8e15992SHerbert Xu 		if (crypto_is_moribund(q) || !crypto_is_larval(q))
38473d3864aSHerbert Xu 			continue;
38573d3864aSHerbert Xu 
38673d3864aSHerbert Xu 		test = (struct crypto_larval *)q;
38773d3864aSHerbert Xu 
38873d3864aSHerbert Xu 		if (!strcmp(q->cra_driver_name, name))
38973d3864aSHerbert Xu 			goto found;
39073d3864aSHerbert Xu 	}
39173d3864aSHerbert Xu 
392c7235857SKarim Eshapa 	pr_err("alg: Unexpected test result for %s: %d\n", name, err);
39373d3864aSHerbert Xu 	goto unlock;
39473d3864aSHerbert Xu 
39573d3864aSHerbert Xu found:
396b8e15992SHerbert Xu 	q->cra_flags |= CRYPTO_ALG_DEAD;
39773d3864aSHerbert Xu 	alg = test->adult;
398d6097b8dSNicolai Stange 
399*83394e7dSHerbert Xu 	if (crypto_is_dead(alg))
40073d3864aSHerbert Xu 		goto complete;
40173d3864aSHerbert Xu 
402d6097b8dSNicolai Stange 	if (err == -ECANCELED)
403d6097b8dSNicolai Stange 		alg->cra_flags |= CRYPTO_ALG_FIPS_INTERNAL;
404d6097b8dSNicolai Stange 	else if (err)
405d6097b8dSNicolai Stange 		goto complete;
406d6097b8dSNicolai Stange 	else
407d6097b8dSNicolai Stange 		alg->cra_flags &= ~CRYPTO_ALG_FIPS_INTERNAL;
408d6097b8dSNicolai Stange 
40973d3864aSHerbert Xu 	alg->cra_flags |= CRYPTO_ALG_TESTED;
41073d3864aSHerbert Xu 
411a7008584SEric Biggers 	/*
412a7008584SEric Biggers 	 * If a higher-priority implementation of the same algorithm is
413a7008584SEric Biggers 	 * currently being tested, then don't fulfill request larvals.
414a7008584SEric Biggers 	 */
4152bbb3375SHerbert Xu 	best = true;
4162bbb3375SHerbert Xu 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
4172bbb3375SHerbert Xu 		if (crypto_is_moribund(q) || !crypto_is_larval(q))
4182bbb3375SHerbert Xu 			continue;
4192bbb3375SHerbert Xu 
4202bbb3375SHerbert Xu 		if (strcmp(alg->cra_name, q->cra_name))
4212bbb3375SHerbert Xu 			continue;
4222bbb3375SHerbert Xu 
4232bbb3375SHerbert Xu 		if (q->cra_priority > alg->cra_priority) {
4242bbb3375SHerbert Xu 			best = false;
4252bbb3375SHerbert Xu 			break;
4262bbb3375SHerbert Xu 		}
4272bbb3375SHerbert Xu 	}
4282bbb3375SHerbert Xu 
429a7008584SEric Biggers 	crypto_alg_finish_registration(alg, best, &list);
430cce9e06dSHerbert Xu 
43173d3864aSHerbert Xu complete:
43273d3864aSHerbert Xu 	complete_all(&test->completion);
4332825982dSHerbert Xu 
43473d3864aSHerbert Xu unlock:
43573d3864aSHerbert Xu 	up_write(&crypto_alg_sem);
4362825982dSHerbert Xu 
43773d3864aSHerbert Xu 	crypto_remove_final(&list);
438cce9e06dSHerbert Xu }
43973d3864aSHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_tested);
4404cc7720cSHerbert Xu 
crypto_remove_final(struct list_head * list)44122e5b20bSSteffen Klassert void crypto_remove_final(struct list_head *list)
4426bfd4809SHerbert Xu {
4436bfd4809SHerbert Xu 	struct crypto_alg *alg;
4446bfd4809SHerbert Xu 	struct crypto_alg *n;
4456bfd4809SHerbert Xu 
4466bfd4809SHerbert Xu 	list_for_each_entry_safe(alg, n, list, cra_list) {
4476bfd4809SHerbert Xu 		list_del_init(&alg->cra_list);
4486bfd4809SHerbert Xu 		crypto_alg_put(alg);
4496bfd4809SHerbert Xu 	}
4506bfd4809SHerbert Xu }
45122e5b20bSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_final);
4526bfd4809SHerbert Xu 
crypto_register_alg(struct crypto_alg * alg)4534cc7720cSHerbert Xu int crypto_register_alg(struct crypto_alg *alg)
4544cc7720cSHerbert Xu {
45573d3864aSHerbert Xu 	struct crypto_larval *larval;
456a7008584SEric Biggers 	LIST_HEAD(algs_to_put);
457a7008584SEric Biggers 	bool test_started = false;
4584cc7720cSHerbert Xu 	int err;
4594cc7720cSHerbert Xu 
460d6040764SSalvatore Benedetto 	alg->cra_flags &= ~CRYPTO_ALG_DEAD;
4614cc7720cSHerbert Xu 	err = crypto_check_alg(alg);
4624cc7720cSHerbert Xu 	if (err)
4634cc7720cSHerbert Xu 		return err;
4644cc7720cSHerbert Xu 
4654cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
466a7008584SEric Biggers 	larval = __crypto_register_alg(alg, &algs_to_put);
467a7008584SEric Biggers 	if (!IS_ERR_OR_NULL(larval)) {
46806bd9c96SEric Biggers 		test_started = crypto_boot_test_finished();
469adad556eSHerbert Xu 		larval->test_started = test_started;
470a7008584SEric Biggers 	}
4714cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
4724cc7720cSHerbert Xu 
473a7008584SEric Biggers 	if (IS_ERR(larval))
47473d3864aSHerbert Xu 		return PTR_ERR(larval);
475adad556eSHerbert Xu 	if (test_started)
47673d3864aSHerbert Xu 		crypto_wait_for_test(larval);
477a7008584SEric Biggers 	crypto_remove_final(&algs_to_put);
47873d3864aSHerbert Xu 	return 0;
4794cc7720cSHerbert Xu }
480cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_alg);
481cce9e06dSHerbert Xu 
crypto_remove_alg(struct crypto_alg * alg,struct list_head * list)4826bfd4809SHerbert Xu static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
4836bfd4809SHerbert Xu {
4846bfd4809SHerbert Xu 	if (unlikely(list_empty(&alg->cra_list)))
4856bfd4809SHerbert Xu 		return -ENOENT;
4866bfd4809SHerbert Xu 
4876bfd4809SHerbert Xu 	alg->cra_flags |= CRYPTO_ALG_DEAD;
4886bfd4809SHerbert Xu 
4896bfd4809SHerbert Xu 	list_del_init(&alg->cra_list);
4902bf29016SHerbert Xu 	crypto_remove_spawns(alg, list, NULL);
4916bfd4809SHerbert Xu 
4926bfd4809SHerbert Xu 	return 0;
4936bfd4809SHerbert Xu }
4946bfd4809SHerbert Xu 
crypto_unregister_alg(struct crypto_alg * alg)495c6d633a9SEric Biggers void crypto_unregister_alg(struct crypto_alg *alg)
496cce9e06dSHerbert Xu {
4976bfd4809SHerbert Xu 	int ret;
4986bfd4809SHerbert Xu 	LIST_HEAD(list);
499cce9e06dSHerbert Xu 
500cce9e06dSHerbert Xu 	down_write(&crypto_alg_sem);
5016bfd4809SHerbert Xu 	ret = crypto_remove_alg(alg, &list);
502cce9e06dSHerbert Xu 	up_write(&crypto_alg_sem);
503cce9e06dSHerbert Xu 
504c6d633a9SEric Biggers 	if (WARN(ret, "Algorithm %s is not registered", alg->cra_driver_name))
505c6d633a9SEric Biggers 		return;
506cce9e06dSHerbert Xu 
507a543ada7SToke Høiland-Jørgensen 	if (WARN_ON(refcount_read(&alg->cra_refcnt) != 1))
508a543ada7SToke Høiland-Jørgensen 		return;
509a543ada7SToke Høiland-Jørgensen 
510cce9e06dSHerbert Xu 	if (alg->cra_destroy)
511cce9e06dSHerbert Xu 		alg->cra_destroy(alg);
512cce9e06dSHerbert Xu 
5136bfd4809SHerbert Xu 	crypto_remove_final(&list);
514cce9e06dSHerbert Xu }
515cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_alg);
516cce9e06dSHerbert Xu 
crypto_register_algs(struct crypto_alg * algs,int count)5174b004346SMark Brown int crypto_register_algs(struct crypto_alg *algs, int count)
5184b004346SMark Brown {
5194b004346SMark Brown 	int i, ret;
5204b004346SMark Brown 
5214b004346SMark Brown 	for (i = 0; i < count; i++) {
5224b004346SMark Brown 		ret = crypto_register_alg(&algs[i]);
5234b004346SMark Brown 		if (ret)
5244b004346SMark Brown 			goto err;
5254b004346SMark Brown 	}
5264b004346SMark Brown 
5274b004346SMark Brown 	return 0;
5284b004346SMark Brown 
5294b004346SMark Brown err:
5304b004346SMark Brown 	for (--i; i >= 0; --i)
5314b004346SMark Brown 		crypto_unregister_alg(&algs[i]);
5324b004346SMark Brown 
5334b004346SMark Brown 	return ret;
5344b004346SMark Brown }
5354b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_register_algs);
5364b004346SMark Brown 
crypto_unregister_algs(struct crypto_alg * algs,int count)537c6d633a9SEric Biggers void crypto_unregister_algs(struct crypto_alg *algs, int count)
5384b004346SMark Brown {
539c6d633a9SEric Biggers 	int i;
5404b004346SMark Brown 
541c6d633a9SEric Biggers 	for (i = 0; i < count; i++)
542c6d633a9SEric Biggers 		crypto_unregister_alg(&algs[i]);
5434b004346SMark Brown }
5444b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_unregister_algs);
5454b004346SMark Brown 
crypto_register_template(struct crypto_template * tmpl)5464cc7720cSHerbert Xu int crypto_register_template(struct crypto_template *tmpl)
5474cc7720cSHerbert Xu {
5484cc7720cSHerbert Xu 	struct crypto_template *q;
5494cc7720cSHerbert Xu 	int err = -EEXIST;
5504cc7720cSHerbert Xu 
5514cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
5524cc7720cSHerbert Xu 
553002c77a4SJarod Wilson 	crypto_check_module_sig(tmpl->module);
554002c77a4SJarod Wilson 
5554cc7720cSHerbert Xu 	list_for_each_entry(q, &crypto_template_list, list) {
5564cc7720cSHerbert Xu 		if (q == tmpl)
5574cc7720cSHerbert Xu 			goto out;
5584cc7720cSHerbert Xu 	}
5594cc7720cSHerbert Xu 
5604cc7720cSHerbert Xu 	list_add(&tmpl->list, &crypto_template_list);
5614cc7720cSHerbert Xu 	err = 0;
5624cc7720cSHerbert Xu out:
5634cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
5644cc7720cSHerbert Xu 	return err;
5654cc7720cSHerbert Xu }
5664cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_template);
5674cc7720cSHerbert Xu 
crypto_register_templates(struct crypto_template * tmpls,int count)5689572442dSXiongfeng Wang int crypto_register_templates(struct crypto_template *tmpls, int count)
5699572442dSXiongfeng Wang {
5709572442dSXiongfeng Wang 	int i, err;
5719572442dSXiongfeng Wang 
5729572442dSXiongfeng Wang 	for (i = 0; i < count; i++) {
5739572442dSXiongfeng Wang 		err = crypto_register_template(&tmpls[i]);
5749572442dSXiongfeng Wang 		if (err)
5759572442dSXiongfeng Wang 			goto out;
5769572442dSXiongfeng Wang 	}
5779572442dSXiongfeng Wang 	return 0;
5789572442dSXiongfeng Wang 
5799572442dSXiongfeng Wang out:
5809572442dSXiongfeng Wang 	for (--i; i >= 0; --i)
5819572442dSXiongfeng Wang 		crypto_unregister_template(&tmpls[i]);
5829572442dSXiongfeng Wang 	return err;
5839572442dSXiongfeng Wang }
5849572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_register_templates);
5859572442dSXiongfeng Wang 
crypto_unregister_template(struct crypto_template * tmpl)5864cc7720cSHerbert Xu void crypto_unregister_template(struct crypto_template *tmpl)
5874cc7720cSHerbert Xu {
5884cc7720cSHerbert Xu 	struct crypto_instance *inst;
589b67bfe0dSSasha Levin 	struct hlist_node *n;
5904cc7720cSHerbert Xu 	struct hlist_head *list;
5916bfd4809SHerbert Xu 	LIST_HEAD(users);
5924cc7720cSHerbert Xu 
5934cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
5944cc7720cSHerbert Xu 
5954cc7720cSHerbert Xu 	BUG_ON(list_empty(&tmpl->list));
5964cc7720cSHerbert Xu 	list_del_init(&tmpl->list);
5974cc7720cSHerbert Xu 
5984cc7720cSHerbert Xu 	list = &tmpl->instances;
599b67bfe0dSSasha Levin 	hlist_for_each_entry(inst, list, list) {
6006bfd4809SHerbert Xu 		int err = crypto_remove_alg(&inst->alg, &users);
6010efcb8d5SJoshua I. James 
6026bfd4809SHerbert Xu 		BUG_ON(err);
6034cc7720cSHerbert Xu 	}
6044cc7720cSHerbert Xu 
6054cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
6064cc7720cSHerbert Xu 
607b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(inst, n, list, list) {
608ce8614a3SEric Biggers 		BUG_ON(refcount_read(&inst->alg.cra_refcnt) != 1);
609319382a6SHerbert Xu 		crypto_free_instance(inst);
6104cc7720cSHerbert Xu 	}
6116bfd4809SHerbert Xu 	crypto_remove_final(&users);
6124cc7720cSHerbert Xu }
6134cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_template);
6144cc7720cSHerbert Xu 
crypto_unregister_templates(struct crypto_template * tmpls,int count)6159572442dSXiongfeng Wang void crypto_unregister_templates(struct crypto_template *tmpls, int count)
6169572442dSXiongfeng Wang {
6179572442dSXiongfeng Wang 	int i;
6189572442dSXiongfeng Wang 
6199572442dSXiongfeng Wang 	for (i = count - 1; i >= 0; --i)
6209572442dSXiongfeng Wang 		crypto_unregister_template(&tmpls[i]);
6219572442dSXiongfeng Wang }
6229572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_unregister_templates);
6239572442dSXiongfeng Wang 
__crypto_lookup_template(const char * name)6244cc7720cSHerbert Xu static struct crypto_template *__crypto_lookup_template(const char *name)
6254cc7720cSHerbert Xu {
6264cc7720cSHerbert Xu 	struct crypto_template *q, *tmpl = NULL;
6274cc7720cSHerbert Xu 
6284cc7720cSHerbert Xu 	down_read(&crypto_alg_sem);
6294cc7720cSHerbert Xu 	list_for_each_entry(q, &crypto_template_list, list) {
6304cc7720cSHerbert Xu 		if (strcmp(q->name, name))
6314cc7720cSHerbert Xu 			continue;
6324cc7720cSHerbert Xu 		if (unlikely(!crypto_tmpl_get(q)))
6334cc7720cSHerbert Xu 			continue;
6344cc7720cSHerbert Xu 
6354cc7720cSHerbert Xu 		tmpl = q;
6364cc7720cSHerbert Xu 		break;
6374cc7720cSHerbert Xu 	}
6384cc7720cSHerbert Xu 	up_read(&crypto_alg_sem);
6394cc7720cSHerbert Xu 
6404cc7720cSHerbert Xu 	return tmpl;
6414cc7720cSHerbert Xu }
6424cc7720cSHerbert Xu 
crypto_lookup_template(const char * name)6434cc7720cSHerbert Xu struct crypto_template *crypto_lookup_template(const char *name)
6444cc7720cSHerbert Xu {
6454943ba16SKees Cook 	return try_then_request_module(__crypto_lookup_template(name),
6464943ba16SKees Cook 				       "crypto-%s", name);
6474cc7720cSHerbert Xu }
6484cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_lookup_template);
6494cc7720cSHerbert Xu 
crypto_register_instance(struct crypto_template * tmpl,struct crypto_instance * inst)6504cc7720cSHerbert Xu int crypto_register_instance(struct crypto_template *tmpl,
6514cc7720cSHerbert Xu 			     struct crypto_instance *inst)
6524cc7720cSHerbert Xu {
65373d3864aSHerbert Xu 	struct crypto_larval *larval;
6545f567fffSHerbert Xu 	struct crypto_spawn *spawn;
655d6097b8dSNicolai Stange 	u32 fips_internal = 0;
656a7008584SEric Biggers 	LIST_HEAD(algs_to_put);
65773d3864aSHerbert Xu 	int err;
6584cc7720cSHerbert Xu 
6594cc7720cSHerbert Xu 	err = crypto_check_alg(&inst->alg);
6604cc7720cSHerbert Xu 	if (err)
6619c521a20SStephan Mueller 		return err;
6629c521a20SStephan Mueller 
6634cc7720cSHerbert Xu 	inst->alg.cra_module = tmpl->module;
66464a947b1SSteffen Klassert 	inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE;
6654cc7720cSHerbert Xu 
6664cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
6674cc7720cSHerbert Xu 
6685f567fffSHerbert Xu 	larval = ERR_PTR(-EAGAIN);
6695f567fffSHerbert Xu 	for (spawn = inst->spawns; spawn;) {
6705f567fffSHerbert Xu 		struct crypto_spawn *next;
6715f567fffSHerbert Xu 
6725f567fffSHerbert Xu 		if (spawn->dead)
6735f567fffSHerbert Xu 			goto unlock;
6745f567fffSHerbert Xu 
6755f567fffSHerbert Xu 		next = spawn->next;
6765f567fffSHerbert Xu 		spawn->inst = inst;
6775f567fffSHerbert Xu 		spawn->registered = true;
6785f567fffSHerbert Xu 
679d6097b8dSNicolai Stange 		fips_internal |= spawn->alg->cra_flags;
680d6097b8dSNicolai Stange 
6815f567fffSHerbert Xu 		crypto_mod_put(spawn->alg);
6825f567fffSHerbert Xu 
6835f567fffSHerbert Xu 		spawn = next;
6845f567fffSHerbert Xu 	}
6855f567fffSHerbert Xu 
686d6097b8dSNicolai Stange 	inst->alg.cra_flags |= (fips_internal & CRYPTO_ALG_FIPS_INTERNAL);
687d6097b8dSNicolai Stange 
688a7008584SEric Biggers 	larval = __crypto_register_alg(&inst->alg, &algs_to_put);
68973d3864aSHerbert Xu 	if (IS_ERR(larval))
6904cc7720cSHerbert Xu 		goto unlock;
691cad439fcSHerbert Xu 	else if (larval)
692adad556eSHerbert Xu 		larval->test_started = true;
693adad556eSHerbert Xu 
6944cc7720cSHerbert Xu 	hlist_add_head(&inst->list, &tmpl->instances);
6954cc7720cSHerbert Xu 	inst->tmpl = tmpl;
6964cc7720cSHerbert Xu 
6974cc7720cSHerbert Xu unlock:
6984cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
6994cc7720cSHerbert Xu 
700a7008584SEric Biggers 	if (IS_ERR(larval))
701a7008584SEric Biggers 		return PTR_ERR(larval);
702a7008584SEric Biggers 	if (larval)
70373d3864aSHerbert Xu 		crypto_wait_for_test(larval);
704a7008584SEric Biggers 	crypto_remove_final(&algs_to_put);
705a7008584SEric Biggers 	return 0;
7064cc7720cSHerbert Xu }
7074cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_instance);
7084cc7720cSHerbert Xu 
crypto_unregister_instance(struct crypto_instance * inst)709c6d633a9SEric Biggers void crypto_unregister_instance(struct crypto_instance *inst)
710ce3fd840SSteffen Klassert {
7111f723710SHerbert Xu 	LIST_HEAD(list);
712ce3fd840SSteffen Klassert 
713ce3fd840SSteffen Klassert 	down_write(&crypto_alg_sem);
714ce3fd840SSteffen Klassert 
71587b16756SHerbert Xu 	crypto_remove_spawns(&inst->alg, &list, NULL);
7161f723710SHerbert Xu 	crypto_remove_instance(inst, &list);
717ce3fd840SSteffen Klassert 
718ce3fd840SSteffen Klassert 	up_write(&crypto_alg_sem);
719ce3fd840SSteffen Klassert 
7201f723710SHerbert Xu 	crypto_remove_final(&list);
721ce3fd840SSteffen Klassert }
722ce3fd840SSteffen Klassert EXPORT_SYMBOL_GPL(crypto_unregister_instance);
723ce3fd840SSteffen Klassert 
crypto_grab_spawn(struct crypto_spawn * spawn,struct crypto_instance * inst,const char * name,u32 type,u32 mask)724de95c957SEric Biggers int crypto_grab_spawn(struct crypto_spawn *spawn, struct crypto_instance *inst,
725de95c957SEric Biggers 		      const char *name, u32 type, u32 mask)
726d6ef2f19SHerbert Xu {
727d6ef2f19SHerbert Xu 	struct crypto_alg *alg;
728aed11cf5SEric Biggers 	int err = -EAGAIN;
729aed11cf5SEric Biggers 
730aed11cf5SEric Biggers 	if (WARN_ON_ONCE(inst == NULL))
731aed11cf5SEric Biggers 		return -EINVAL;
732d6ef2f19SHerbert Xu 
733ca94e937SEric Biggers 	/* Allow the result of crypto_attr_alg_name() to be passed directly */
734ca94e937SEric Biggers 	if (IS_ERR(name))
735ca94e937SEric Biggers 		return PTR_ERR(name);
736ca94e937SEric Biggers 
737d6097b8dSNicolai Stange 	alg = crypto_find_alg(name, spawn->frontend,
738d6097b8dSNicolai Stange 			      type | CRYPTO_ALG_FIPS_INTERNAL, mask);
739d6ef2f19SHerbert Xu 	if (IS_ERR(alg))
740d6ef2f19SHerbert Xu 		return PTR_ERR(alg);
741d6ef2f19SHerbert Xu 
742aed11cf5SEric Biggers 	down_write(&crypto_alg_sem);
743aed11cf5SEric Biggers 	if (!crypto_is_moribund(alg)) {
744aed11cf5SEric Biggers 		list_add(&spawn->list, &alg->cra_users);
745aed11cf5SEric Biggers 		spawn->alg = alg;
746aed11cf5SEric Biggers 		spawn->mask = mask;
747aed11cf5SEric Biggers 		spawn->next = inst->spawns;
748aed11cf5SEric Biggers 		inst->spawns = spawn;
7497bcb2c99SEric Biggers 		inst->alg.cra_flags |=
7507bcb2c99SEric Biggers 			(alg->cra_flags & CRYPTO_ALG_INHERITED_FLAGS);
751aed11cf5SEric Biggers 		err = 0;
752aed11cf5SEric Biggers 	}
753aed11cf5SEric Biggers 	up_write(&crypto_alg_sem);
7545f567fffSHerbert Xu 	if (err)
755d6ef2f19SHerbert Xu 		crypto_mod_put(alg);
756d6ef2f19SHerbert Xu 	return err;
757d6ef2f19SHerbert Xu }
758d6ef2f19SHerbert Xu EXPORT_SYMBOL_GPL(crypto_grab_spawn);
759d6ef2f19SHerbert Xu 
crypto_drop_spawn(struct crypto_spawn * spawn)7606bfd4809SHerbert Xu void crypto_drop_spawn(struct crypto_spawn *spawn)
7616bfd4809SHerbert Xu {
762ff670627SEric Biggers 	if (!spawn->alg) /* not yet initialized? */
763ff670627SEric Biggers 		return;
764ff670627SEric Biggers 
7656bfd4809SHerbert Xu 	down_write(&crypto_alg_sem);
7664f87ee11SHerbert Xu 	if (!spawn->dead)
7676bfd4809SHerbert Xu 		list_del(&spawn->list);
7686bfd4809SHerbert Xu 	up_write(&crypto_alg_sem);
7695f567fffSHerbert Xu 
770aed11cf5SEric Biggers 	if (!spawn->registered)
7715f567fffSHerbert Xu 		crypto_mod_put(spawn->alg);
7726bfd4809SHerbert Xu }
7736bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_drop_spawn);
7746bfd4809SHerbert Xu 
crypto_spawn_alg(struct crypto_spawn * spawn)77597eedce1SHerbert Xu static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
7766bfd4809SHerbert Xu {
7776603523bSHerbert Xu 	struct crypto_alg *alg = ERR_PTR(-EAGAIN);
7786603523bSHerbert Xu 	struct crypto_alg *target;
7796603523bSHerbert Xu 	bool shoot = false;
7806bfd4809SHerbert Xu 
7816bfd4809SHerbert Xu 	down_read(&crypto_alg_sem);
7826603523bSHerbert Xu 	if (!spawn->dead) {
7836bfd4809SHerbert Xu 		alg = spawn->alg;
7846603523bSHerbert Xu 		if (!crypto_mod_get(alg)) {
7856603523bSHerbert Xu 			target = crypto_alg_get(alg);
7866603523bSHerbert Xu 			shoot = true;
7876603523bSHerbert Xu 			alg = ERR_PTR(-EAGAIN);
7886603523bSHerbert Xu 		}
78973669cc5SHerbert Xu 	}
7906bfd4809SHerbert Xu 	up_read(&crypto_alg_sem);
7916bfd4809SHerbert Xu 
7926603523bSHerbert Xu 	if (shoot) {
7936603523bSHerbert Xu 		crypto_shoot_alg(target);
7946603523bSHerbert Xu 		crypto_alg_put(target);
7956603523bSHerbert Xu 	}
7966603523bSHerbert Xu 
7976603523bSHerbert Xu 	return alg;
79897eedce1SHerbert Xu }
79997eedce1SHerbert Xu 
crypto_spawn_tfm(struct crypto_spawn * spawn,u32 type,u32 mask)80097eedce1SHerbert Xu struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
80197eedce1SHerbert Xu 				    u32 mask)
80297eedce1SHerbert Xu {
80397eedce1SHerbert Xu 	struct crypto_alg *alg;
80497eedce1SHerbert Xu 	struct crypto_tfm *tfm;
80597eedce1SHerbert Xu 
80697eedce1SHerbert Xu 	alg = crypto_spawn_alg(spawn);
80797eedce1SHerbert Xu 	if (IS_ERR(alg))
80897eedce1SHerbert Xu 		return ERR_CAST(alg);
80997eedce1SHerbert Xu 
8102e306ee0SHerbert Xu 	tfm = ERR_PTR(-EINVAL);
8112e306ee0SHerbert Xu 	if (unlikely((alg->cra_flags ^ type) & mask))
8122e306ee0SHerbert Xu 		goto out_put_alg;
8132e306ee0SHerbert Xu 
81427d2a330SHerbert Xu 	tfm = __crypto_alloc_tfm(alg, type, mask);
8156bfd4809SHerbert Xu 	if (IS_ERR(tfm))
8162e306ee0SHerbert Xu 		goto out_put_alg;
8176bfd4809SHerbert Xu 
8186bfd4809SHerbert Xu 	return tfm;
8192e306ee0SHerbert Xu 
8202e306ee0SHerbert Xu out_put_alg:
8212e306ee0SHerbert Xu 	crypto_mod_put(alg);
8222e306ee0SHerbert Xu 	return tfm;
8236bfd4809SHerbert Xu }
8246bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
8256bfd4809SHerbert Xu 
crypto_spawn_tfm2(struct crypto_spawn * spawn)82697eedce1SHerbert Xu void *crypto_spawn_tfm2(struct crypto_spawn *spawn)
82797eedce1SHerbert Xu {
82897eedce1SHerbert Xu 	struct crypto_alg *alg;
82997eedce1SHerbert Xu 	struct crypto_tfm *tfm;
83097eedce1SHerbert Xu 
83197eedce1SHerbert Xu 	alg = crypto_spawn_alg(spawn);
83297eedce1SHerbert Xu 	if (IS_ERR(alg))
83397eedce1SHerbert Xu 		return ERR_CAST(alg);
83497eedce1SHerbert Xu 
83597eedce1SHerbert Xu 	tfm = crypto_create_tfm(alg, spawn->frontend);
83697eedce1SHerbert Xu 	if (IS_ERR(tfm))
83797eedce1SHerbert Xu 		goto out_put_alg;
83897eedce1SHerbert Xu 
83997eedce1SHerbert Xu 	return tfm;
84097eedce1SHerbert Xu 
84197eedce1SHerbert Xu out_put_alg:
84297eedce1SHerbert Xu 	crypto_mod_put(alg);
84397eedce1SHerbert Xu 	return tfm;
84497eedce1SHerbert Xu }
84597eedce1SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm2);
84697eedce1SHerbert Xu 
crypto_register_notifier(struct notifier_block * nb)8472825982dSHerbert Xu int crypto_register_notifier(struct notifier_block *nb)
8482825982dSHerbert Xu {
8492825982dSHerbert Xu 	return blocking_notifier_chain_register(&crypto_chain, nb);
8502825982dSHerbert Xu }
8512825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_notifier);
8522825982dSHerbert Xu 
crypto_unregister_notifier(struct notifier_block * nb)8532825982dSHerbert Xu int crypto_unregister_notifier(struct notifier_block *nb)
8542825982dSHerbert Xu {
8552825982dSHerbert Xu 	return blocking_notifier_chain_unregister(&crypto_chain, nb);
8562825982dSHerbert Xu }
8572825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
8582825982dSHerbert Xu 
crypto_get_attr_type(struct rtattr ** tb)859ebc610e5SHerbert Xu struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
8607fed0bf2SHerbert Xu {
86139e1ee01SHerbert Xu 	struct rtattr *rta = tb[0];
862ebc610e5SHerbert Xu 	struct crypto_attr_type *algt;
863ebc610e5SHerbert Xu 
864ebc610e5SHerbert Xu 	if (!rta)
865ebc610e5SHerbert Xu 		return ERR_PTR(-ENOENT);
866ebc610e5SHerbert Xu 	if (RTA_PAYLOAD(rta) < sizeof(*algt))
867ebc610e5SHerbert Xu 		return ERR_PTR(-EINVAL);
86839e1ee01SHerbert Xu 	if (rta->rta_type != CRYPTOA_TYPE)
86939e1ee01SHerbert Xu 		return ERR_PTR(-EINVAL);
870ebc610e5SHerbert Xu 
871ebc610e5SHerbert Xu 	algt = RTA_DATA(rta);
872ebc610e5SHerbert Xu 
873ebc610e5SHerbert Xu 	return algt;
874ebc610e5SHerbert Xu }
875ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_get_attr_type);
876ebc610e5SHerbert Xu 
8777bcb2c99SEric Biggers /**
8787bcb2c99SEric Biggers  * crypto_check_attr_type() - check algorithm type and compute inherited mask
8797bcb2c99SEric Biggers  * @tb: the template parameters
8807bcb2c99SEric Biggers  * @type: the algorithm type the template would be instantiated as
8817bcb2c99SEric Biggers  * @mask_ret: (output) the mask that should be passed to crypto_grab_*()
8827bcb2c99SEric Biggers  *	      to restrict the flags of any inner algorithms
8837bcb2c99SEric Biggers  *
8847bcb2c99SEric Biggers  * Validate that the algorithm type the user requested is compatible with the
8857bcb2c99SEric Biggers  * one the template would actually be instantiated as.  E.g., if the user is
8867bcb2c99SEric Biggers  * doing crypto_alloc_shash("cbc(aes)", ...), this would return an error because
8877bcb2c99SEric Biggers  * the "cbc" template creates an "skcipher" algorithm, not an "shash" algorithm.
8887bcb2c99SEric Biggers  *
8897bcb2c99SEric Biggers  * Also compute the mask to use to restrict the flags of any inner algorithms.
8907bcb2c99SEric Biggers  *
8917bcb2c99SEric Biggers  * Return: 0 on success; -errno on failure
8927bcb2c99SEric Biggers  */
crypto_check_attr_type(struct rtattr ** tb,u32 type,u32 * mask_ret)8937bcb2c99SEric Biggers int crypto_check_attr_type(struct rtattr **tb, u32 type, u32 *mask_ret)
894ebc610e5SHerbert Xu {
895ebc610e5SHerbert Xu 	struct crypto_attr_type *algt;
896ebc610e5SHerbert Xu 
897ebc610e5SHerbert Xu 	algt = crypto_get_attr_type(tb);
898ebc610e5SHerbert Xu 	if (IS_ERR(algt))
899ebc610e5SHerbert Xu 		return PTR_ERR(algt);
900ebc610e5SHerbert Xu 
901ebc610e5SHerbert Xu 	if ((algt->type ^ type) & algt->mask)
902ebc610e5SHerbert Xu 		return -EINVAL;
903ebc610e5SHerbert Xu 
9047bcb2c99SEric Biggers 	*mask_ret = crypto_algt_inherited_mask(algt);
905ebc610e5SHerbert Xu 	return 0;
906ebc610e5SHerbert Xu }
907ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_check_attr_type);
908ebc610e5SHerbert Xu 
crypto_attr_alg_name(struct rtattr * rta)90968b6c7d6SHerbert Xu const char *crypto_attr_alg_name(struct rtattr *rta)
910ebc610e5SHerbert Xu {
9117fed0bf2SHerbert Xu 	struct crypto_attr_alg *alga;
9127fed0bf2SHerbert Xu 
913ebc610e5SHerbert Xu 	if (!rta)
914ebc610e5SHerbert Xu 		return ERR_PTR(-ENOENT);
915ebc610e5SHerbert Xu 	if (RTA_PAYLOAD(rta) < sizeof(*alga))
9167fed0bf2SHerbert Xu 		return ERR_PTR(-EINVAL);
91739e1ee01SHerbert Xu 	if (rta->rta_type != CRYPTOA_ALG)
91839e1ee01SHerbert Xu 		return ERR_PTR(-EINVAL);
9197fed0bf2SHerbert Xu 
9207fed0bf2SHerbert Xu 	alga = RTA_DATA(rta);
9217fed0bf2SHerbert Xu 	alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
9227fed0bf2SHerbert Xu 
92368b6c7d6SHerbert Xu 	return alga->name;
92468b6c7d6SHerbert Xu }
92568b6c7d6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
92668b6c7d6SHerbert Xu 
crypto_inst_setname(struct crypto_instance * inst,const char * name,struct crypto_alg * alg)92732f27c74SHerbert Xu int crypto_inst_setname(struct crypto_instance *inst, const char *name,
92832f27c74SHerbert Xu 			struct crypto_alg *alg)
92932f27c74SHerbert Xu {
93032f27c74SHerbert Xu 	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
93132f27c74SHerbert Xu 		     alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
93232f27c74SHerbert Xu 		return -ENAMETOOLONG;
93332f27c74SHerbert Xu 
93432f27c74SHerbert Xu 	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
93532f27c74SHerbert Xu 		     name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
93632f27c74SHerbert Xu 		return -ENAMETOOLONG;
93732f27c74SHerbert Xu 
93832f27c74SHerbert Xu 	return 0;
93932f27c74SHerbert Xu }
94032f27c74SHerbert Xu EXPORT_SYMBOL_GPL(crypto_inst_setname);
94132f27c74SHerbert Xu 
crypto_init_queue(struct crypto_queue * queue,unsigned int max_qlen)942b5b7f088SHerbert Xu void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
943b5b7f088SHerbert Xu {
944b5b7f088SHerbert Xu 	INIT_LIST_HEAD(&queue->list);
945b5b7f088SHerbert Xu 	queue->backlog = &queue->list;
946b5b7f088SHerbert Xu 	queue->qlen = 0;
947b5b7f088SHerbert Xu 	queue->max_qlen = max_qlen;
948b5b7f088SHerbert Xu }
949b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_init_queue);
950b5b7f088SHerbert Xu 
crypto_enqueue_request(struct crypto_queue * queue,struct crypto_async_request * request)951b5b7f088SHerbert Xu int crypto_enqueue_request(struct crypto_queue *queue,
952b5b7f088SHerbert Xu 			   struct crypto_async_request *request)
953b5b7f088SHerbert Xu {
954b5b7f088SHerbert Xu 	int err = -EINPROGRESS;
955b5b7f088SHerbert Xu 
956b5b7f088SHerbert Xu 	if (unlikely(queue->qlen >= queue->max_qlen)) {
9576b80ea38SGilad Ben-Yossef 		if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
9586b80ea38SGilad Ben-Yossef 			err = -ENOSPC;
959b5b7f088SHerbert Xu 			goto out;
9606b80ea38SGilad Ben-Yossef 		}
9616b80ea38SGilad Ben-Yossef 		err = -EBUSY;
962b5b7f088SHerbert Xu 		if (queue->backlog == &queue->list)
963b5b7f088SHerbert Xu 			queue->backlog = &request->list;
964b5b7f088SHerbert Xu 	}
965b5b7f088SHerbert Xu 
966b5b7f088SHerbert Xu 	queue->qlen++;
967b5b7f088SHerbert Xu 	list_add_tail(&request->list, &queue->list);
968b5b7f088SHerbert Xu 
969b5b7f088SHerbert Xu out:
970b5b7f088SHerbert Xu 	return err;
971b5b7f088SHerbert Xu }
972b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_enqueue_request);
973b5b7f088SHerbert Xu 
crypto_enqueue_request_head(struct crypto_queue * queue,struct crypto_async_request * request)974ec6e2bf3SIuliana Prodan void crypto_enqueue_request_head(struct crypto_queue *queue,
975ec6e2bf3SIuliana Prodan 				 struct crypto_async_request *request)
976ec6e2bf3SIuliana Prodan {
9774140aafcSOlivier Bacon 	if (unlikely(queue->qlen >= queue->max_qlen))
9784140aafcSOlivier Bacon 		queue->backlog = queue->backlog->prev;
9794140aafcSOlivier Bacon 
980ec6e2bf3SIuliana Prodan 	queue->qlen++;
981ec6e2bf3SIuliana Prodan 	list_add(&request->list, &queue->list);
982ec6e2bf3SIuliana Prodan }
983ec6e2bf3SIuliana Prodan EXPORT_SYMBOL_GPL(crypto_enqueue_request_head);
984ec6e2bf3SIuliana Prodan 
crypto_dequeue_request(struct crypto_queue * queue)98531d228ccSHerbert Xu struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
986b5b7f088SHerbert Xu {
987b5b7f088SHerbert Xu 	struct list_head *request;
988b5b7f088SHerbert Xu 
989b5b7f088SHerbert Xu 	if (unlikely(!queue->qlen))
990b5b7f088SHerbert Xu 		return NULL;
991b5b7f088SHerbert Xu 
992b5b7f088SHerbert Xu 	queue->qlen--;
993b5b7f088SHerbert Xu 
994b5b7f088SHerbert Xu 	if (queue->backlog != &queue->list)
995b5b7f088SHerbert Xu 		queue->backlog = queue->backlog->next;
996b5b7f088SHerbert Xu 
997b5b7f088SHerbert Xu 	request = queue->list.next;
998b5b7f088SHerbert Xu 	list_del(request);
999b5b7f088SHerbert Xu 
100031d228ccSHerbert Xu 	return list_entry(request, struct crypto_async_request, list);
1001b5b7f088SHerbert Xu }
1002b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_dequeue_request);
1003b5b7f088SHerbert Xu 
crypto_inc_byte(u8 * a,unsigned int size)10047613636dSHerbert Xu static inline void crypto_inc_byte(u8 *a, unsigned int size)
10057613636dSHerbert Xu {
10067613636dSHerbert Xu 	u8 *b = (a + size);
10077613636dSHerbert Xu 	u8 c;
10087613636dSHerbert Xu 
10097613636dSHerbert Xu 	for (; size; size--) {
10107613636dSHerbert Xu 		c = *--b + 1;
10117613636dSHerbert Xu 		*b = c;
10127613636dSHerbert Xu 		if (c)
10137613636dSHerbert Xu 			break;
10147613636dSHerbert Xu 	}
10157613636dSHerbert Xu }
10167613636dSHerbert Xu 
crypto_inc(u8 * a,unsigned int size)10177613636dSHerbert Xu void crypto_inc(u8 *a, unsigned int size)
10187613636dSHerbert Xu {
10197613636dSHerbert Xu 	__be32 *b = (__be32 *)(a + size);
10207613636dSHerbert Xu 	u32 c;
10217613636dSHerbert Xu 
1022db91af0fSArd Biesheuvel 	if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
102327c539aeSArd Biesheuvel 	    IS_ALIGNED((unsigned long)b, __alignof__(*b)))
10247613636dSHerbert Xu 		for (; size >= 4; size -= 4) {
10257613636dSHerbert Xu 			c = be32_to_cpu(*--b) + 1;
10267613636dSHerbert Xu 			*b = cpu_to_be32(c);
102727c539aeSArd Biesheuvel 			if (likely(c))
10287613636dSHerbert Xu 				return;
10297613636dSHerbert Xu 		}
10307613636dSHerbert Xu 
10317613636dSHerbert Xu 	crypto_inc_byte(a, size);
10327613636dSHerbert Xu }
10337613636dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_inc);
10347613636dSHerbert Xu 
crypto_alg_extsize(struct crypto_alg * alg)103538d21433SHerbert Xu unsigned int crypto_alg_extsize(struct crypto_alg *alg)
103638d21433SHerbert Xu {
1037c2110f28SHerbert Xu 	return alg->cra_ctxsize +
1038c2110f28SHerbert Xu 	       (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
103938d21433SHerbert Xu }
104038d21433SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_extsize);
104138d21433SHerbert Xu 
crypto_type_has_alg(const char * name,const struct crypto_type * frontend,u32 type,u32 mask)1042f2aefdabSHerbert Xu int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
1043f2aefdabSHerbert Xu 			u32 type, u32 mask)
1044f2aefdabSHerbert Xu {
1045f2aefdabSHerbert Xu 	int ret = 0;
1046f2aefdabSHerbert Xu 	struct crypto_alg *alg = crypto_find_alg(name, frontend, type, mask);
1047f2aefdabSHerbert Xu 
1048f2aefdabSHerbert Xu 	if (!IS_ERR(alg)) {
1049f2aefdabSHerbert Xu 		crypto_mod_put(alg);
1050f2aefdabSHerbert Xu 		ret = 1;
1051f2aefdabSHerbert Xu 	}
1052f2aefdabSHerbert Xu 
1053f2aefdabSHerbert Xu 	return ret;
1054f2aefdabSHerbert Xu }
1055f2aefdabSHerbert Xu EXPORT_SYMBOL_GPL(crypto_type_has_alg);
1056f2aefdabSHerbert Xu 
crypto_start_tests(void)1057adad556eSHerbert Xu static void __init crypto_start_tests(void)
1058adad556eSHerbert Xu {
105906bd9c96SEric Biggers 	if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS))
106006bd9c96SEric Biggers 		return;
106106bd9c96SEric Biggers 
1062adad556eSHerbert Xu 	for (;;) {
1063adad556eSHerbert Xu 		struct crypto_larval *larval = NULL;
1064adad556eSHerbert Xu 		struct crypto_alg *q;
1065adad556eSHerbert Xu 
1066adad556eSHerbert Xu 		down_write(&crypto_alg_sem);
1067adad556eSHerbert Xu 
1068adad556eSHerbert Xu 		list_for_each_entry(q, &crypto_alg_list, cra_list) {
1069adad556eSHerbert Xu 			struct crypto_larval *l;
1070adad556eSHerbert Xu 
1071adad556eSHerbert Xu 			if (!crypto_is_larval(q))
1072adad556eSHerbert Xu 				continue;
1073adad556eSHerbert Xu 
1074adad556eSHerbert Xu 			l = (void *)q;
1075adad556eSHerbert Xu 
1076adad556eSHerbert Xu 			if (!crypto_is_test_larval(l))
1077adad556eSHerbert Xu 				continue;
1078adad556eSHerbert Xu 
1079adad556eSHerbert Xu 			if (l->test_started)
1080adad556eSHerbert Xu 				continue;
1081adad556eSHerbert Xu 
1082adad556eSHerbert Xu 			l->test_started = true;
1083adad556eSHerbert Xu 			larval = l;
1084adad556eSHerbert Xu 			break;
1085adad556eSHerbert Xu 		}
1086adad556eSHerbert Xu 
1087adad556eSHerbert Xu 		up_write(&crypto_alg_sem);
1088adad556eSHerbert Xu 
1089adad556eSHerbert Xu 		if (!larval)
1090adad556eSHerbert Xu 			break;
1091adad556eSHerbert Xu 
1092adad556eSHerbert Xu 		crypto_wait_for_test(larval);
1093adad556eSHerbert Xu 	}
1094adad556eSHerbert Xu 
109506bd9c96SEric Biggers 	set_crypto_boot_test_finished();
1096adad556eSHerbert Xu }
1097adad556eSHerbert Xu 
crypto_algapi_init(void)1098cce9e06dSHerbert Xu static int __init crypto_algapi_init(void)
1099cce9e06dSHerbert Xu {
1100cce9e06dSHerbert Xu 	crypto_init_proc();
1101adad556eSHerbert Xu 	crypto_start_tests();
1102cce9e06dSHerbert Xu 	return 0;
1103cce9e06dSHerbert Xu }
1104cce9e06dSHerbert Xu 
crypto_algapi_exit(void)1105cce9e06dSHerbert Xu static void __exit crypto_algapi_exit(void)
1106cce9e06dSHerbert Xu {
1107cce9e06dSHerbert Xu 	crypto_exit_proc();
1108cce9e06dSHerbert Xu }
1109cce9e06dSHerbert Xu 
1110adad556eSHerbert Xu /*
1111adad556eSHerbert Xu  * We run this at late_initcall so that all the built-in algorithms
1112adad556eSHerbert Xu  * have had a chance to register themselves first.
1113adad556eSHerbert Xu  */
1114adad556eSHerbert Xu late_initcall(crypto_algapi_init);
1115cce9e06dSHerbert Xu module_exit(crypto_algapi_exit);
1116cce9e06dSHerbert Xu 
1117cce9e06dSHerbert Xu MODULE_LICENSE("GPL");
1118cce9e06dSHerbert Xu MODULE_DESCRIPTION("Cryptographic algorithms API");
1119c6ce9c58SHerbert Xu MODULE_SOFTDEP("pre: cryptomgr");
1120