xref: /linux-6.15/crypto/algapi.c (revision 27b13425)
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 <[email protected]>
6cce9e06dSHerbert Xu  */
7cce9e06dSHerbert Xu 
813c935bbSSalvatore Mesoraca #include <crypto/algapi.h>
96bfd4809SHerbert Xu #include <linux/err.h>
10cce9e06dSHerbert Xu #include <linux/errno.h>
113133d76fSHerbert Xu #include <linux/fips.h>
12cce9e06dSHerbert Xu #include <linux/init.h>
13cce9e06dSHerbert Xu #include <linux/kernel.h>
144cc7720cSHerbert Xu #include <linux/list.h>
15cce9e06dSHerbert Xu #include <linux/module.h>
167fed0bf2SHerbert Xu #include <linux/rtnetlink.h>
175a0e3ad6STejun Heo #include <linux/slab.h>
18cce9e06dSHerbert Xu #include <linux/string.h>
199ae4577bSHerbert Xu #include <linux/workqueue.h>
20cce9e06dSHerbert Xu 
21cce9e06dSHerbert Xu #include "internal.h"
22cce9e06dSHerbert Xu 
234cc7720cSHerbert Xu static LIST_HEAD(crypto_template_list);
244cc7720cSHerbert Xu 
crypto_check_module_sig(struct module * mod)25002c77a4SJarod Wilson static inline void crypto_check_module_sig(struct module *mod)
26002c77a4SJarod Wilson {
2759afdc7bSHerbert Xu 	if (fips_enabled && mod && !module_sig_ok(mod))
28002c77a4SJarod Wilson 		panic("Module %s signature verification failed in FIPS mode\n",
29bd4a7c69SHerbert Xu 		      module_name(mod));
30002c77a4SJarod Wilson }
31002c77a4SJarod Wilson 
crypto_check_alg(struct crypto_alg * alg)324cc7720cSHerbert Xu static int crypto_check_alg(struct crypto_alg *alg)
33cce9e06dSHerbert Xu {
34002c77a4SJarod Wilson 	crypto_check_module_sig(alg->cra_module);
35002c77a4SJarod Wilson 
36177f87d0SEric Biggers 	if (!alg->cra_name[0] || !alg->cra_driver_name[0])
37177f87d0SEric Biggers 		return -EINVAL;
38177f87d0SEric Biggers 
39cce9e06dSHerbert Xu 	if (alg->cra_alignmask & (alg->cra_alignmask + 1))
40cce9e06dSHerbert Xu 		return -EINVAL;
41cce9e06dSHerbert Xu 
42a9f7f88aSKees Cook 	/* General maximums for all algs. */
43a9f7f88aSKees Cook 	if (alg->cra_alignmask > MAX_ALGAPI_ALIGNMASK)
44cce9e06dSHerbert Xu 		return -EINVAL;
45cce9e06dSHerbert Xu 
46a9f7f88aSKees Cook 	if (alg->cra_blocksize > MAX_ALGAPI_BLOCKSIZE)
47a9f7f88aSKees Cook 		return -EINVAL;
48a9f7f88aSKees Cook 
49a9f7f88aSKees Cook 	/* Lower maximums for specific alg types. */
5013c935bbSSalvatore Mesoraca 	if (!alg->cra_type && (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
5113c935bbSSalvatore Mesoraca 			       CRYPTO_ALG_TYPE_CIPHER) {
5213c935bbSSalvatore Mesoraca 		if (alg->cra_alignmask > MAX_CIPHER_ALIGNMASK)
5313c935bbSSalvatore Mesoraca 			return -EINVAL;
5413c935bbSSalvatore Mesoraca 
5513c935bbSSalvatore Mesoraca 		if (alg->cra_blocksize > MAX_CIPHER_BLOCKSIZE)
5613c935bbSSalvatore Mesoraca 			return -EINVAL;
5713c935bbSSalvatore Mesoraca 	}
5813c935bbSSalvatore Mesoraca 
59cce9e06dSHerbert Xu 	if (alg->cra_priority < 0)
60cce9e06dSHerbert Xu 		return -EINVAL;
61cce9e06dSHerbert Xu 
62ce8614a3SEric Biggers 	refcount_set(&alg->cra_refcnt, 1);
63e9b8e5beSHerbert Xu 
64177f87d0SEric Biggers 	return 0;
654cc7720cSHerbert Xu }
66cce9e06dSHerbert Xu 
crypto_free_instance(struct crypto_instance * inst)67319382a6SHerbert Xu static void crypto_free_instance(struct crypto_instance *inst)
68319382a6SHerbert Xu {
69319382a6SHerbert Xu 	inst->alg.cra_type->free(inst);
70319382a6SHerbert Xu }
71319382a6SHerbert Xu 
crypto_destroy_instance_workfn(struct work_struct * w)729ae4577bSHerbert Xu static void crypto_destroy_instance_workfn(struct work_struct *w)
736bfd4809SHerbert Xu {
749ae4577bSHerbert Xu 	struct crypto_instance *inst = container_of(w, struct crypto_instance,
759ae4577bSHerbert Xu 						    free_work);
766bfd4809SHerbert Xu 	struct crypto_template *tmpl = inst->tmpl;
776bfd4809SHerbert Xu 
78319382a6SHerbert Xu 	crypto_free_instance(inst);
796bfd4809SHerbert Xu 	crypto_tmpl_put(tmpl);
806bfd4809SHerbert Xu }
816bfd4809SHerbert Xu 
crypto_destroy_instance(struct crypto_alg * alg)829ae4577bSHerbert Xu static void crypto_destroy_instance(struct crypto_alg *alg)
839ae4577bSHerbert Xu {
849ae4577bSHerbert Xu 	struct crypto_instance *inst = container_of(alg,
859ae4577bSHerbert Xu 						    struct crypto_instance,
869ae4577bSHerbert Xu 						    alg);
879ae4577bSHerbert Xu 
889ae4577bSHerbert Xu 	INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
899ae4577bSHerbert Xu 	schedule_work(&inst->free_work);
909ae4577bSHerbert Xu }
919ae4577bSHerbert Xu 
9202244ba4SHerbert Xu /*
9302244ba4SHerbert Xu  * This function adds a spawn to the list secondary_spawns which
9402244ba4SHerbert Xu  * will be used at the end of crypto_remove_spawns to unregister
9502244ba4SHerbert Xu  * instances, unless the spawn happens to be one that is depended
9602244ba4SHerbert Xu  * on by the new algorithm (nalg in crypto_remove_spawns).
9702244ba4SHerbert Xu  *
9802244ba4SHerbert Xu  * This function is also responsible for resurrecting any algorithms
9902244ba4SHerbert Xu  * in the dependency chain of nalg by unsetting n->dead.
10002244ba4SHerbert Xu  */
crypto_more_spawns(struct crypto_alg * alg,struct list_head * stack,struct list_head * top,struct list_head * secondary_spawns)1012bf29016SHerbert Xu static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
1022bf29016SHerbert Xu 					    struct list_head *stack,
1032bf29016SHerbert Xu 					    struct list_head *top,
104a73e6996SHerbert Xu 					    struct list_head *secondary_spawns)
1056bfd4809SHerbert Xu {
1062bf29016SHerbert Xu 	struct crypto_spawn *spawn, *n;
1072bf29016SHerbert Xu 
108304e4818SGeliang Tang 	spawn = list_first_entry_or_null(stack, struct crypto_spawn, list);
109304e4818SGeliang Tang 	if (!spawn)
1102bf29016SHerbert Xu 		return NULL;
1112bf29016SHerbert Xu 
1124f87ee11SHerbert Xu 	n = list_prev_entry(spawn, list);
1132bf29016SHerbert Xu 	list_move(&spawn->list, secondary_spawns);
1142bf29016SHerbert Xu 
1154f87ee11SHerbert Xu 	if (list_is_last(&n->list, stack))
1164f87ee11SHerbert Xu 		return top;
1174f87ee11SHerbert Xu 
1184f87ee11SHerbert Xu 	n = list_next_entry(n, list);
1194f87ee11SHerbert Xu 	if (!spawn->dead)
1204f87ee11SHerbert Xu 		n->dead = false;
1214f87ee11SHerbert Xu 
1224f87ee11SHerbert Xu 	return &n->inst->alg.cra_users;
1232bf29016SHerbert Xu }
1242bf29016SHerbert Xu 
crypto_remove_instance(struct crypto_instance * inst,struct list_head * list)1251f723710SHerbert Xu static void crypto_remove_instance(struct crypto_instance *inst,
1262bf29016SHerbert Xu 				   struct list_head *list)
1272bf29016SHerbert Xu {
1286bfd4809SHerbert Xu 	struct crypto_template *tmpl = inst->tmpl;
1296bfd4809SHerbert Xu 
1306bfd4809SHerbert Xu 	if (crypto_is_dead(&inst->alg))
131a73e6996SHerbert Xu 		return;
1326bfd4809SHerbert Xu 
1336bfd4809SHerbert Xu 	inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
13438cb2419SHerbert Xu 
1356bfd4809SHerbert Xu 	if (!tmpl || !crypto_tmpl_get(tmpl))
136a73e6996SHerbert Xu 		return;
1376bfd4809SHerbert Xu 
1386bfd4809SHerbert Xu 	list_move(&inst->alg.cra_list, list);
1396bfd4809SHerbert Xu 	hlist_del(&inst->list);
1406bfd4809SHerbert Xu 	inst->alg.cra_destroy = crypto_destroy_instance;
1416bfd4809SHerbert Xu 
1422bf29016SHerbert Xu 	BUG_ON(!list_empty(&inst->alg.cra_users));
1436bfd4809SHerbert Xu }
144a73e6996SHerbert Xu 
14502244ba4SHerbert Xu /*
14602244ba4SHerbert Xu  * Given an algorithm alg, remove all algorithms that depend on it
14702244ba4SHerbert Xu  * through spawns.  If nalg is not null, then exempt any algorithms
14802244ba4SHerbert Xu  * that is depended on by nalg.  This is useful when nalg itself
14902244ba4SHerbert Xu  * depends on alg.
15002244ba4SHerbert Xu  */
crypto_remove_spawns(struct crypto_alg * alg,struct list_head * list,struct crypto_alg * nalg)15189b596baSSteffen Klassert void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
1522bf29016SHerbert Xu 			  struct crypto_alg *nalg)
153a73e6996SHerbert Xu {
1542bf29016SHerbert Xu 	u32 new_type = (nalg ?: alg)->cra_flags;
155a73e6996SHerbert Xu 	struct crypto_spawn *spawn, *n;
156a73e6996SHerbert Xu 	LIST_HEAD(secondary_spawns);
1572bf29016SHerbert Xu 	struct list_head *spawns;
1582bf29016SHerbert Xu 	LIST_HEAD(stack);
1592bf29016SHerbert Xu 	LIST_HEAD(top);
160a73e6996SHerbert Xu 
1612bf29016SHerbert Xu 	spawns = &alg->cra_users;
162a73e6996SHerbert Xu 	list_for_each_entry_safe(spawn, n, spawns, list) {
163a73e6996SHerbert Xu 		if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
164a73e6996SHerbert Xu 			continue;
165a73e6996SHerbert Xu 
1662bf29016SHerbert Xu 		list_move(&spawn->list, &top);
167a73e6996SHerbert Xu 	}
168a73e6996SHerbert Xu 
16902244ba4SHerbert Xu 	/*
17002244ba4SHerbert Xu 	 * Perform a depth-first walk starting from alg through
17102244ba4SHerbert Xu 	 * the cra_users tree.  The list stack records the path
17202244ba4SHerbert Xu 	 * from alg to the current spawn.
17302244ba4SHerbert Xu 	 */
1742bf29016SHerbert Xu 	spawns = &top;
1752bf29016SHerbert Xu 	do {
1762bf29016SHerbert Xu 		while (!list_empty(spawns)) {
1772bf29016SHerbert Xu 			struct crypto_instance *inst;
1782bf29016SHerbert Xu 
1792bf29016SHerbert Xu 			spawn = list_first_entry(spawns, struct crypto_spawn,
1802bf29016SHerbert Xu 						 list);
1812bf29016SHerbert Xu 			inst = spawn->inst;
1822bf29016SHerbert Xu 
1832bf29016SHerbert Xu 			list_move(&spawn->list, &stack);
1845f567fffSHerbert Xu 			spawn->dead = !spawn->registered || &inst->alg != nalg;
1855f567fffSHerbert Xu 
1865f567fffSHerbert Xu 			if (!spawn->registered)
1875f567fffSHerbert Xu 				break;
1885f567fffSHerbert Xu 
1895f567fffSHerbert Xu 			BUG_ON(&inst->alg == alg);
1902bf29016SHerbert Xu 
1912bf29016SHerbert Xu 			if (&inst->alg == nalg)
1922bf29016SHerbert Xu 				break;
1932bf29016SHerbert Xu 
1942bf29016SHerbert Xu 			spawns = &inst->alg.cra_users;
1959a006742SEric Biggers 
1969a006742SEric Biggers 			/*
1975f567fffSHerbert Xu 			 * Even if spawn->registered is true, the
1985f567fffSHerbert Xu 			 * instance itself may still be unregistered.
1995f567fffSHerbert Xu 			 * This is because it may have failed during
2005f567fffSHerbert Xu 			 * registration.  Therefore we still need to
2015f567fffSHerbert Xu 			 * make the following test.
2025f567fffSHerbert Xu 			 *
2039a006742SEric Biggers 			 * We may encounter an unregistered instance here, since
2049a006742SEric Biggers 			 * an instance's spawns are set up prior to the instance
2059a006742SEric Biggers 			 * being registered.  An unregistered instance will have
2069a006742SEric Biggers 			 * NULL ->cra_users.next, since ->cra_users isn't
2079a006742SEric Biggers 			 * properly initialized until registration.  But an
2089a006742SEric Biggers 			 * unregistered instance cannot have any users, so treat
2099a006742SEric Biggers 			 * it the same as ->cra_users being empty.
2109a006742SEric Biggers 			 */
2119a006742SEric Biggers 			if (spawns->next == NULL)
2129a006742SEric Biggers 				break;
2132bf29016SHerbert Xu 		}
2142bf29016SHerbert Xu 	} while ((spawns = crypto_more_spawns(alg, &stack, &top,
2152bf29016SHerbert Xu 					      &secondary_spawns)));
2162bf29016SHerbert Xu 
21702244ba4SHerbert Xu 	/*
21802244ba4SHerbert Xu 	 * Remove all instances that are marked as dead.  Also
21902244ba4SHerbert Xu 	 * complete the resurrection of the others by moving them
22002244ba4SHerbert Xu 	 * back to the cra_users list.
22102244ba4SHerbert Xu 	 */
2222bf29016SHerbert Xu 	list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
2234f87ee11SHerbert Xu 		if (!spawn->dead)
2242bf29016SHerbert Xu 			list_move(&spawn->list, &spawn->alg->cra_users);
2255f567fffSHerbert Xu 		else if (spawn->registered)
2261f723710SHerbert Xu 			crypto_remove_instance(spawn->inst, list);
2276bfd4809SHerbert Xu 	}
2286bfd4809SHerbert Xu }
22989b596baSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_spawns);
2306bfd4809SHerbert Xu 
crypto_alg_finish_registration(struct crypto_alg * alg,struct list_head * algs_to_put)231a7008584SEric Biggers static void crypto_alg_finish_registration(struct crypto_alg *alg,
232a7008584SEric Biggers 					   struct list_head *algs_to_put)
233a7008584SEric Biggers {
234a7008584SEric Biggers 	struct crypto_alg *q;
235a7008584SEric Biggers 
236a7008584SEric Biggers 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
237a7008584SEric Biggers 		if (q == alg)
238a7008584SEric Biggers 			continue;
239a7008584SEric Biggers 
240a7008584SEric Biggers 		if (crypto_is_moribund(q))
241a7008584SEric Biggers 			continue;
242a7008584SEric Biggers 
24396ad5955SHerbert Xu 		if (crypto_is_larval(q))
244a7008584SEric Biggers 			continue;
245a7008584SEric Biggers 
246a7008584SEric Biggers 		if (strcmp(alg->cra_name, q->cra_name))
247a7008584SEric Biggers 			continue;
248a7008584SEric Biggers 
249a7008584SEric Biggers 		if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
250a7008584SEric Biggers 		    q->cra_priority > alg->cra_priority)
251a7008584SEric Biggers 			continue;
252a7008584SEric Biggers 
253a7008584SEric Biggers 		crypto_remove_spawns(q, algs_to_put, alg);
254a7008584SEric Biggers 	}
255a7008584SEric Biggers 
256a7008584SEric Biggers 	crypto_notify(CRYPTO_MSG_ALG_LOADED, alg);
257a7008584SEric Biggers }
258a7008584SEric Biggers 
crypto_alloc_test_larval(struct crypto_alg * alg)259cad439fcSHerbert Xu static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg)
260cad439fcSHerbert Xu {
261cad439fcSHerbert Xu 	struct crypto_larval *larval;
262cad439fcSHerbert Xu 
263a7008584SEric Biggers 	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER) ||
2649cadd73aSEric Biggers 	    IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) ||
2659cadd73aSEric Biggers 	    (alg->cra_flags & CRYPTO_ALG_INTERNAL))
266a7008584SEric Biggers 		return NULL; /* No self-test needed */
267cad439fcSHerbert Xu 
268cad439fcSHerbert Xu 	larval = crypto_larval_alloc(alg->cra_name,
269cad439fcSHerbert Xu 				     alg->cra_flags | CRYPTO_ALG_TESTED, 0);
270cad439fcSHerbert Xu 	if (IS_ERR(larval))
271cad439fcSHerbert Xu 		return larval;
272cad439fcSHerbert Xu 
273cad439fcSHerbert Xu 	larval->adult = crypto_mod_get(alg);
274cad439fcSHerbert Xu 	if (!larval->adult) {
275cad439fcSHerbert Xu 		kfree(larval);
276cad439fcSHerbert Xu 		return ERR_PTR(-ENOENT);
277cad439fcSHerbert Xu 	}
278cad439fcSHerbert Xu 
279cad439fcSHerbert Xu 	refcount_set(&larval->alg.cra_refcnt, 1);
280cad439fcSHerbert Xu 	memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
281cad439fcSHerbert Xu 	       CRYPTO_MAX_ALG_NAME);
282cad439fcSHerbert Xu 	larval->alg.cra_priority = alg->cra_priority;
283cad439fcSHerbert Xu 
284cad439fcSHerbert Xu 	return larval;
285cad439fcSHerbert Xu }
286cad439fcSHerbert Xu 
287a7008584SEric Biggers static struct crypto_larval *
__crypto_register_alg(struct crypto_alg * alg,struct list_head * algs_to_put)288a7008584SEric Biggers __crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_put)
2894cc7720cSHerbert Xu {
2904cc7720cSHerbert Xu 	struct crypto_alg *q;
29173d3864aSHerbert Xu 	struct crypto_larval *larval;
2926bfd4809SHerbert Xu 	int ret = -EAGAIN;
2936bfd4809SHerbert Xu 
2946bfd4809SHerbert Xu 	if (crypto_is_dead(alg))
29573d3864aSHerbert Xu 		goto err;
2966bfd4809SHerbert Xu 
2976bfd4809SHerbert Xu 	INIT_LIST_HEAD(&alg->cra_users);
2986bfd4809SHerbert Xu 
2996bfd4809SHerbert Xu 	ret = -EEXIST;
300cce9e06dSHerbert Xu 
301cce9e06dSHerbert Xu 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
3024cc7720cSHerbert Xu 		if (q == alg)
30373d3864aSHerbert Xu 			goto err;
30473d3864aSHerbert Xu 
305b8e15992SHerbert Xu 		if (crypto_is_moribund(q))
306b8e15992SHerbert Xu 			continue;
307b8e15992SHerbert Xu 
30873d3864aSHerbert Xu 		if (crypto_is_larval(q)) {
30973d3864aSHerbert Xu 			if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
31073d3864aSHerbert Xu 				goto err;
31173d3864aSHerbert Xu 			continue;
31273d3864aSHerbert Xu 		}
31373d3864aSHerbert Xu 
31473d3864aSHerbert Xu 		if (!strcmp(q->cra_driver_name, alg->cra_name) ||
31527016f75SHerbert Xu 		    !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
31673d3864aSHerbert Xu 		    !strcmp(q->cra_name, alg->cra_driver_name))
31773d3864aSHerbert Xu 			goto err;
31873d3864aSHerbert Xu 	}
31973d3864aSHerbert Xu 
320cad439fcSHerbert Xu 	larval = crypto_alloc_test_larval(alg);
32173d3864aSHerbert Xu 	if (IS_ERR(larval))
322cce9e06dSHerbert Xu 		goto out;
3236bfd4809SHerbert Xu 
32473d3864aSHerbert Xu 	list_add(&alg->cra_list, &crypto_alg_list);
325cad439fcSHerbert Xu 
326a7008584SEric Biggers 	if (larval) {
327a7008584SEric Biggers 		/* No cheating! */
328a7008584SEric Biggers 		alg->cra_flags &= ~CRYPTO_ALG_TESTED;
329a7008584SEric Biggers 
330a7008584SEric Biggers 		list_add(&larval->alg.cra_list, &crypto_alg_list);
331a7008584SEric Biggers 	} else {
332a7008584SEric Biggers 		alg->cra_flags |= CRYPTO_ALG_TESTED;
33396ad5955SHerbert Xu 		crypto_alg_finish_registration(alg, algs_to_put);
334a7008584SEric Biggers 	}
335a7008584SEric Biggers 
33673d3864aSHerbert Xu out:
33773d3864aSHerbert Xu 	return larval;
33873d3864aSHerbert Xu 
33973d3864aSHerbert Xu err:
34073d3864aSHerbert Xu 	larval = ERR_PTR(ret);
34173d3864aSHerbert Xu 	goto out;
34273d3864aSHerbert Xu }
34373d3864aSHerbert Xu 
crypto_alg_tested(const char * name,int err)34473d3864aSHerbert Xu void crypto_alg_tested(const char *name, int err)
34573d3864aSHerbert Xu {
34673d3864aSHerbert Xu 	struct crypto_larval *test;
34773d3864aSHerbert Xu 	struct crypto_alg *alg;
34873d3864aSHerbert Xu 	struct crypto_alg *q;
34973d3864aSHerbert Xu 	LIST_HEAD(list);
35073d3864aSHerbert Xu 
35173d3864aSHerbert Xu 	down_write(&crypto_alg_sem);
35273d3864aSHerbert Xu 	list_for_each_entry(q, &crypto_alg_list, cra_list) {
353b8e15992SHerbert Xu 		if (crypto_is_moribund(q) || !crypto_is_larval(q))
35473d3864aSHerbert Xu 			continue;
35573d3864aSHerbert Xu 
35673d3864aSHerbert Xu 		test = (struct crypto_larval *)q;
35773d3864aSHerbert Xu 
35873d3864aSHerbert Xu 		if (!strcmp(q->cra_driver_name, name))
35973d3864aSHerbert Xu 			goto found;
36073d3864aSHerbert Xu 	}
36173d3864aSHerbert Xu 
362c7235857SKarim Eshapa 	pr_err("alg: Unexpected test result for %s: %d\n", name, err);
36337da5d0fSHerbert Xu 	up_write(&crypto_alg_sem);
36437da5d0fSHerbert Xu 	return;
36573d3864aSHerbert Xu 
36673d3864aSHerbert Xu found:
367b8e15992SHerbert Xu 	q->cra_flags |= CRYPTO_ALG_DEAD;
36873d3864aSHerbert Xu 	alg = test->adult;
369d6097b8dSNicolai Stange 
370b81e286bSHerbert Xu 	if (crypto_is_dead(alg))
37173d3864aSHerbert Xu 		goto complete;
37273d3864aSHerbert Xu 
373d6097b8dSNicolai Stange 	if (err == -ECANCELED)
374d6097b8dSNicolai Stange 		alg->cra_flags |= CRYPTO_ALG_FIPS_INTERNAL;
375d6097b8dSNicolai Stange 	else if (err)
376d6097b8dSNicolai Stange 		goto complete;
377d6097b8dSNicolai Stange 	else
378d6097b8dSNicolai Stange 		alg->cra_flags &= ~CRYPTO_ALG_FIPS_INTERNAL;
379d6097b8dSNicolai Stange 
38073d3864aSHerbert Xu 	alg->cra_flags |= CRYPTO_ALG_TESTED;
38173d3864aSHerbert Xu 
38296ad5955SHerbert Xu 	crypto_alg_finish_registration(alg, &list);
383cce9e06dSHerbert Xu 
38473d3864aSHerbert Xu complete:
38537da5d0fSHerbert Xu 	list_del_init(&test->alg.cra_list);
38673d3864aSHerbert Xu 	complete_all(&test->completion);
3872825982dSHerbert Xu 
38873d3864aSHerbert Xu 	up_write(&crypto_alg_sem);
3892825982dSHerbert Xu 
39037da5d0fSHerbert Xu 	crypto_alg_put(&test->alg);
39173d3864aSHerbert Xu 	crypto_remove_final(&list);
392cce9e06dSHerbert Xu }
39373d3864aSHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_tested);
3944cc7720cSHerbert Xu 
crypto_remove_final(struct list_head * list)39522e5b20bSSteffen Klassert void crypto_remove_final(struct list_head *list)
3966bfd4809SHerbert Xu {
3976bfd4809SHerbert Xu 	struct crypto_alg *alg;
3986bfd4809SHerbert Xu 	struct crypto_alg *n;
3996bfd4809SHerbert Xu 
4006bfd4809SHerbert Xu 	list_for_each_entry_safe(alg, n, list, cra_list) {
4016bfd4809SHerbert Xu 		list_del_init(&alg->cra_list);
4026bfd4809SHerbert Xu 		crypto_alg_put(alg);
4036bfd4809SHerbert Xu 	}
4046bfd4809SHerbert Xu }
40522e5b20bSSteffen Klassert EXPORT_SYMBOL_GPL(crypto_remove_final);
4066bfd4809SHerbert Xu 
crypto_register_alg(struct crypto_alg * alg)4074cc7720cSHerbert Xu int crypto_register_alg(struct crypto_alg *alg)
4084cc7720cSHerbert Xu {
40973d3864aSHerbert Xu 	struct crypto_larval *larval;
410b7685262SHerbert Xu 	bool test_started = false;
411a7008584SEric Biggers 	LIST_HEAD(algs_to_put);
4124cc7720cSHerbert Xu 	int err;
4134cc7720cSHerbert Xu 
414d6040764SSalvatore Benedetto 	alg->cra_flags &= ~CRYPTO_ALG_DEAD;
4154cc7720cSHerbert Xu 	err = crypto_check_alg(alg);
4164cc7720cSHerbert Xu 	if (err)
4174cc7720cSHerbert Xu 		return err;
4184cc7720cSHerbert Xu 
4194cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
420a7008584SEric Biggers 	larval = __crypto_register_alg(alg, &algs_to_put);
421a7008584SEric Biggers 	if (!IS_ERR_OR_NULL(larval)) {
422b7685262SHerbert Xu 		test_started = crypto_boot_test_finished();
423adad556eSHerbert Xu 		larval->test_started = test_started;
424a7008584SEric Biggers 	}
4254cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
4264cc7720cSHerbert Xu 
427a7008584SEric Biggers 	if (IS_ERR(larval))
42873d3864aSHerbert Xu 		return PTR_ERR(larval);
429b7685262SHerbert Xu 
430b7685262SHerbert Xu 	if (test_started)
431b7685262SHerbert Xu 		crypto_schedule_test(larval);
432b7685262SHerbert Xu 	else
433a7008584SEric Biggers 		crypto_remove_final(&algs_to_put);
434b7685262SHerbert Xu 
43573d3864aSHerbert Xu 	return 0;
4364cc7720cSHerbert Xu }
437cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_alg);
438cce9e06dSHerbert Xu 
crypto_remove_alg(struct crypto_alg * alg,struct list_head * list)4396bfd4809SHerbert Xu static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
4406bfd4809SHerbert Xu {
4416bfd4809SHerbert Xu 	if (unlikely(list_empty(&alg->cra_list)))
4426bfd4809SHerbert Xu 		return -ENOENT;
4436bfd4809SHerbert Xu 
4446bfd4809SHerbert Xu 	alg->cra_flags |= CRYPTO_ALG_DEAD;
4456bfd4809SHerbert Xu 
4466bfd4809SHerbert Xu 	list_del_init(&alg->cra_list);
4472bf29016SHerbert Xu 	crypto_remove_spawns(alg, list, NULL);
4486bfd4809SHerbert Xu 
4496bfd4809SHerbert Xu 	return 0;
4506bfd4809SHerbert Xu }
4516bfd4809SHerbert Xu 
crypto_unregister_alg(struct crypto_alg * alg)452c6d633a9SEric Biggers void crypto_unregister_alg(struct crypto_alg *alg)
453cce9e06dSHerbert Xu {
4546bfd4809SHerbert Xu 	int ret;
4556bfd4809SHerbert Xu 	LIST_HEAD(list);
456cce9e06dSHerbert Xu 
457cce9e06dSHerbert Xu 	down_write(&crypto_alg_sem);
4586bfd4809SHerbert Xu 	ret = crypto_remove_alg(alg, &list);
459cce9e06dSHerbert Xu 	up_write(&crypto_alg_sem);
460cce9e06dSHerbert Xu 
461c6d633a9SEric Biggers 	if (WARN(ret, "Algorithm %s is not registered", alg->cra_driver_name))
462c6d633a9SEric Biggers 		return;
463cce9e06dSHerbert Xu 
464a543ada7SToke Høiland-Jørgensen 	if (WARN_ON(refcount_read(&alg->cra_refcnt) != 1))
465a543ada7SToke Høiland-Jørgensen 		return;
466a543ada7SToke Høiland-Jørgensen 
467*27b13425SHerbert Xu 	crypto_alg_put(alg);
468cce9e06dSHerbert Xu 
4696bfd4809SHerbert Xu 	crypto_remove_final(&list);
470cce9e06dSHerbert Xu }
471cce9e06dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_alg);
472cce9e06dSHerbert Xu 
crypto_register_algs(struct crypto_alg * algs,int count)4734b004346SMark Brown int crypto_register_algs(struct crypto_alg *algs, int count)
4744b004346SMark Brown {
4754b004346SMark Brown 	int i, ret;
4764b004346SMark Brown 
4774b004346SMark Brown 	for (i = 0; i < count; i++) {
4784b004346SMark Brown 		ret = crypto_register_alg(&algs[i]);
4794b004346SMark Brown 		if (ret)
4804b004346SMark Brown 			goto err;
4814b004346SMark Brown 	}
4824b004346SMark Brown 
4834b004346SMark Brown 	return 0;
4844b004346SMark Brown 
4854b004346SMark Brown err:
4864b004346SMark Brown 	for (--i; i >= 0; --i)
4874b004346SMark Brown 		crypto_unregister_alg(&algs[i]);
4884b004346SMark Brown 
4894b004346SMark Brown 	return ret;
4904b004346SMark Brown }
4914b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_register_algs);
4924b004346SMark Brown 
crypto_unregister_algs(struct crypto_alg * algs,int count)493c6d633a9SEric Biggers void crypto_unregister_algs(struct crypto_alg *algs, int count)
4944b004346SMark Brown {
495c6d633a9SEric Biggers 	int i;
4964b004346SMark Brown 
497c6d633a9SEric Biggers 	for (i = 0; i < count; i++)
498c6d633a9SEric Biggers 		crypto_unregister_alg(&algs[i]);
4994b004346SMark Brown }
5004b004346SMark Brown EXPORT_SYMBOL_GPL(crypto_unregister_algs);
5014b004346SMark Brown 
crypto_register_template(struct crypto_template * tmpl)5024cc7720cSHerbert Xu int crypto_register_template(struct crypto_template *tmpl)
5034cc7720cSHerbert Xu {
5044cc7720cSHerbert Xu 	struct crypto_template *q;
5054cc7720cSHerbert Xu 	int err = -EEXIST;
5064cc7720cSHerbert Xu 
5074cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
5084cc7720cSHerbert Xu 
509002c77a4SJarod Wilson 	crypto_check_module_sig(tmpl->module);
510002c77a4SJarod Wilson 
5114cc7720cSHerbert Xu 	list_for_each_entry(q, &crypto_template_list, list) {
5124cc7720cSHerbert Xu 		if (q == tmpl)
5134cc7720cSHerbert Xu 			goto out;
5144cc7720cSHerbert Xu 	}
5154cc7720cSHerbert Xu 
5164cc7720cSHerbert Xu 	list_add(&tmpl->list, &crypto_template_list);
5174cc7720cSHerbert Xu 	err = 0;
5184cc7720cSHerbert Xu out:
5194cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
5204cc7720cSHerbert Xu 	return err;
5214cc7720cSHerbert Xu }
5224cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_template);
5234cc7720cSHerbert Xu 
crypto_register_templates(struct crypto_template * tmpls,int count)5249572442dSXiongfeng Wang int crypto_register_templates(struct crypto_template *tmpls, int count)
5259572442dSXiongfeng Wang {
5269572442dSXiongfeng Wang 	int i, err;
5279572442dSXiongfeng Wang 
5289572442dSXiongfeng Wang 	for (i = 0; i < count; i++) {
5299572442dSXiongfeng Wang 		err = crypto_register_template(&tmpls[i]);
5309572442dSXiongfeng Wang 		if (err)
5319572442dSXiongfeng Wang 			goto out;
5329572442dSXiongfeng Wang 	}
5339572442dSXiongfeng Wang 	return 0;
5349572442dSXiongfeng Wang 
5359572442dSXiongfeng Wang out:
5369572442dSXiongfeng Wang 	for (--i; i >= 0; --i)
5379572442dSXiongfeng Wang 		crypto_unregister_template(&tmpls[i]);
5389572442dSXiongfeng Wang 	return err;
5399572442dSXiongfeng Wang }
5409572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_register_templates);
5419572442dSXiongfeng Wang 
crypto_unregister_template(struct crypto_template * tmpl)5424cc7720cSHerbert Xu void crypto_unregister_template(struct crypto_template *tmpl)
5434cc7720cSHerbert Xu {
5444cc7720cSHerbert Xu 	struct crypto_instance *inst;
545b67bfe0dSSasha Levin 	struct hlist_node *n;
5464cc7720cSHerbert Xu 	struct hlist_head *list;
5476bfd4809SHerbert Xu 	LIST_HEAD(users);
5484cc7720cSHerbert Xu 
5494cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
5504cc7720cSHerbert Xu 
5514cc7720cSHerbert Xu 	BUG_ON(list_empty(&tmpl->list));
5524cc7720cSHerbert Xu 	list_del_init(&tmpl->list);
5534cc7720cSHerbert Xu 
5544cc7720cSHerbert Xu 	list = &tmpl->instances;
555b67bfe0dSSasha Levin 	hlist_for_each_entry(inst, list, list) {
5566bfd4809SHerbert Xu 		int err = crypto_remove_alg(&inst->alg, &users);
5570efcb8d5SJoshua I. James 
5586bfd4809SHerbert Xu 		BUG_ON(err);
5594cc7720cSHerbert Xu 	}
5604cc7720cSHerbert Xu 
5614cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
5624cc7720cSHerbert Xu 
563b67bfe0dSSasha Levin 	hlist_for_each_entry_safe(inst, n, list, list) {
564ce8614a3SEric Biggers 		BUG_ON(refcount_read(&inst->alg.cra_refcnt) != 1);
565319382a6SHerbert Xu 		crypto_free_instance(inst);
5664cc7720cSHerbert Xu 	}
5676bfd4809SHerbert Xu 	crypto_remove_final(&users);
5684cc7720cSHerbert Xu }
5694cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_template);
5704cc7720cSHerbert Xu 
crypto_unregister_templates(struct crypto_template * tmpls,int count)5719572442dSXiongfeng Wang void crypto_unregister_templates(struct crypto_template *tmpls, int count)
5729572442dSXiongfeng Wang {
5739572442dSXiongfeng Wang 	int i;
5749572442dSXiongfeng Wang 
5759572442dSXiongfeng Wang 	for (i = count - 1; i >= 0; --i)
5769572442dSXiongfeng Wang 		crypto_unregister_template(&tmpls[i]);
5779572442dSXiongfeng Wang }
5789572442dSXiongfeng Wang EXPORT_SYMBOL_GPL(crypto_unregister_templates);
5799572442dSXiongfeng Wang 
__crypto_lookup_template(const char * name)5804cc7720cSHerbert Xu static struct crypto_template *__crypto_lookup_template(const char *name)
5814cc7720cSHerbert Xu {
5824cc7720cSHerbert Xu 	struct crypto_template *q, *tmpl = NULL;
5834cc7720cSHerbert Xu 
5844cc7720cSHerbert Xu 	down_read(&crypto_alg_sem);
5854cc7720cSHerbert Xu 	list_for_each_entry(q, &crypto_template_list, list) {
5864cc7720cSHerbert Xu 		if (strcmp(q->name, name))
5874cc7720cSHerbert Xu 			continue;
5884cc7720cSHerbert Xu 		if (unlikely(!crypto_tmpl_get(q)))
5894cc7720cSHerbert Xu 			continue;
5904cc7720cSHerbert Xu 
5914cc7720cSHerbert Xu 		tmpl = q;
5924cc7720cSHerbert Xu 		break;
5934cc7720cSHerbert Xu 	}
5944cc7720cSHerbert Xu 	up_read(&crypto_alg_sem);
5954cc7720cSHerbert Xu 
5964cc7720cSHerbert Xu 	return tmpl;
5974cc7720cSHerbert Xu }
5984cc7720cSHerbert Xu 
crypto_lookup_template(const char * name)5994cc7720cSHerbert Xu struct crypto_template *crypto_lookup_template(const char *name)
6004cc7720cSHerbert Xu {
6014943ba16SKees Cook 	return try_then_request_module(__crypto_lookup_template(name),
6024943ba16SKees Cook 				       "crypto-%s", name);
6034cc7720cSHerbert Xu }
6044cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_lookup_template);
6054cc7720cSHerbert Xu 
crypto_register_instance(struct crypto_template * tmpl,struct crypto_instance * inst)6064cc7720cSHerbert Xu int crypto_register_instance(struct crypto_template *tmpl,
6074cc7720cSHerbert Xu 			     struct crypto_instance *inst)
6084cc7720cSHerbert Xu {
60973d3864aSHerbert Xu 	struct crypto_larval *larval;
6105f567fffSHerbert Xu 	struct crypto_spawn *spawn;
611d6097b8dSNicolai Stange 	u32 fips_internal = 0;
612a7008584SEric Biggers 	LIST_HEAD(algs_to_put);
61373d3864aSHerbert Xu 	int err;
6144cc7720cSHerbert Xu 
6154cc7720cSHerbert Xu 	err = crypto_check_alg(&inst->alg);
6164cc7720cSHerbert Xu 	if (err)
6179c521a20SStephan Mueller 		return err;
6189c521a20SStephan Mueller 
6194cc7720cSHerbert Xu 	inst->alg.cra_module = tmpl->module;
62064a947b1SSteffen Klassert 	inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE;
6214cc7720cSHerbert Xu 
6224cc7720cSHerbert Xu 	down_write(&crypto_alg_sem);
6234cc7720cSHerbert Xu 
6245f567fffSHerbert Xu 	larval = ERR_PTR(-EAGAIN);
6255f567fffSHerbert Xu 	for (spawn = inst->spawns; spawn;) {
6265f567fffSHerbert Xu 		struct crypto_spawn *next;
6275f567fffSHerbert Xu 
6285f567fffSHerbert Xu 		if (spawn->dead)
6295f567fffSHerbert Xu 			goto unlock;
6305f567fffSHerbert Xu 
6315f567fffSHerbert Xu 		next = spawn->next;
6325f567fffSHerbert Xu 		spawn->inst = inst;
6335f567fffSHerbert Xu 		spawn->registered = true;
6345f567fffSHerbert Xu 
635d6097b8dSNicolai Stange 		fips_internal |= spawn->alg->cra_flags;
636d6097b8dSNicolai Stange 
6375f567fffSHerbert Xu 		crypto_mod_put(spawn->alg);
6385f567fffSHerbert Xu 
6395f567fffSHerbert Xu 		spawn = next;
6405f567fffSHerbert Xu 	}
6415f567fffSHerbert Xu 
642d6097b8dSNicolai Stange 	inst->alg.cra_flags |= (fips_internal & CRYPTO_ALG_FIPS_INTERNAL);
643d6097b8dSNicolai Stange 
644a7008584SEric Biggers 	larval = __crypto_register_alg(&inst->alg, &algs_to_put);
64573d3864aSHerbert Xu 	if (IS_ERR(larval))
6464cc7720cSHerbert Xu 		goto unlock;
647b7685262SHerbert Xu 	else if (larval)
648adad556eSHerbert Xu 		larval->test_started = true;
649adad556eSHerbert Xu 
6504cc7720cSHerbert Xu 	hlist_add_head(&inst->list, &tmpl->instances);
6514cc7720cSHerbert Xu 	inst->tmpl = tmpl;
6524cc7720cSHerbert Xu 
6534cc7720cSHerbert Xu unlock:
6544cc7720cSHerbert Xu 	up_write(&crypto_alg_sem);
6554cc7720cSHerbert Xu 
656a7008584SEric Biggers 	if (IS_ERR(larval))
657a7008584SEric Biggers 		return PTR_ERR(larval);
658b7685262SHerbert Xu 
659b7685262SHerbert Xu 	if (larval)
660b7685262SHerbert Xu 		crypto_schedule_test(larval);
661b7685262SHerbert Xu 	else
662a7008584SEric Biggers 		crypto_remove_final(&algs_to_put);
663b7685262SHerbert Xu 
664a7008584SEric Biggers 	return 0;
6654cc7720cSHerbert Xu }
6664cc7720cSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_instance);
6674cc7720cSHerbert Xu 
crypto_unregister_instance(struct crypto_instance * inst)668c6d633a9SEric Biggers void crypto_unregister_instance(struct crypto_instance *inst)
669ce3fd840SSteffen Klassert {
6701f723710SHerbert Xu 	LIST_HEAD(list);
671ce3fd840SSteffen Klassert 
672ce3fd840SSteffen Klassert 	down_write(&crypto_alg_sem);
673ce3fd840SSteffen Klassert 
67487b16756SHerbert Xu 	crypto_remove_spawns(&inst->alg, &list, NULL);
6751f723710SHerbert Xu 	crypto_remove_instance(inst, &list);
676ce3fd840SSteffen Klassert 
677ce3fd840SSteffen Klassert 	up_write(&crypto_alg_sem);
678ce3fd840SSteffen Klassert 
6791f723710SHerbert Xu 	crypto_remove_final(&list);
680ce3fd840SSteffen Klassert }
681ce3fd840SSteffen Klassert EXPORT_SYMBOL_GPL(crypto_unregister_instance);
682ce3fd840SSteffen Klassert 
crypto_grab_spawn(struct crypto_spawn * spawn,struct crypto_instance * inst,const char * name,u32 type,u32 mask)683de95c957SEric Biggers int crypto_grab_spawn(struct crypto_spawn *spawn, struct crypto_instance *inst,
684de95c957SEric Biggers 		      const char *name, u32 type, u32 mask)
685d6ef2f19SHerbert Xu {
686d6ef2f19SHerbert Xu 	struct crypto_alg *alg;
687aed11cf5SEric Biggers 	int err = -EAGAIN;
688aed11cf5SEric Biggers 
689aed11cf5SEric Biggers 	if (WARN_ON_ONCE(inst == NULL))
690aed11cf5SEric Biggers 		return -EINVAL;
691d6ef2f19SHerbert Xu 
692ca94e937SEric Biggers 	/* Allow the result of crypto_attr_alg_name() to be passed directly */
693ca94e937SEric Biggers 	if (IS_ERR(name))
694ca94e937SEric Biggers 		return PTR_ERR(name);
695ca94e937SEric Biggers 
696d6097b8dSNicolai Stange 	alg = crypto_find_alg(name, spawn->frontend,
697d6097b8dSNicolai Stange 			      type | CRYPTO_ALG_FIPS_INTERNAL, mask);
698d6ef2f19SHerbert Xu 	if (IS_ERR(alg))
699d6ef2f19SHerbert Xu 		return PTR_ERR(alg);
700d6ef2f19SHerbert Xu 
701aed11cf5SEric Biggers 	down_write(&crypto_alg_sem);
702aed11cf5SEric Biggers 	if (!crypto_is_moribund(alg)) {
703aed11cf5SEric Biggers 		list_add(&spawn->list, &alg->cra_users);
704aed11cf5SEric Biggers 		spawn->alg = alg;
705aed11cf5SEric Biggers 		spawn->mask = mask;
706aed11cf5SEric Biggers 		spawn->next = inst->spawns;
707aed11cf5SEric Biggers 		inst->spawns = spawn;
7087bcb2c99SEric Biggers 		inst->alg.cra_flags |=
7097bcb2c99SEric Biggers 			(alg->cra_flags & CRYPTO_ALG_INHERITED_FLAGS);
710aed11cf5SEric Biggers 		err = 0;
711aed11cf5SEric Biggers 	}
712aed11cf5SEric Biggers 	up_write(&crypto_alg_sem);
7135f567fffSHerbert Xu 	if (err)
714d6ef2f19SHerbert Xu 		crypto_mod_put(alg);
715d6ef2f19SHerbert Xu 	return err;
716d6ef2f19SHerbert Xu }
717d6ef2f19SHerbert Xu EXPORT_SYMBOL_GPL(crypto_grab_spawn);
718d6ef2f19SHerbert Xu 
crypto_drop_spawn(struct crypto_spawn * spawn)7196bfd4809SHerbert Xu void crypto_drop_spawn(struct crypto_spawn *spawn)
7206bfd4809SHerbert Xu {
721ff670627SEric Biggers 	if (!spawn->alg) /* not yet initialized? */
722ff670627SEric Biggers 		return;
723ff670627SEric Biggers 
7246bfd4809SHerbert Xu 	down_write(&crypto_alg_sem);
7254f87ee11SHerbert Xu 	if (!spawn->dead)
7266bfd4809SHerbert Xu 		list_del(&spawn->list);
7276bfd4809SHerbert Xu 	up_write(&crypto_alg_sem);
7285f567fffSHerbert Xu 
729aed11cf5SEric Biggers 	if (!spawn->registered)
7305f567fffSHerbert Xu 		crypto_mod_put(spawn->alg);
7316bfd4809SHerbert Xu }
7326bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_drop_spawn);
7336bfd4809SHerbert Xu 
crypto_spawn_alg(struct crypto_spawn * spawn)73497eedce1SHerbert Xu static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
7356bfd4809SHerbert Xu {
7366603523bSHerbert Xu 	struct crypto_alg *alg = ERR_PTR(-EAGAIN);
7376603523bSHerbert Xu 	struct crypto_alg *target;
7386603523bSHerbert Xu 	bool shoot = false;
7396bfd4809SHerbert Xu 
7406bfd4809SHerbert Xu 	down_read(&crypto_alg_sem);
7416603523bSHerbert Xu 	if (!spawn->dead) {
7426bfd4809SHerbert Xu 		alg = spawn->alg;
7436603523bSHerbert Xu 		if (!crypto_mod_get(alg)) {
7446603523bSHerbert Xu 			target = crypto_alg_get(alg);
7456603523bSHerbert Xu 			shoot = true;
7466603523bSHerbert Xu 			alg = ERR_PTR(-EAGAIN);
7476603523bSHerbert Xu 		}
74873669cc5SHerbert Xu 	}
7496bfd4809SHerbert Xu 	up_read(&crypto_alg_sem);
7506bfd4809SHerbert Xu 
7516603523bSHerbert Xu 	if (shoot) {
7526603523bSHerbert Xu 		crypto_shoot_alg(target);
7536603523bSHerbert Xu 		crypto_alg_put(target);
7546603523bSHerbert Xu 	}
7556603523bSHerbert Xu 
7566603523bSHerbert Xu 	return alg;
75797eedce1SHerbert Xu }
75897eedce1SHerbert Xu 
crypto_spawn_tfm(struct crypto_spawn * spawn,u32 type,u32 mask)75997eedce1SHerbert Xu struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
76097eedce1SHerbert Xu 				    u32 mask)
76197eedce1SHerbert Xu {
76297eedce1SHerbert Xu 	struct crypto_alg *alg;
76397eedce1SHerbert Xu 	struct crypto_tfm *tfm;
76497eedce1SHerbert Xu 
76597eedce1SHerbert Xu 	alg = crypto_spawn_alg(spawn);
76697eedce1SHerbert Xu 	if (IS_ERR(alg))
76797eedce1SHerbert Xu 		return ERR_CAST(alg);
76897eedce1SHerbert Xu 
7692e306ee0SHerbert Xu 	tfm = ERR_PTR(-EINVAL);
7702e306ee0SHerbert Xu 	if (unlikely((alg->cra_flags ^ type) & mask))
7712e306ee0SHerbert Xu 		goto out_put_alg;
7722e306ee0SHerbert Xu 
77327d2a330SHerbert Xu 	tfm = __crypto_alloc_tfm(alg, type, mask);
7746bfd4809SHerbert Xu 	if (IS_ERR(tfm))
7752e306ee0SHerbert Xu 		goto out_put_alg;
7766bfd4809SHerbert Xu 
7776bfd4809SHerbert Xu 	return tfm;
7782e306ee0SHerbert Xu 
7792e306ee0SHerbert Xu out_put_alg:
7802e306ee0SHerbert Xu 	crypto_mod_put(alg);
7812e306ee0SHerbert Xu 	return tfm;
7826bfd4809SHerbert Xu }
7836bfd4809SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
7846bfd4809SHerbert Xu 
crypto_spawn_tfm2(struct crypto_spawn * spawn)78597eedce1SHerbert Xu void *crypto_spawn_tfm2(struct crypto_spawn *spawn)
78697eedce1SHerbert Xu {
78797eedce1SHerbert Xu 	struct crypto_alg *alg;
78897eedce1SHerbert Xu 	struct crypto_tfm *tfm;
78997eedce1SHerbert Xu 
79097eedce1SHerbert Xu 	alg = crypto_spawn_alg(spawn);
79197eedce1SHerbert Xu 	if (IS_ERR(alg))
79297eedce1SHerbert Xu 		return ERR_CAST(alg);
79397eedce1SHerbert Xu 
79497eedce1SHerbert Xu 	tfm = crypto_create_tfm(alg, spawn->frontend);
79597eedce1SHerbert Xu 	if (IS_ERR(tfm))
79697eedce1SHerbert Xu 		goto out_put_alg;
79797eedce1SHerbert Xu 
79897eedce1SHerbert Xu 	return tfm;
79997eedce1SHerbert Xu 
80097eedce1SHerbert Xu out_put_alg:
80197eedce1SHerbert Xu 	crypto_mod_put(alg);
80297eedce1SHerbert Xu 	return tfm;
80397eedce1SHerbert Xu }
80497eedce1SHerbert Xu EXPORT_SYMBOL_GPL(crypto_spawn_tfm2);
80597eedce1SHerbert Xu 
crypto_register_notifier(struct notifier_block * nb)8062825982dSHerbert Xu int crypto_register_notifier(struct notifier_block *nb)
8072825982dSHerbert Xu {
8082825982dSHerbert Xu 	return blocking_notifier_chain_register(&crypto_chain, nb);
8092825982dSHerbert Xu }
8102825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_register_notifier);
8112825982dSHerbert Xu 
crypto_unregister_notifier(struct notifier_block * nb)8122825982dSHerbert Xu int crypto_unregister_notifier(struct notifier_block *nb)
8132825982dSHerbert Xu {
8142825982dSHerbert Xu 	return blocking_notifier_chain_unregister(&crypto_chain, nb);
8152825982dSHerbert Xu }
8162825982dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
8172825982dSHerbert Xu 
crypto_get_attr_type(struct rtattr ** tb)818ebc610e5SHerbert Xu struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
8197fed0bf2SHerbert Xu {
82039e1ee01SHerbert Xu 	struct rtattr *rta = tb[0];
821ebc610e5SHerbert Xu 	struct crypto_attr_type *algt;
822ebc610e5SHerbert Xu 
823ebc610e5SHerbert Xu 	if (!rta)
824ebc610e5SHerbert Xu 		return ERR_PTR(-ENOENT);
825ebc610e5SHerbert Xu 	if (RTA_PAYLOAD(rta) < sizeof(*algt))
826ebc610e5SHerbert Xu 		return ERR_PTR(-EINVAL);
82739e1ee01SHerbert Xu 	if (rta->rta_type != CRYPTOA_TYPE)
82839e1ee01SHerbert Xu 		return ERR_PTR(-EINVAL);
829ebc610e5SHerbert Xu 
830ebc610e5SHerbert Xu 	algt = RTA_DATA(rta);
831ebc610e5SHerbert Xu 
832ebc610e5SHerbert Xu 	return algt;
833ebc610e5SHerbert Xu }
834ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_get_attr_type);
835ebc610e5SHerbert Xu 
8367bcb2c99SEric Biggers /**
8377bcb2c99SEric Biggers  * crypto_check_attr_type() - check algorithm type and compute inherited mask
8387bcb2c99SEric Biggers  * @tb: the template parameters
8397bcb2c99SEric Biggers  * @type: the algorithm type the template would be instantiated as
8407bcb2c99SEric Biggers  * @mask_ret: (output) the mask that should be passed to crypto_grab_*()
8417bcb2c99SEric Biggers  *	      to restrict the flags of any inner algorithms
8427bcb2c99SEric Biggers  *
8437bcb2c99SEric Biggers  * Validate that the algorithm type the user requested is compatible with the
8447bcb2c99SEric Biggers  * one the template would actually be instantiated as.  E.g., if the user is
8457bcb2c99SEric Biggers  * doing crypto_alloc_shash("cbc(aes)", ...), this would return an error because
8467bcb2c99SEric Biggers  * the "cbc" template creates an "skcipher" algorithm, not an "shash" algorithm.
8477bcb2c99SEric Biggers  *
8487bcb2c99SEric Biggers  * Also compute the mask to use to restrict the flags of any inner algorithms.
8497bcb2c99SEric Biggers  *
8507bcb2c99SEric Biggers  * Return: 0 on success; -errno on failure
8517bcb2c99SEric Biggers  */
crypto_check_attr_type(struct rtattr ** tb,u32 type,u32 * mask_ret)8527bcb2c99SEric Biggers int crypto_check_attr_type(struct rtattr **tb, u32 type, u32 *mask_ret)
853ebc610e5SHerbert Xu {
854ebc610e5SHerbert Xu 	struct crypto_attr_type *algt;
855ebc610e5SHerbert Xu 
856ebc610e5SHerbert Xu 	algt = crypto_get_attr_type(tb);
857ebc610e5SHerbert Xu 	if (IS_ERR(algt))
858ebc610e5SHerbert Xu 		return PTR_ERR(algt);
859ebc610e5SHerbert Xu 
860ebc610e5SHerbert Xu 	if ((algt->type ^ type) & algt->mask)
861ebc610e5SHerbert Xu 		return -EINVAL;
862ebc610e5SHerbert Xu 
8637bcb2c99SEric Biggers 	*mask_ret = crypto_algt_inherited_mask(algt);
864ebc610e5SHerbert Xu 	return 0;
865ebc610e5SHerbert Xu }
866ebc610e5SHerbert Xu EXPORT_SYMBOL_GPL(crypto_check_attr_type);
867ebc610e5SHerbert Xu 
crypto_attr_alg_name(struct rtattr * rta)86868b6c7d6SHerbert Xu const char *crypto_attr_alg_name(struct rtattr *rta)
869ebc610e5SHerbert Xu {
8707fed0bf2SHerbert Xu 	struct crypto_attr_alg *alga;
8717fed0bf2SHerbert Xu 
872ebc610e5SHerbert Xu 	if (!rta)
873ebc610e5SHerbert Xu 		return ERR_PTR(-ENOENT);
874ebc610e5SHerbert Xu 	if (RTA_PAYLOAD(rta) < sizeof(*alga))
8757fed0bf2SHerbert Xu 		return ERR_PTR(-EINVAL);
87639e1ee01SHerbert Xu 	if (rta->rta_type != CRYPTOA_ALG)
87739e1ee01SHerbert Xu 		return ERR_PTR(-EINVAL);
8787fed0bf2SHerbert Xu 
8797fed0bf2SHerbert Xu 	alga = RTA_DATA(rta);
8807fed0bf2SHerbert Xu 	alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
8817fed0bf2SHerbert Xu 
88268b6c7d6SHerbert Xu 	return alga->name;
88368b6c7d6SHerbert Xu }
88468b6c7d6SHerbert Xu EXPORT_SYMBOL_GPL(crypto_attr_alg_name);
88568b6c7d6SHerbert Xu 
crypto_inst_setname(struct crypto_instance * inst,const char * name,struct crypto_alg * alg)88632f27c74SHerbert Xu int crypto_inst_setname(struct crypto_instance *inst, const char *name,
88732f27c74SHerbert Xu 			struct crypto_alg *alg)
88832f27c74SHerbert Xu {
88932f27c74SHerbert Xu 	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
89032f27c74SHerbert Xu 		     alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
89132f27c74SHerbert Xu 		return -ENAMETOOLONG;
89232f27c74SHerbert Xu 
89332f27c74SHerbert Xu 	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
89432f27c74SHerbert Xu 		     name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
89532f27c74SHerbert Xu 		return -ENAMETOOLONG;
89632f27c74SHerbert Xu 
89732f27c74SHerbert Xu 	return 0;
89832f27c74SHerbert Xu }
89932f27c74SHerbert Xu EXPORT_SYMBOL_GPL(crypto_inst_setname);
90032f27c74SHerbert Xu 
crypto_init_queue(struct crypto_queue * queue,unsigned int max_qlen)901b5b7f088SHerbert Xu void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
902b5b7f088SHerbert Xu {
903b5b7f088SHerbert Xu 	INIT_LIST_HEAD(&queue->list);
904b5b7f088SHerbert Xu 	queue->backlog = &queue->list;
905b5b7f088SHerbert Xu 	queue->qlen = 0;
906b5b7f088SHerbert Xu 	queue->max_qlen = max_qlen;
907b5b7f088SHerbert Xu }
908b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_init_queue);
909b5b7f088SHerbert Xu 
crypto_enqueue_request(struct crypto_queue * queue,struct crypto_async_request * request)910b5b7f088SHerbert Xu int crypto_enqueue_request(struct crypto_queue *queue,
911b5b7f088SHerbert Xu 			   struct crypto_async_request *request)
912b5b7f088SHerbert Xu {
913b5b7f088SHerbert Xu 	int err = -EINPROGRESS;
914b5b7f088SHerbert Xu 
915b5b7f088SHerbert Xu 	if (unlikely(queue->qlen >= queue->max_qlen)) {
9166b80ea38SGilad Ben-Yossef 		if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
9176b80ea38SGilad Ben-Yossef 			err = -ENOSPC;
918b5b7f088SHerbert Xu 			goto out;
9196b80ea38SGilad Ben-Yossef 		}
9206b80ea38SGilad Ben-Yossef 		err = -EBUSY;
921b5b7f088SHerbert Xu 		if (queue->backlog == &queue->list)
922b5b7f088SHerbert Xu 			queue->backlog = &request->list;
923b5b7f088SHerbert Xu 	}
924b5b7f088SHerbert Xu 
925b5b7f088SHerbert Xu 	queue->qlen++;
926b5b7f088SHerbert Xu 	list_add_tail(&request->list, &queue->list);
927b5b7f088SHerbert Xu 
928b5b7f088SHerbert Xu out:
929b5b7f088SHerbert Xu 	return err;
930b5b7f088SHerbert Xu }
931b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_enqueue_request);
932b5b7f088SHerbert Xu 
crypto_enqueue_request_head(struct crypto_queue * queue,struct crypto_async_request * request)933ec6e2bf3SIuliana Prodan void crypto_enqueue_request_head(struct crypto_queue *queue,
934ec6e2bf3SIuliana Prodan 				 struct crypto_async_request *request)
935ec6e2bf3SIuliana Prodan {
9364140aafcSOlivier Bacon 	if (unlikely(queue->qlen >= queue->max_qlen))
9374140aafcSOlivier Bacon 		queue->backlog = queue->backlog->prev;
9384140aafcSOlivier Bacon 
939ec6e2bf3SIuliana Prodan 	queue->qlen++;
940ec6e2bf3SIuliana Prodan 	list_add(&request->list, &queue->list);
941ec6e2bf3SIuliana Prodan }
942ec6e2bf3SIuliana Prodan EXPORT_SYMBOL_GPL(crypto_enqueue_request_head);
943ec6e2bf3SIuliana Prodan 
crypto_dequeue_request(struct crypto_queue * queue)94431d228ccSHerbert Xu struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
945b5b7f088SHerbert Xu {
946b5b7f088SHerbert Xu 	struct list_head *request;
947b5b7f088SHerbert Xu 
948b5b7f088SHerbert Xu 	if (unlikely(!queue->qlen))
949b5b7f088SHerbert Xu 		return NULL;
950b5b7f088SHerbert Xu 
951b5b7f088SHerbert Xu 	queue->qlen--;
952b5b7f088SHerbert Xu 
953b5b7f088SHerbert Xu 	if (queue->backlog != &queue->list)
954b5b7f088SHerbert Xu 		queue->backlog = queue->backlog->next;
955b5b7f088SHerbert Xu 
956b5b7f088SHerbert Xu 	request = queue->list.next;
957f2ffe5a9SHerbert Xu 	list_del_init(request);
958b5b7f088SHerbert Xu 
95931d228ccSHerbert Xu 	return list_entry(request, struct crypto_async_request, list);
960b5b7f088SHerbert Xu }
961b5b7f088SHerbert Xu EXPORT_SYMBOL_GPL(crypto_dequeue_request);
962b5b7f088SHerbert Xu 
crypto_inc_byte(u8 * a,unsigned int size)9637613636dSHerbert Xu static inline void crypto_inc_byte(u8 *a, unsigned int size)
9647613636dSHerbert Xu {
9657613636dSHerbert Xu 	u8 *b = (a + size);
9667613636dSHerbert Xu 	u8 c;
9677613636dSHerbert Xu 
9687613636dSHerbert Xu 	for (; size; size--) {
9697613636dSHerbert Xu 		c = *--b + 1;
9707613636dSHerbert Xu 		*b = c;
9717613636dSHerbert Xu 		if (c)
9727613636dSHerbert Xu 			break;
9737613636dSHerbert Xu 	}
9747613636dSHerbert Xu }
9757613636dSHerbert Xu 
crypto_inc(u8 * a,unsigned int size)9767613636dSHerbert Xu void crypto_inc(u8 *a, unsigned int size)
9777613636dSHerbert Xu {
9787613636dSHerbert Xu 	__be32 *b = (__be32 *)(a + size);
9797613636dSHerbert Xu 	u32 c;
9807613636dSHerbert Xu 
981db91af0fSArd Biesheuvel 	if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) ||
98227c539aeSArd Biesheuvel 	    IS_ALIGNED((unsigned long)b, __alignof__(*b)))
9837613636dSHerbert Xu 		for (; size >= 4; size -= 4) {
9847613636dSHerbert Xu 			c = be32_to_cpu(*--b) + 1;
9857613636dSHerbert Xu 			*b = cpu_to_be32(c);
98627c539aeSArd Biesheuvel 			if (likely(c))
9877613636dSHerbert Xu 				return;
9887613636dSHerbert Xu 		}
9897613636dSHerbert Xu 
9907613636dSHerbert Xu 	crypto_inc_byte(a, size);
9917613636dSHerbert Xu }
9927613636dSHerbert Xu EXPORT_SYMBOL_GPL(crypto_inc);
9937613636dSHerbert Xu 
crypto_alg_extsize(struct crypto_alg * alg)99438d21433SHerbert Xu unsigned int crypto_alg_extsize(struct crypto_alg *alg)
99538d21433SHerbert Xu {
996c2110f28SHerbert Xu 	return alg->cra_ctxsize +
997c2110f28SHerbert Xu 	       (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
99838d21433SHerbert Xu }
99938d21433SHerbert Xu EXPORT_SYMBOL_GPL(crypto_alg_extsize);
100038d21433SHerbert Xu 
crypto_type_has_alg(const char * name,const struct crypto_type * frontend,u32 type,u32 mask)1001f2aefdabSHerbert Xu int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
1002f2aefdabSHerbert Xu 			u32 type, u32 mask)
1003f2aefdabSHerbert Xu {
1004f2aefdabSHerbert Xu 	int ret = 0;
1005f2aefdabSHerbert Xu 	struct crypto_alg *alg = crypto_find_alg(name, frontend, type, mask);
1006f2aefdabSHerbert Xu 
1007f2aefdabSHerbert Xu 	if (!IS_ERR(alg)) {
1008f2aefdabSHerbert Xu 		crypto_mod_put(alg);
1009f2aefdabSHerbert Xu 		ret = 1;
1010f2aefdabSHerbert Xu 	}
1011f2aefdabSHerbert Xu 
1012f2aefdabSHerbert Xu 	return ret;
1013f2aefdabSHerbert Xu }
1014f2aefdabSHerbert Xu EXPORT_SYMBOL_GPL(crypto_type_has_alg);
1015f2aefdabSHerbert Xu 
crypto_start_tests(void)1016adad556eSHerbert Xu static void __init crypto_start_tests(void)
1017adad556eSHerbert Xu {
1018f9110822SHerbert Xu 	if (!IS_BUILTIN(CONFIG_CRYPTO_ALGAPI))
1019f9110822SHerbert Xu 		return;
1020f9110822SHerbert Xu 
102106bd9c96SEric Biggers 	if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS))
102206bd9c96SEric Biggers 		return;
102306bd9c96SEric Biggers 
10248dd458cbSHerbert Xu 	set_crypto_boot_test_finished();
10258dd458cbSHerbert Xu 
1026adad556eSHerbert Xu 	for (;;) {
1027adad556eSHerbert Xu 		struct crypto_larval *larval = NULL;
1028adad556eSHerbert Xu 		struct crypto_alg *q;
1029adad556eSHerbert Xu 
1030adad556eSHerbert Xu 		down_write(&crypto_alg_sem);
1031adad556eSHerbert Xu 
1032adad556eSHerbert Xu 		list_for_each_entry(q, &crypto_alg_list, cra_list) {
1033adad556eSHerbert Xu 			struct crypto_larval *l;
1034adad556eSHerbert Xu 
1035adad556eSHerbert Xu 			if (!crypto_is_larval(q))
1036adad556eSHerbert Xu 				continue;
1037adad556eSHerbert Xu 
1038adad556eSHerbert Xu 			l = (void *)q;
1039adad556eSHerbert Xu 
1040adad556eSHerbert Xu 			if (!crypto_is_test_larval(l))
1041adad556eSHerbert Xu 				continue;
1042adad556eSHerbert Xu 
1043adad556eSHerbert Xu 			if (l->test_started)
1044adad556eSHerbert Xu 				continue;
1045adad556eSHerbert Xu 
1046adad556eSHerbert Xu 			l->test_started = true;
1047adad556eSHerbert Xu 			larval = l;
1048adad556eSHerbert Xu 			break;
1049adad556eSHerbert Xu 		}
1050adad556eSHerbert Xu 
1051adad556eSHerbert Xu 		up_write(&crypto_alg_sem);
1052adad556eSHerbert Xu 
1053adad556eSHerbert Xu 		if (!larval)
1054adad556eSHerbert Xu 			break;
1055b7685262SHerbert Xu 
1056b7685262SHerbert Xu 		crypto_schedule_test(larval);
1057adad556eSHerbert Xu 	}
1058adad556eSHerbert Xu }
1059adad556eSHerbert Xu 
crypto_algapi_init(void)1060cce9e06dSHerbert Xu static int __init crypto_algapi_init(void)
1061cce9e06dSHerbert Xu {
1062cce9e06dSHerbert Xu 	crypto_init_proc();
1063adad556eSHerbert Xu 	crypto_start_tests();
1064cce9e06dSHerbert Xu 	return 0;
1065cce9e06dSHerbert Xu }
1066cce9e06dSHerbert Xu 
crypto_algapi_exit(void)1067cce9e06dSHerbert Xu static void __exit crypto_algapi_exit(void)
1068cce9e06dSHerbert Xu {
1069cce9e06dSHerbert Xu 	crypto_exit_proc();
1070cce9e06dSHerbert Xu }
1071cce9e06dSHerbert Xu 
1072adad556eSHerbert Xu /*
1073adad556eSHerbert Xu  * We run this at late_initcall so that all the built-in algorithms
1074adad556eSHerbert Xu  * have had a chance to register themselves first.
1075adad556eSHerbert Xu  */
1076adad556eSHerbert Xu late_initcall(crypto_algapi_init);
1077cce9e06dSHerbert Xu module_exit(crypto_algapi_exit);
1078cce9e06dSHerbert Xu 
1079cce9e06dSHerbert Xu MODULE_LICENSE("GPL");
1080cce9e06dSHerbert Xu MODULE_DESCRIPTION("Cryptographic algorithms API");
1081c6ce9c58SHerbert Xu MODULE_SOFTDEP("pre: cryptomgr");
1082