forked from mirrors/linux
		
	crypto: api - Add support for duplicating algorithms before registration
If the bit CRYPTO_ALG_DUP_FIRST is set, an algorithm will be duplicated by kmemdup before registration. This is inteded for hardware-based algorithms that may be unplugged at will. Do not use this if the algorithm data structure is embedded in a bigger data structure. Perform the duplication in the driver instead. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
		
							parent
							
								
									66fecd9d94
								
							
						
					
					
						commit
						f1440a9046
					
				
					 15 changed files with 61 additions and 14 deletions
				
			
		|  | @ -150,6 +150,7 @@ static const struct crypto_type crypto_acomp_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_ACOMPRESS_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_ACOMPRESS, | ||||
| 	.tfmsize = offsetof(struct crypto_acomp, base), | ||||
| 	.algsize = offsetof(struct acomp_alg, base), | ||||
| }; | ||||
| 
 | ||||
| struct crypto_acomp *crypto_alloc_acomp(const char *alg_name, u32 type, | ||||
|  |  | |||
|  | @ -186,6 +186,7 @@ static const struct crypto_type crypto_aead_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_AEAD, | ||||
| 	.tfmsize = offsetof(struct crypto_aead, base), | ||||
| 	.algsize = offsetof(struct aead_alg, base), | ||||
| }; | ||||
| 
 | ||||
| int crypto_grab_aead(struct crypto_aead_spawn *spawn, | ||||
|  |  | |||
|  | @ -792,6 +792,7 @@ static const struct crypto_type crypto_ahash_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_AHASH_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_AHASH, | ||||
| 	.tfmsize = offsetof(struct crypto_ahash, base), | ||||
| 	.algsize = offsetof(struct ahash_alg, halg.base), | ||||
| }; | ||||
| 
 | ||||
| int crypto_grab_ahash(struct crypto_ahash_spawn *spawn, | ||||
|  |  | |||
|  | @ -97,6 +97,7 @@ static const struct crypto_type crypto_akcipher_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_AHASH_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_AKCIPHER, | ||||
| 	.tfmsize = offsetof(struct crypto_akcipher, base), | ||||
| 	.algsize = offsetof(struct akcipher_alg, base), | ||||
| }; | ||||
| 
 | ||||
| int crypto_grab_akcipher(struct crypto_akcipher_spawn *spawn, | ||||
|  |  | |||
|  | @ -66,13 +66,7 @@ static int crypto_check_alg(struct crypto_alg *alg) | |||
| 
 | ||||
| static void crypto_free_instance(struct crypto_instance *inst) | ||||
| { | ||||
| 	struct crypto_alg *alg = &inst->alg; | ||||
| 	const struct crypto_type *type; | ||||
| 
 | ||||
| 	type = alg->cra_type; | ||||
| 	if (type->destroy) | ||||
| 		type->destroy(alg); | ||||
| 	type->free(inst); | ||||
| 	inst->alg.cra_type->free(inst); | ||||
| } | ||||
| 
 | ||||
| static void crypto_destroy_instance_workfn(struct work_struct *w) | ||||
|  | @ -424,6 +418,15 @@ void crypto_remove_final(struct list_head *list) | |||
| } | ||||
| EXPORT_SYMBOL_GPL(crypto_remove_final); | ||||
| 
 | ||||
| static void crypto_free_alg(struct crypto_alg *alg) | ||||
| { | ||||
| 	unsigned int algsize = alg->cra_type->algsize; | ||||
| 	u8 *p = (u8 *)alg - algsize; | ||||
| 
 | ||||
| 	crypto_destroy_alg(alg); | ||||
| 	kfree(p); | ||||
| } | ||||
| 
 | ||||
