diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2025-04-12 13:16:43 +0800 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2025-04-16 15:36:24 +0800 |
commit | f1440a90465bea1993f937ac7add592ce1e4ff44 (patch) | |
tree | a1000e8fd4220a04b318b7fabc191a2b7fb22818 /crypto/algapi.c | |
parent | 66fecd9d94034b6193636fe3bc01f089439f5413 (diff) |
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>
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r-- | crypto/algapi.c | 41 |
1 files changed, 28 insertions, 13 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c index f368c0dc0d6d..532d3efc3c7d 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -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); |