forked from mirrors/linux
		
	[CRYPTO] api: Added spawns
Spawns lock a specific crypto algorithm in place. They can then be used with crypto_spawn_tfm to allocate a tfm for that algorithm. When the base algorithm of a spawn is deregistered, all its spawns will be automatically removed. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									492e2b63eb
								
							
						
					
					
						commit
						6bfd48096f
					
				
					 6 changed files with 280 additions and 53 deletions
				
			
		
							
								
								
									
										185
									
								
								crypto/algapi.c
									
									
									
									
									
								
							
							
						
						
									
										185
									
								
								crypto/algapi.c
									
									
									
									
									
								
							|  | @ -10,6 +10,7 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <linux/err.h> | ||||||
| #include <linux/errno.h> | #include <linux/errno.h> | ||||||
| #include <linux/init.h> | #include <linux/init.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
|  | @ -73,27 +74,96 @@ static int crypto_check_alg(struct crypto_alg *alg) | ||||||
| 	return crypto_set_driver_name(alg); | 	return crypto_set_driver_name(alg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int __crypto_register_alg(struct crypto_alg *alg) | static void crypto_destroy_instance(struct crypto_alg *alg) | ||||||
|  | { | ||||||
|  | 	struct crypto_instance *inst = (void *)alg; | ||||||
|  | 	struct crypto_template *tmpl = inst->tmpl; | ||||||
|  | 
 | ||||||
|  | 	tmpl->free(inst); | ||||||
|  | 	crypto_tmpl_put(tmpl); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void crypto_remove_spawns(struct list_head *spawns, | ||||||
|  | 				 struct list_head *list) | ||||||
|  | { | ||||||
|  | 	struct crypto_spawn *spawn, *n; | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(spawn, n, spawns, list) { | ||||||
|  | 		struct crypto_instance *inst = spawn->inst; | ||||||
|  | 		struct crypto_template *tmpl = inst->tmpl; | ||||||
|  | 
 | ||||||
|  | 		list_del_init(&spawn->list); | ||||||
|  | 		spawn->alg = NULL; | ||||||
|  | 
 | ||||||
|  | 		if (crypto_is_dead(&inst->alg)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		inst->alg.cra_flags |= CRYPTO_ALG_DEAD; | ||||||
|  | 		if (!tmpl || !crypto_tmpl_get(tmpl)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); | ||||||
|  | 		list_move(&inst->alg.cra_list, list); | ||||||
|  | 		hlist_del(&inst->list); | ||||||
|  | 		inst->alg.cra_destroy = crypto_destroy_instance; | ||||||
|  | 
 | ||||||
|  | 		if (!list_empty(&inst->alg.cra_users)) { | ||||||
|  | 			if (&n->list == spawns) | ||||||
|  | 				n = list_entry(inst->alg.cra_users.next, | ||||||
|  | 					       typeof(*n), list); | ||||||
|  | 			__list_splice(&inst->alg.cra_users, spawns->prev); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int __crypto_register_alg(struct crypto_alg *alg, | ||||||
|  | 				 struct list_head *list) | ||||||
| { | { | ||||||
| 	struct crypto_alg *q; | 	struct crypto_alg *q; | ||||||
| 	int ret = -EEXIST; | 	int ret = -EAGAIN; | ||||||
|  | 
 | ||||||
|  | 	if (crypto_is_dead(alg)) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	INIT_LIST_HEAD(&alg->cra_users); | ||||||
|  | 
 | ||||||
|  | 	ret = -EEXIST; | ||||||
| 
 | 
 | ||||||
| 	atomic_set(&alg->cra_refcnt, 1); | 	atomic_set(&alg->cra_refcnt, 1); | ||||||
| 	list_for_each_entry(q, &crypto_alg_list, cra_list) { | 	list_for_each_entry(q, &crypto_alg_list, cra_list) { | ||||||
| 		if (q == alg) | 		if (q == alg) | ||||||
| 			goto out; | 			goto out; | ||||||
| 		if (crypto_is_larval(q) && | 
 | ||||||
| 		    (!strcmp(alg->cra_name, q->cra_name) || | 		if (crypto_is_moribund(q)) | ||||||
| 		     !strcmp(alg->cra_driver_name, q->cra_name))) { | 			continue; | ||||||
|  | 
 | ||||||
|  | 		if (crypto_is_larval(q)) { | ||||||
| 			struct crypto_larval *larval = (void *)q; | 			struct crypto_larval *larval = (void *)q; | ||||||
| 
 | 
 | ||||||
|  | 			if (strcmp(alg->cra_name, q->cra_name) && | ||||||
|  | 			    strcmp(alg->cra_driver_name, q->cra_name)) | ||||||
|  | 				continue; | ||||||
|  | 
 | ||||||
|  | 			if (larval->adult) | ||||||
|  | 				continue; | ||||||
| 			if ((q->cra_flags ^ alg->cra_flags) & larval->mask) | 			if ((q->cra_flags ^ alg->cra_flags) & larval->mask) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (!crypto_mod_get(alg)) | 			if (!crypto_mod_get(alg)) | ||||||
| 				continue; | 				continue; | ||||||
|  | 
 | ||||||
| 			larval->adult = alg; | 			larval->adult = alg; | ||||||
| 			complete(&larval->completion); | 			complete(&larval->completion); | ||||||
|  | 			continue; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		if (strcmp(alg->cra_name, q->cra_name)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		if (strcmp(alg->cra_driver_name, q->cra_driver_name) && | ||||||
|  | 		    q->cra_priority > alg->cra_priority) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		crypto_remove_spawns(&q->cra_users, list); | ||||||
| 	} | 	} | ||||||
| 	 | 	 | ||||||
| 	list_add(&alg->cra_list, &crypto_alg_list); | 	list_add(&alg->cra_list, &crypto_alg_list); | ||||||
|  | @ -105,8 +175,20 @@ static int __crypto_register_alg(struct crypto_alg *alg) | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void crypto_remove_final(struct list_head *list) | ||||||
|  | { | ||||||
|  | 	struct crypto_alg *alg; | ||||||
|  | 	struct crypto_alg *n; | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(alg, n, list, cra_list) { | ||||||
|  | 		list_del_init(&alg->cra_list); | ||||||
|  | 		crypto_alg_put(alg); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int crypto_register_alg(struct crypto_alg *alg) | int crypto_register_alg(struct crypto_alg *alg) | ||||||
| { | { | ||||||
|  | 	LIST_HEAD(list); | ||||||
| 	int err; | 	int err; | ||||||
| 
 | 
 | ||||||
| 	err = crypto_check_alg(alg); | 	err = crypto_check_alg(alg); | ||||||
|  | @ -114,23 +196,35 @@ int crypto_register_alg(struct crypto_alg *alg) | ||||||
| 		return err; | 		return err; | ||||||
| 
 | 
 | ||||||
| 	down_write(&crypto_alg_sem); | 	down_write(&crypto_alg_sem); | ||||||
| 	err = __crypto_register_alg(alg); | 	err = __crypto_register_alg(alg, &list); | ||||||
| 	up_write(&crypto_alg_sem); | 	up_write(&crypto_alg_sem); | ||||||
| 
 | 
 | ||||||
|  | 	crypto_remove_final(&list); | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(crypto_register_alg); | EXPORT_SYMBOL_GPL(crypto_register_alg); | ||||||
| 
 | 
 | ||||||
|  | static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list) | ||||||
|  | { | ||||||
|  | 	if (unlikely(list_empty(&alg->cra_list))) | ||||||
|  | 		return -ENOENT; | ||||||
|  | 
 | ||||||
|  | 	alg->cra_flags |= CRYPTO_ALG_DEAD; | ||||||
|  | 
 | ||||||
|  | 	crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); | ||||||
|  | 	list_del_init(&alg->cra_list); | ||||||
|  | 	crypto_remove_spawns(&alg->cra_users, list); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int crypto_unregister_alg(struct crypto_alg *alg) | int crypto_unregister_alg(struct crypto_alg *alg) | ||||||
| { | { | ||||||
| 	int ret = -ENOENT; | 	int ret; | ||||||
|  | 	LIST_HEAD(list); | ||||||
| 	 | 	 | ||||||
| 	down_write(&crypto_alg_sem); | 	down_write(&crypto_alg_sem); | ||||||
| 	if (likely(!list_empty(&alg->cra_list))) { | 	ret = crypto_remove_alg(alg, &list); | ||||||
| 		list_del_init(&alg->cra_list); |  | ||||||
| 		ret = 0; |  | ||||||
| 	} |  | ||||||
| 	crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); |  | ||||||
| 	up_write(&crypto_alg_sem); | 	up_write(&crypto_alg_sem); | ||||||
| 
 | 
 | ||||||
| 	if (ret) | 	if (ret) | ||||||
|  | @ -140,6 +234,7 @@ int crypto_unregister_alg(struct crypto_alg *alg) | ||||||
| 	if (alg->cra_destroy) | 	if (alg->cra_destroy) | ||||||
| 		alg->cra_destroy(alg); | 		alg->cra_destroy(alg); | ||||||
| 
 | 
 | ||||||
|  | 	crypto_remove_final(&list); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(crypto_unregister_alg); | EXPORT_SYMBOL_GPL(crypto_unregister_alg); | ||||||
|  | @ -170,6 +265,7 @@ void crypto_unregister_template(struct crypto_template *tmpl) | ||||||
| 	struct crypto_instance *inst; | 	struct crypto_instance *inst; | ||||||
| 	struct hlist_node *p, *n; | 	struct hlist_node *p, *n; | ||||||
| 	struct hlist_head *list; | 	struct hlist_head *list; | ||||||
|  | 	LIST_HEAD(users); | ||||||
| 
 | 
 | ||||||
| 	down_write(&crypto_alg_sem); | 	down_write(&crypto_alg_sem); | ||||||
| 
 | 
 | ||||||
|  | @ -178,9 +274,8 @@ void crypto_unregister_template(struct crypto_template *tmpl) | ||||||
| 
 | 
 | ||||||
| 	list = &tmpl->instances; | 	list = &tmpl->instances; | ||||||
| 	hlist_for_each_entry(inst, p, list, list) { | 	hlist_for_each_entry(inst, p, list, list) { | ||||||
| 		BUG_ON(list_empty(&inst->alg.cra_list)); | 		int err = crypto_remove_alg(&inst->alg, &users); | ||||||
| 		list_del_init(&inst->alg.cra_list); | 		BUG_ON(err); | ||||||
| 		crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl); | 	crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl); | ||||||
|  | @ -191,6 +286,7 @@ void crypto_unregister_template(struct crypto_template *tmpl) | ||||||
| 		BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1); | 		BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1); | ||||||
| 		tmpl->free(inst); | 		tmpl->free(inst); | ||||||
| 	} | 	} | ||||||
|  | 	crypto_remove_final(&users); | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(crypto_unregister_template); | EXPORT_SYMBOL_GPL(crypto_unregister_template); | ||||||
| 
 | 
 | ||||||
|  | @ -222,6 +318,7 @@ EXPORT_SYMBOL_GPL(crypto_lookup_template); | ||||||
| int crypto_register_instance(struct crypto_template *tmpl, | int crypto_register_instance(struct crypto_template *tmpl, | ||||||
| 			     struct crypto_instance *inst) | 			     struct crypto_instance *inst) | ||||||
| { | { | ||||||
|  | 	LIST_HEAD(list); | ||||||
| 	int err = -EINVAL; | 	int err = -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	if (inst->alg.cra_destroy) | 	if (inst->alg.cra_destroy) | ||||||
|  | @ -235,7 +332,7 @@ int crypto_register_instance(struct crypto_template *tmpl, | ||||||
| 
 | 
 | ||||||
| 	down_write(&crypto_alg_sem); | 	down_write(&crypto_alg_sem); | ||||||
| 
 | 
 | ||||||
| 	err = __crypto_register_alg(&inst->alg); | 	err = __crypto_register_alg(&inst->alg, &list); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		goto unlock; | 		goto unlock; | ||||||
| 
 | 
 | ||||||
|  | @ -245,11 +342,67 @@ int crypto_register_instance(struct crypto_template *tmpl, | ||||||
| unlock: | unlock: | ||||||
| 	up_write(&crypto_alg_sem); | 	up_write(&crypto_alg_sem); | ||||||
| 
 | 
 | ||||||
|  | 	crypto_remove_final(&list); | ||||||
|  | 
 | ||||||
| err: | err: | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(crypto_register_instance); | EXPORT_SYMBOL_GPL(crypto_register_instance); | ||||||
| 
 | 
 | ||||||
|  | int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, | ||||||
|  | 		      struct crypto_instance *inst) | ||||||
|  | { | ||||||
|  | 	int err = -EAGAIN; | ||||||
|  | 
 | ||||||
|  | 	spawn->inst = inst; | ||||||
|  | 
 | ||||||
|  | 	down_write(&crypto_alg_sem); | ||||||
|  | 	if (!crypto_is_moribund(alg)) { | ||||||
|  | 		list_add(&spawn->list, &alg->cra_users); | ||||||
|  | 		spawn->alg = alg; | ||||||
|  | 		err = 0; | ||||||
|  | 	} | ||||||
|  | 	up_write(&crypto_alg_sem); | ||||||
|  | 
 | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(crypto_init_spawn); | ||||||
|  | 
 | ||||||
|  | void crypto_drop_spawn(struct crypto_spawn *spawn) | ||||||
|  | { | ||||||
|  | 	down_write(&crypto_alg_sem); | ||||||
|  | 	list_del(&spawn->list); | ||||||
|  | 	up_write(&crypto_alg_sem); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(crypto_drop_spawn); | ||||||
|  | 
 | ||||||
|  | struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn) | ||||||
|  | { | ||||||
|  | 	struct crypto_alg *alg; | ||||||
|  | 	struct crypto_alg *alg2; | ||||||
|  | 	struct crypto_tfm *tfm; | ||||||
|  | 
 | ||||||
|  | 	down_read(&crypto_alg_sem); | ||||||
|  | 	alg = spawn->alg; | ||||||
|  | 	alg2 = alg; | ||||||
|  | 	if (alg2) | ||||||
|  | 		alg2 = crypto_mod_get(alg2); | ||||||
|  | 	up_read(&crypto_alg_sem); | ||||||
|  | 
 | ||||||
|  | 	if (!alg2) { | ||||||
|  | 		if (alg) | ||||||
|  | 			crypto_shoot_alg(alg); | ||||||
|  | 		return ERR_PTR(-EAGAIN); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	tfm = __crypto_alloc_tfm(alg, 0); | ||||||
|  | 	if (IS_ERR(tfm)) | ||||||
|  | 		crypto_mod_put(alg); | ||||||
|  | 
 | ||||||
|  | 	return tfm; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(crypto_spawn_tfm); | ||||||
|  | 
 | ||||||
| int crypto_register_notifier(struct notifier_block *nb) | int crypto_register_notifier(struct notifier_block *nb) | ||||||
| { | { | ||||||
| 	return blocking_notifier_chain_register(&crypto_chain, nb); | 	return blocking_notifier_chain_register(&crypto_chain, nb); | ||||||
|  |  | ||||||
							
								
								
									
										93
									
								
								crypto/api.c
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								crypto/api.c
									
									
									
									
									
								
							|  | @ -15,11 +15,13 @@ | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <linux/err.h> | ||||||
| #include <linux/errno.h> | #include <linux/errno.h> | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| #include <linux/kmod.h> | #include <linux/kmod.h> | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/param.h> | #include <linux/param.h> | ||||||
|  | #include <linux/sched.h> | ||||||
| #include <linux/slab.h> | #include <linux/slab.h> | ||||||
| #include <linux/string.h> | #include <linux/string.h> | ||||||
| #include "internal.h" | #include "internal.h" | ||||||
|  | @ -38,12 +40,6 @@ static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) | ||||||
| 	return alg; | 	return alg; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void crypto_alg_put(struct crypto_alg *alg) |  | ||||||
| { |  | ||||||
| 	if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) |  | ||||||
| 		alg->cra_destroy(alg); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) | struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) | ||||||
| { | { | ||||||
| 	return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; | 	return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; | ||||||
|  | @ -65,6 +61,9 @@ struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask) | ||||||
| 	list_for_each_entry(q, &crypto_alg_list, cra_list) { | 	list_for_each_entry(q, &crypto_alg_list, cra_list) { | ||||||
| 		int exact, fuzzy; | 		int exact, fuzzy; | ||||||
| 
 | 
 | ||||||
|  | 		if (crypto_is_moribund(q)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
| 		if ((q->cra_flags ^ type) & mask) | 		if ((q->cra_flags ^ type) & mask) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
|  | @ -111,7 +110,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, | ||||||
| 
 | 
 | ||||||
| 	larval = kzalloc(sizeof(*larval), GFP_KERNEL); | 	larval = kzalloc(sizeof(*larval), GFP_KERNEL); | ||||||
| 	if (!larval) | 	if (!larval) | ||||||
| 		return NULL; | 		return ERR_PTR(-ENOMEM); | ||||||
| 
 | 
 | ||||||
| 	larval->mask = mask; | 	larval->mask = mask; | ||||||
| 	larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; | 	larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; | ||||||
|  | @ -153,8 +152,11 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) | ||||||
| 
 | 
 | ||||||
| 	wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); | 	wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); | ||||||
| 	alg = larval->adult; | 	alg = larval->adult; | ||||||
| 	if (alg && !crypto_mod_get(alg)) | 	if (alg) { | ||||||
| 		alg = NULL; | 		if (!crypto_mod_get(alg)) | ||||||
|  | 			alg = ERR_PTR(-EAGAIN); | ||||||
|  | 	} else | ||||||
|  | 		alg = ERR_PTR(-ENOENT); | ||||||
| 	crypto_mod_put(&larval->alg); | 	crypto_mod_put(&larval->alg); | ||||||
| 
 | 
 | ||||||
| 	return alg; | 	return alg; | ||||||
|  | @ -165,9 +167,6 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, | ||||||
| { | { | ||||||
| 	struct crypto_alg *alg; | 	struct crypto_alg *alg; | ||||||
| 
 | 
 | ||||||
| 	if (!name) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	down_read(&crypto_alg_sem); | 	down_read(&crypto_alg_sem); | ||||||
| 	alg = __crypto_alg_lookup(name, type, mask); | 	alg = __crypto_alg_lookup(name, type, mask); | ||||||
| 	up_read(&crypto_alg_sem); | 	up_read(&crypto_alg_sem); | ||||||
|  | @ -181,7 +180,10 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) | ||||||
| 	struct crypto_alg *larval; | 	struct crypto_alg *larval; | ||||||
| 	int ok; | 	int ok; | ||||||
| 
 | 
 | ||||||
| 	mask &= ~CRYPTO_ALG_LARVAL; | 	if (!name) | ||||||
|  | 		return ERR_PTR(-ENOENT); | ||||||
|  | 
 | ||||||
|  | 	mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); | ||||||
| 	type &= mask; | 	type &= mask; | ||||||
| 
 | 
 | ||||||
| 	alg = try_then_request_module(crypto_alg_lookup(name, type, mask), | 	alg = try_then_request_module(crypto_alg_lookup(name, type, mask), | ||||||
|  | @ -190,7 +192,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) | ||||||
| 		return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; | 		return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; | ||||||
| 
 | 
 | ||||||
| 	larval = crypto_larval_alloc(name, type, mask); | 	larval = crypto_larval_alloc(name, type, mask); | ||||||
| 	if (!larval || !crypto_is_larval(larval)) | 	if (IS_ERR(larval) || !crypto_is_larval(larval)) | ||||||
| 		return larval; | 		return larval; | ||||||
| 
 | 
 | ||||||
| 	ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); | 	ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); | ||||||
|  | @ -203,7 +205,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) | ||||||
| 		alg = crypto_larval_wait(larval); | 		alg = crypto_larval_wait(larval); | ||||||
| 	else { | 	else { | ||||||
| 		crypto_mod_put(larval); | 		crypto_mod_put(larval); | ||||||
| 		alg = NULL; | 		alg = ERR_PTR(-ENOENT); | ||||||
| 	} | 	} | ||||||
| 	crypto_larval_kill(larval); | 	crypto_larval_kill(larval); | ||||||
| 	return alg; | 	return alg; | ||||||
|  | @ -298,31 +300,40 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) | ||||||
| 	return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); | 	return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) | void crypto_shoot_alg(struct crypto_alg *alg) | ||||||
|  | { | ||||||
|  | 	down_write(&crypto_alg_sem); | ||||||
|  | 	alg->cra_flags |= CRYPTO_ALG_DYING; | ||||||
|  | 	up_write(&crypto_alg_sem); | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL_GPL(crypto_shoot_alg); | ||||||
|  | 
 | ||||||
|  | struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) | ||||||
| { | { | ||||||
| 	struct crypto_tfm *tfm = NULL; | 	struct crypto_tfm *tfm = NULL; | ||||||
| 	struct crypto_alg *alg; |  | ||||||
| 	unsigned int tfm_size; | 	unsigned int tfm_size; | ||||||
| 
 | 	int err = -ENOMEM; | ||||||
| 	alg = crypto_alg_mod_lookup(name, 0, 0); |  | ||||||
| 	if (alg == NULL) |  | ||||||
| 		goto out; |  | ||||||
| 
 | 
 | ||||||
| 	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); | 	tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); | ||||||
| 	tfm = kzalloc(tfm_size, GFP_KERNEL); | 	tfm = kzalloc(tfm_size, GFP_KERNEL); | ||||||
| 	if (tfm == NULL) | 	if (tfm == NULL) | ||||||
| 		goto out_put; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	tfm->__crt_alg = alg; | 	tfm->__crt_alg = alg; | ||||||
| 
 | 
 | ||||||
| 	if (crypto_init_flags(tfm, flags)) | 	err = crypto_init_flags(tfm, flags); | ||||||
|  | 	if (err) | ||||||
| 		goto out_free_tfm; | 		goto out_free_tfm; | ||||||
| 		 | 		 | ||||||
| 	if (crypto_init_ops(tfm)) | 	err = crypto_init_ops(tfm); | ||||||
|  | 	if (err) | ||||||
| 		goto out_free_tfm; | 		goto out_free_tfm; | ||||||
| 
 | 
 | ||||||
| 	if (alg->cra_init && alg->cra_init(tfm)) | 	if (alg->cra_init && (err = alg->cra_init(tfm))) { | ||||||
|  | 		if (err == -EAGAIN) | ||||||
|  | 			crypto_shoot_alg(alg); | ||||||
| 		goto cra_init_failed; | 		goto cra_init_failed; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	goto out; | 	goto out; | ||||||
| 
 | 
 | ||||||
|  | @ -330,12 +341,36 @@ struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) | ||||||
| 	crypto_exit_ops(tfm); | 	crypto_exit_ops(tfm); | ||||||
| out_free_tfm: | out_free_tfm: | ||||||
| 	kfree(tfm); | 	kfree(tfm); | ||||||
| 	tfm = NULL; | 	tfm = ERR_PTR(err); | ||||||
| out_put: |  | ||||||
| 	crypto_mod_put(alg); |  | ||||||
| out: | out: | ||||||
| 	return tfm; | 	return tfm; | ||||||
| } | } | ||||||
|  | EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); | ||||||
|  | 
 | ||||||
|  | struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) | ||||||
|  | { | ||||||
|  | 	struct crypto_tfm *tfm = NULL; | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		struct crypto_alg *alg; | ||||||
|  | 
 | ||||||
|  | 		alg = crypto_alg_mod_lookup(name, 0, 0); | ||||||
|  | 		err = PTR_ERR(alg); | ||||||
|  | 		if (IS_ERR(alg)) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		tfm = __crypto_alloc_tfm(alg, flags); | ||||||
|  | 		err = 0; | ||||||
|  | 		if (IS_ERR(tfm)) { | ||||||
|  | 			crypto_mod_put(alg); | ||||||
|  | 			err = PTR_ERR(tfm); | ||||||
|  | 			tfm = NULL; | ||||||
|  | 		} | ||||||
|  | 	} while (err == -EAGAIN && !signal_pending(current)); | ||||||
|  | 
 | ||||||
|  | 	return tfm; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void crypto_free_tfm(struct crypto_tfm *tfm) | void crypto_free_tfm(struct crypto_tfm *tfm) | ||||||
| { | { | ||||||
|  | @ -361,7 +396,7 @@ int crypto_alg_available(const char *name, u32 flags) | ||||||
| 	int ret = 0; | 	int ret = 0; | ||||||
| 	struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0); | 	struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, 0); | ||||||
| 	 | 	 | ||||||
| 	if (alg) { | 	if (!IS_ERR(alg)) { | ||||||
| 		crypto_mod_put(alg); | 		crypto_mod_put(alg); | ||||||
| 		ret = 1; | 		ret = 1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/notifier.h> | #include <linux/notifier.h> | ||||||
| #include <linux/rtnetlink.h> | #include <linux/rtnetlink.h> | ||||||
|  | #include <linux/sched.h> | ||||||
| #include <linux/string.h> | #include <linux/string.h> | ||||||
| #include <linux/workqueue.h> | #include <linux/workqueue.h> | ||||||
| 
 | 
 | ||||||
|  | @ -44,21 +45,25 @@ static void cryptomgr_probe(void *data) | ||||||
| 	struct cryptomgr_param *param = data; | 	struct cryptomgr_param *param = data; | ||||||
| 	struct crypto_template *tmpl; | 	struct crypto_template *tmpl; | ||||||
| 	struct crypto_instance *inst; | 	struct crypto_instance *inst; | ||||||
|  | 	int err; | ||||||
| 
 | 
 | ||||||
| 	tmpl = crypto_lookup_template(param->template); | 	tmpl = crypto_lookup_template(param->template); | ||||||
| 	if (!tmpl) | 	if (!tmpl) | ||||||
| 		goto err; | 		goto err; | ||||||
| 
 | 
 | ||||||
|  | 	do { | ||||||
| 		inst = tmpl->alloc(¶m->alg, sizeof(param->alg)); | 		inst = tmpl->alloc(¶m->alg, sizeof(param->alg)); | ||||||
| 		if (IS_ERR(inst)) | 		if (IS_ERR(inst)) | ||||||
| 		goto err; | 			err = PTR_ERR(inst); | ||||||
| 	else if ((err = crypto_register_instance(tmpl, inst))) { | 		else if ((err = crypto_register_instance(tmpl, inst))) | ||||||
| 			tmpl->free(inst); | 			tmpl->free(inst); | ||||||
| 		goto err; | 	} while (err == -EAGAIN && !signal_pending(current)); | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	crypto_tmpl_put(tmpl); | 	crypto_tmpl_put(tmpl); | ||||||
| 
 | 
 | ||||||
|  | 	if (err) | ||||||
|  | 		goto err; | ||||||
|  | 
 | ||||||
| out: | out: | ||||||
| 	kfree(param); | 	kfree(param); | ||||||
| 	return; | 	return; | ||||||
|  |  | ||||||
|  | @ -142,12 +142,21 @@ void crypto_exit_compress_ops(struct crypto_tfm *tfm); | ||||||
| 
 | 
 | ||||||
| void crypto_larval_error(const char *name, u32 type, u32 mask); | void crypto_larval_error(const char *name, u32 type, u32 mask); | ||||||
| 
 | 
 | ||||||
|  | void crypto_shoot_alg(struct crypto_alg *alg); | ||||||
|  | struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags); | ||||||
|  | 
 | ||||||
| int crypto_register_instance(struct crypto_template *tmpl, | int crypto_register_instance(struct crypto_template *tmpl, | ||||||
| 			     struct crypto_instance *inst); | 			     struct crypto_instance *inst); | ||||||
| 
 | 
 | ||||||
| int crypto_register_notifier(struct notifier_block *nb); | int crypto_register_notifier(struct notifier_block *nb); | ||||||
| int crypto_unregister_notifier(struct notifier_block *nb); | int crypto_unregister_notifier(struct notifier_block *nb); | ||||||
| 
 | 
 | ||||||
|  | static inline void crypto_alg_put(struct crypto_alg *alg) | ||||||
|  | { | ||||||
|  | 	if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) | ||||||
|  | 		alg->cra_destroy(alg); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline int crypto_tmpl_get(struct crypto_template *tmpl) | static inline int crypto_tmpl_get(struct crypto_template *tmpl) | ||||||
| { | { | ||||||
| 	return try_module_get(tmpl->module); | 	return try_module_get(tmpl->module); | ||||||
|  | @ -163,6 +172,16 @@ static inline int crypto_is_larval(struct crypto_alg *alg) | ||||||
| 	return alg->cra_flags & CRYPTO_ALG_LARVAL; | 	return alg->cra_flags & CRYPTO_ALG_LARVAL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline int crypto_is_dead(struct crypto_alg *alg) | ||||||
|  | { | ||||||
|  | 	return alg->cra_flags & CRYPTO_ALG_DEAD; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline int crypto_is_moribund(struct crypto_alg *alg) | ||||||
|  | { | ||||||
|  | 	return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline int crypto_notify(unsigned long val, void *v) | static inline int crypto_notify(unsigned long val, void *v) | ||||||
| { | { | ||||||
| 	return blocking_notifier_call_chain(&crypto_chain, val, v); | 	return blocking_notifier_call_chain(&crypto_chain, val, v); | ||||||
|  |  | ||||||
|  | @ -36,10 +36,21 @@ struct crypto_template { | ||||||
| 	char name[CRYPTO_MAX_ALG_NAME]; | 	char name[CRYPTO_MAX_ALG_NAME]; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | struct crypto_spawn { | ||||||
|  | 	struct list_head list; | ||||||
|  | 	struct crypto_alg *alg; | ||||||
|  | 	struct crypto_instance *inst; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| int crypto_register_template(struct crypto_template *tmpl); | int crypto_register_template(struct crypto_template *tmpl); | ||||||
| void crypto_unregister_template(struct crypto_template *tmpl); | void crypto_unregister_template(struct crypto_template *tmpl); | ||||||
| struct crypto_template *crypto_lookup_template(const char *name); | struct crypto_template *crypto_lookup_template(const char *name); | ||||||
| 
 | 
 | ||||||
|  | int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, | ||||||
|  | 		      struct crypto_instance *inst); | ||||||
|  | void crypto_drop_spawn(struct crypto_spawn *spawn); | ||||||
|  | struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn); | ||||||
|  | 
 | ||||||
| static inline void *crypto_instance_ctx(struct crypto_instance *inst) | static inline void *crypto_instance_ctx(struct crypto_instance *inst) | ||||||
| { | { | ||||||
| 	return inst->__ctx; | 	return inst->__ctx; | ||||||
|  |  | ||||||
|  | @ -35,6 +35,8 @@ | ||||||
| #define CRYPTO_ALG_TYPE_COMPRESS	0x00000004 | #define CRYPTO_ALG_TYPE_COMPRESS	0x00000004 | ||||||
| 
 | 
 | ||||||
| #define CRYPTO_ALG_LARVAL		0x00000010 | #define CRYPTO_ALG_LARVAL		0x00000010 | ||||||
|  | #define CRYPTO_ALG_DEAD			0x00000020 | ||||||
|  | #define CRYPTO_ALG_DYING		0x00000040 | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Transform masks and values (for crt_flags). |  * Transform masks and values (for crt_flags). | ||||||
|  | @ -145,6 +147,8 @@ struct compress_alg { | ||||||
| 
 | 
 | ||||||
| struct crypto_alg { | struct crypto_alg { | ||||||
| 	struct list_head cra_list; | 	struct list_head cra_list; | ||||||
|  | 	struct list_head cra_users; | ||||||
|  | 
 | ||||||
| 	u32 cra_flags; | 	u32 cra_flags; | ||||||
| 	unsigned int cra_blocksize; | 	unsigned int cra_blocksize; | ||||||
| 	unsigned int cra_ctxsize; | 	unsigned int cra_ctxsize; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Herbert Xu
						Herbert Xu