| int crypto_register_alg(struct crypto_alg *alg) | ||||
| { | ||||
| 	struct crypto_larval *larval; | ||||
|  | @ -436,6 +439,19 @@ int crypto_register_alg(struct crypto_alg *alg) | |||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	if (alg->cra_flags & CRYPTO_ALG_DUP_FIRST && | ||||
| 	    !WARN_ON_ONCE(alg->cra_destroy)) { | ||||
| 		unsigned int algsize = alg->cra_type->algsize; | ||||
| 		u8 *p = (u8 *)alg - algsize; | ||||
| 
 | ||||
| 		p = kmemdup(p, algsize + sizeof(*alg), GFP_KERNEL); | ||||
| 		if (!p) | ||||
| 			return -ENOMEM; | ||||
| 
 | ||||
| 		alg = (void *)(p + algsize); | ||||
| 		alg->cra_destroy = crypto_free_alg; | ||||
| 	} | ||||
| 
 | ||||
| 	down_write(&crypto_alg_sem); | ||||
| 	larval = __crypto_register_alg(alg, &algs_to_put); | ||||
| 	if (!IS_ERR_OR_NULL(larval)) { | ||||
|  | @ -444,8 +460,10 @@ int crypto_register_alg(struct crypto_alg *alg) | |||
| 	} | ||||
| 	up_write(&crypto_alg_sem); | ||||
| 
 | ||||
| 	if (IS_ERR(larval)) | ||||
| 	if (IS_ERR(larval)) { | ||||
| 		crypto_alg_put(alg); | ||||
| 		return PTR_ERR(larval); | ||||
| 	} | ||||
| 
 | ||||
| 	if (test_started) | ||||
| 		crypto_schedule_test(larval); | ||||
|  | @ -481,12 +499,9 @@ void crypto_unregister_alg(struct crypto_alg *alg) | |||
| 	if (WARN(ret, "Algorithm %s is not registered", alg->cra_driver_name)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (alg->cra_destroy) | ||||
| 		crypto_alg_put(alg); | ||||
| 	else if (!WARN_ON(refcount_read(&alg->cra_refcnt) != 1) && | ||||
| 		 alg->cra_type && alg->cra_type->destroy) | ||||
| 		alg->cra_type->destroy(alg); | ||||
| 	WARN_ON(!alg->cra_destroy && refcount_read(&alg->cra_refcnt) != 1); | ||||
| 
 | ||||
| 	list_add(&alg->cra_list, &list); | ||||
| 	crypto_remove_final(&list); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(crypto_unregister_alg); | ||||
|  |  | |||
|  | @ -703,5 +703,14 @@ void crypto_req_done(void *data, int err) | |||
| } | ||||
| EXPORT_SYMBOL_GPL(crypto_req_done); | ||||
| 
 | ||||
| void crypto_destroy_alg(struct crypto_alg *alg) | ||||
| { | ||||
| 	if (alg->cra_type && alg->cra_type->destroy) | ||||
| 		alg->cra_type->destroy(alg); | ||||
| 	if (alg->cra_destroy) | ||||
| 		alg->cra_destroy(alg); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(crypto_destroy_alg); | ||||
| 
 | ||||
| MODULE_DESCRIPTION("Cryptographic core API"); | ||||
| MODULE_LICENSE("GPL"); | ||||
|  |  | |||
|  | @ -46,6 +46,7 @@ struct crypto_type { | |||
| 	unsigned int maskclear; | ||||
| 	unsigned int maskset; | ||||
| 	unsigned int tfmsize; | ||||
| 	unsigned int algsize; | ||||
| }; | ||||
| 
 | ||||
| enum { | ||||
|  | @ -162,10 +163,12 @@ static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) | |||
| 	return alg; | ||||
| } | ||||
| 
 | ||||
| void crypto_destroy_alg(struct crypto_alg *alg); | ||||
| 
 | ||||
| static inline void crypto_alg_put(struct crypto_alg *alg) | ||||
| { | ||||
| 	if (refcount_dec_and_test(&alg->cra_refcnt)) | ||||
| 		alg->cra_destroy(alg); | ||||
| 		crypto_destroy_alg(alg); | ||||
| } | ||||
| 
 | ||||
| static inline int crypto_tmpl_get(struct crypto_template *tmpl) | ||||
|  |  | |||
|  | @ -80,6 +80,7 @@ static const struct crypto_type crypto_kpp_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_KPP, | ||||
| 	.tfmsize = offsetof(struct crypto_kpp, base), | ||||
| 	.algsize = offsetof(struct kpp_alg, base), | ||||
| }; | ||||
| 
 | ||||
| struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask) | ||||
|  |  | |||
|  | @ -294,6 +294,7 @@ static const struct crypto_type crypto_lskcipher_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_LSKCIPHER, | ||||
| 	.tfmsize = offsetof(struct crypto_lskcipher, base), | ||||
| 	.algsize = offsetof(struct lskcipher_alg, co.base), | ||||
| }; | ||||
| 
 | ||||
| static void crypto_lskcipher_exit_tfm_sg(struct crypto_tfm *tfm) | ||||
|  |  | |||
|  | @ -98,6 +98,7 @@ static const struct crypto_type crypto_rng_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_RNG, | ||||
| 	.tfmsize = offsetof(struct crypto_rng, base), | ||||
| 	.algsize = offsetof(struct rng_alg, base), | ||||
| }; | ||||
| 
 | ||||
| struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask) | ||||
|  |  | |||
|  | @ -347,6 +347,7 @@ static const struct crypto_type crypto_scomp_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_SCOMPRESS, | ||||
| 	.tfmsize = offsetof(struct crypto_scomp, base), | ||||
| 	.algsize = offsetof(struct scomp_alg, base), | ||||
| }; | ||||
| 
 | ||||
| static void scomp_prepare_alg(struct scomp_alg *alg) | ||||
|  |  | |||
|  | @ -227,6 +227,7 @@ const struct crypto_type crypto_shash_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_SHASH, | ||||
| 	.tfmsize = offsetof(struct crypto_shash, base), | ||||
| 	.algsize = offsetof(struct shash_alg, base), | ||||
| }; | ||||
| 
 | ||||
| int crypto_grab_shash(struct crypto_shash_spawn *spawn, | ||||
|  |  | |||
|  | @ -74,6 +74,7 @@ static const struct crypto_type crypto_sig_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_SIG, | ||||
| 	.tfmsize = offsetof(struct crypto_sig, base), | ||||
| 	.algsize = offsetof(struct sig_alg, base), | ||||
| }; | ||||
| 
 | ||||
| struct crypto_sig *crypto_alloc_sig(const char *alg_name, u32 type, u32 mask) | ||||
|  |  | |||
|  | @ -620,6 +620,7 @@ static const struct crypto_type crypto_skcipher_type = { | |||
| 	.maskset = CRYPTO_ALG_TYPE_SKCIPHER_MASK, | ||||
| 	.type = CRYPTO_ALG_TYPE_SKCIPHER, | ||||
| 	.tfmsize = offsetof(struct crypto_skcipher, base), | ||||
| 	.algsize = offsetof(struct skcipher_alg, base), | ||||
| }; | ||||
| 
 | ||||
| int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, | ||||
|  |  | |||
|  | @ -49,6 +49,15 @@ | |||
|  */ | ||||
| #define CRYPTO_ALG_NEED_FALLBACK	0x00000100 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set if the algorithm data structure should be duplicated into | ||||
|  * kmalloc memory before registration.  This is useful for hardware | ||||
|  * that can be disconnected at will.  Do not use this if the data | ||||
|  * structure is embedded into a bigger one.  Duplicate the overall | ||||
|  * data structure in the driver in that case. | ||||
|  */ | ||||
| #define CRYPTO_ALG_DUP_FIRST		0x00000200 | ||||
| 
 | ||||
| /*
 | ||||
|  * Set if the algorithm has passed automated run-time testing.  Note that | ||||
|  * if there is no run-time testing for a given algorithm it is considered | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Herbert Xu
						Herbert Xu