diff options
Diffstat (limited to 'crypto/algapi.c')
| -rw-r--r-- | crypto/algapi.c | 123 | 
1 files changed, 84 insertions, 39 deletions
| diff --git a/crypto/algapi.c b/crypto/algapi.c index 43f999dba4dc..d379fd91fb7b 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -216,6 +216,32 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,  }  EXPORT_SYMBOL_GPL(crypto_remove_spawns); +static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg) +{ +	struct crypto_larval *larval; + +	if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER)) +		return NULL; + +	larval = crypto_larval_alloc(alg->cra_name, +				     alg->cra_flags | CRYPTO_ALG_TESTED, 0); +	if (IS_ERR(larval)) +		return larval; + +	larval->adult = crypto_mod_get(alg); +	if (!larval->adult) { +		kfree(larval); +		return ERR_PTR(-ENOENT); +	} + +	refcount_set(&larval->alg.cra_refcnt, 1); +	memcpy(larval->alg.cra_driver_name, alg->cra_driver_name, +	       CRYPTO_MAX_ALG_NAME); +	larval->alg.cra_priority = alg->cra_priority; + +	return larval; +} +  static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)  {  	struct crypto_alg *q; @@ -250,31 +276,20 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)  			goto err;  	} -	larval = crypto_larval_alloc(alg->cra_name, -				     alg->cra_flags | CRYPTO_ALG_TESTED, 0); +	larval = crypto_alloc_test_larval(alg);  	if (IS_ERR(larval))  		goto out; -	ret = -ENOENT; -	larval->adult = crypto_mod_get(alg); -	if (!larval->adult) -		goto free_larval; - -	refcount_set(&larval->alg.cra_refcnt, 1); -	memcpy(larval->alg.cra_driver_name, alg->cra_driver_name, -	       CRYPTO_MAX_ALG_NAME); -	larval->alg.cra_priority = alg->cra_priority; -  	list_add(&alg->cra_list, &crypto_alg_list); -	list_add(&larval->alg.cra_list, &crypto_alg_list); + +	if (larval) +		list_add(&larval->alg.cra_list, &crypto_alg_list);  	crypto_stats_init(alg);  out:  	return larval; -free_larval: -	kfree(larval);  err:  	larval = ERR_PTR(ret);  	goto out; @@ -389,29 +404,10 @@ void crypto_remove_final(struct list_head *list)  }  EXPORT_SYMBOL_GPL(crypto_remove_final); -static void crypto_wait_for_test(struct crypto_larval *larval) -{ -	int err; - -	err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult); -	if (err != NOTIFY_STOP) { -		if (WARN_ON(err != NOTIFY_DONE)) -			goto out; -		crypto_alg_tested(larval->alg.cra_driver_name, 0); -	} - -	err = wait_for_completion_killable(&larval->completion); -	WARN_ON(err); -	if (!err) -		crypto_notify(CRYPTO_MSG_ALG_LOADED, larval); - -out: -	crypto_larval_kill(&larval->alg); -} -  int crypto_register_alg(struct crypto_alg *alg)  {  	struct crypto_larval *larval; +	bool test_started;  	int err;  	alg->cra_flags &= ~CRYPTO_ALG_DEAD; @@ -421,12 +417,16 @@ int crypto_register_alg(struct crypto_alg *alg)  	down_write(&crypto_alg_sem);  	larval = __crypto_register_alg(alg); +	test_started = static_key_enabled(&crypto_boot_test_finished); +	if (!IS_ERR_OR_NULL(larval)) +		larval->test_started = test_started;  	up_write(&crypto_alg_sem); -	if (IS_ERR(larval)) +	if (IS_ERR_OR_NULL(larval))  		return PTR_ERR(larval); -	crypto_wait_for_test(larval); +	if (test_started) +		crypto_wait_for_test(larval);  	return 0;  }  EXPORT_SYMBOL_GPL(crypto_register_alg); @@ -632,6 +632,8 @@ int crypto_register_instance(struct crypto_template *tmpl,  	larval = __crypto_register_alg(&inst->alg);  	if (IS_ERR(larval))  		goto unlock; +	else if (larval) +		larval->test_started = true;  	hlist_add_head(&inst->list, &tmpl->instances);  	inst->tmpl = tmpl; @@ -640,7 +642,7 @@ unlock:  	up_write(&crypto_alg_sem);  	err = PTR_ERR(larval); -	if (IS_ERR(larval)) +	if (IS_ERR_OR_NULL(larval))  		goto err;  	crypto_wait_for_test(larval); @@ -1261,9 +1263,48 @@ void crypto_stats_skcipher_decrypt(unsigned int cryptlen, int ret,  EXPORT_SYMBOL_GPL(crypto_stats_skcipher_decrypt);  #endif +static void __init crypto_start_tests(void) +{ +	for (;;) { +		struct crypto_larval *larval = NULL; +		struct crypto_alg *q; + +		down_write(&crypto_alg_sem); + +		list_for_each_entry(q, &crypto_alg_list, cra_list) { +			struct crypto_larval *l; + +			if (!crypto_is_larval(q)) +				continue; + +			l = (void *)q; + +			if (!crypto_is_test_larval(l)) +				continue; + +			if (l->test_started) +				continue; + +			l->test_started = true; +			larval = l; +			break; +		} + +		up_write(&crypto_alg_sem); + +		if (!larval) +			break; + +		crypto_wait_for_test(larval); +	} + +	static_branch_enable(&crypto_boot_test_finished); +} +  static int __init crypto_algapi_init(void)  {  	crypto_init_proc(); +	crypto_start_tests();  	return 0;  } @@ -1272,7 +1313,11 @@ static void __exit crypto_algapi_exit(void)  	crypto_exit_proc();  } -module_init(crypto_algapi_init); +/* + * We run this at late_initcall so that all the built-in algorithms + * have had a chance to register themselves first. + */ +late_initcall(crypto_algapi_init);  module_exit(crypto_algapi_exit);  MODULE_LICENSE("GPL"); |