Linux 6.9-rc1
[linux-2.6-microblaze.git] / crypto / algapi.c
index d1c9928..85bc279 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/workqueue.h>
 
 #include "internal.h"
 
@@ -74,15 +75,26 @@ static void crypto_free_instance(struct crypto_instance *inst)
        inst->alg.cra_type->free(inst);
 }
 
-static void crypto_destroy_instance(struct crypto_alg *alg)
+static void crypto_destroy_instance_workfn(struct work_struct *w)
 {
-       struct crypto_instance *inst = (void *)alg;
+       struct crypto_instance *inst = container_of(w, struct crypto_instance,
+                                                   free_work);
        struct crypto_template *tmpl = inst->tmpl;
 
        crypto_free_instance(inst);
        crypto_tmpl_put(tmpl);
 }
 
+static void crypto_destroy_instance(struct crypto_alg *alg)
+{
+       struct crypto_instance *inst = container_of(alg,
+                                                   struct crypto_instance,
+                                                   alg);
+
+       INIT_WORK(&inst->free_work, crypto_destroy_instance_workfn);
+       schedule_work(&inst->free_work);
+}
+
 /*
  * This function adds a spawn to the list secondary_spawns which
  * will be used at the end of crypto_remove_spawns to unregister
@@ -222,12 +234,65 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
 }
 EXPORT_SYMBOL_GPL(crypto_remove_spawns);
 
+static void crypto_alg_finish_registration(struct crypto_alg *alg,
+                                          bool fulfill_requests,
+                                          struct list_head *algs_to_put)
+{
+       struct crypto_alg *q;
+
+       list_for_each_entry(q, &crypto_alg_list, cra_list) {
+               if (q == alg)
+                       continue;
+
+               if (crypto_is_moribund(q))
+                       continue;
+
+               if (crypto_is_larval(q)) {
+                       struct crypto_larval *larval = (void *)q;
+
+                       /*
+                        * Check to see if either our generic name or
+                        * specific name can satisfy the name requested
+                        * by the larval entry 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)
+                               continue;
+
+                       if (fulfill_requests && crypto_mod_get(alg))
+                               larval->adult = alg;
+                       else
+                               larval->adult = ERR_PTR(-EAGAIN);
+
+                       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, algs_to_put, alg);
+       }
+
+       crypto_notify(CRYPTO_MSG_ALG_LOADED, alg);
+}
+
 static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg)
 {
        struct crypto_larval *larval;
 
-       if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER))
-               return NULL;
+       if (!IS_ENABLED(CONFIG_CRYPTO_MANAGER) ||
+           IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS) ||
+           (alg->cra_flags & CRYPTO_ALG_INTERNAL))
+               return NULL; /* No self-test needed */
 
        larval = crypto_larval_alloc(alg->cra_name,
                                     alg->cra_flags | CRYPTO_ALG_TESTED, 0);
@@ -248,7 +313,8 @@ static struct crypto_larval *crypto_alloc_test_larval(struct crypto_alg *alg)
        return larval;
 }
 
-static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
+static struct crypto_larval *
+__crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_put)
 {
        struct crypto_alg *q;
        struct crypto_larval *larval;
@@ -259,9 +325,6 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
 
        INIT_LIST_HEAD(&alg->cra_users);
 
-       /* No cheating! */
-       alg->cra_flags &= ~CRYPTO_ALG_TESTED;
-
        ret = -EEXIST;
 
        list_for_each_entry(q, &crypto_alg_list, cra_list) {
@@ -278,6 +341,7 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
                }
 
                if (!strcmp(q->cra_driver_name, alg->cra_name) ||
+                   !strcmp(q->cra_driver_name, alg->cra_driver_name) ||
                    !strcmp(q->cra_name, alg->cra_driver_name))
                        goto err;
        }
@@ -288,12 +352,15 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
 
        list_add(&alg->cra_list, &crypto_alg_list);
 
-       if (larval)
+       if (larval) {
+               /* No cheating! */
+               alg->cra_flags &= ~CRYPTO_ALG_TESTED;
+
                list_add(&larval->alg.cra_list, &crypto_alg_list);
-       else
+       } else {
                alg->cra_flags |= CRYPTO_ALG_TESTED;
-
-       crypto_stats_init(alg);
+               crypto_alg_finish_registration(alg, true, algs_to_put);
+       }
 
 out:
        return larval;
@@ -341,7 +408,10 @@ found:
 
        alg->cra_flags |= CRYPTO_ALG_TESTED;
 
-       /* Only satisfy larval waiters if we are the best. */
+       /*
+        * If a higher-priority implementation of the same algorithm is
+        * currently being tested, then don't fulfill request larvals.
+        */
        best = true;
        list_for_each_entry(q, &crypto_alg_list, cra_list) {
                if (crypto_is_moribund(q) || !crypto_is_larval(q))
@@ -356,47 +426,7 @@ found:
                }
        }
 
-       list_for_each_entry(q, &crypto_alg_list, cra_list) {
-               if (q == alg)
-                       continue;
-
-               if (crypto_is_moribund(q))
-                       continue;
-
-               if (crypto_is_larval(q)) {
-                       struct crypto_larval *larval = (void *)q;
-
-                       /*
-                        * Check to see if either our generic name or
-                        * specific name can satisfy the name requested
-                        * by the larval entry 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)
-                               continue;
-
-                       if (best && crypto_mod_get(alg))
-                               larval->adult = alg;
-                       else
-                               larval->adult = ERR_PTR(-EAGAIN);
-
-                       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, &list, alg);
-       }
+       crypto_alg_finish_registration(alg, best, &list);
 
 complete:
        complete_all(&test->completion);
@@ -423,7 +453,8 @@ EXPORT_SYMBOL_GPL(crypto_remove_final);
 int crypto_register_alg(struct crypto_alg *alg)
 {
        struct crypto_larval *larval;
-       bool test_started;
+       LIST_HEAD(algs_to_put);
+       bool test_started = false;
        int err;
 
        alg->cra_flags &= ~CRYPTO_ALG_DEAD;
@@ -432,17 +463,18 @@ int crypto_register_alg(struct crypto_alg *alg)
                return err;
 
        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 = __crypto_register_alg(alg, &algs_to_put);
+       if (!IS_ERR_OR_NULL(larval)) {
+               test_started = crypto_boot_test_finished();
                larval->test_started = test_started;
+       }
        up_write(&crypto_alg_sem);
 
-       if (IS_ERR_OR_NULL(larval))
+       if (IS_ERR(larval))
                return PTR_ERR(larval);
-
        if (test_started)
                crypto_wait_for_test(larval);
+       crypto_remove_final(&algs_to_put);
        return 0;
 }
 EXPORT_SYMBOL_GPL(crypto_register_alg);
@@ -472,7 +504,9 @@ void crypto_unregister_alg(struct crypto_alg *alg)
        if (WARN(ret, "Algorithm %s is not registered", alg->cra_driver_name))
                return;
 
-       BUG_ON(refcount_read(&alg->cra_refcnt) != 1);
+       if (WARN_ON(refcount_read(&alg->cra_refcnt) != 1))
+               return;
+
        if (alg->cra_destroy)
                alg->cra_destroy(alg);
 
@@ -619,6 +653,7 @@ int crypto_register_instance(struct crypto_template *tmpl,
        struct crypto_larval *larval;
        struct crypto_spawn *spawn;
        u32 fips_internal = 0;
+       LIST_HEAD(algs_to_put);
        int err;
 
        err = crypto_check_alg(&inst->alg);
@@ -650,7 +685,7 @@ int crypto_register_instance(struct crypto_template *tmpl,
 
        inst->alg.cra_flags |= (fips_internal & CRYPTO_ALG_FIPS_INTERNAL);
 
-       larval = __crypto_register_alg(&inst->alg);
+       larval = __crypto_register_alg(&inst->alg, &algs_to_put);
        if (IS_ERR(larval))
                goto unlock;
        else if (larval)
@@ -662,15 +697,12 @@ int crypto_register_instance(struct crypto_template *tmpl,
 unlock:
        up_write(&crypto_alg_sem);
 
-       err = PTR_ERR(larval);
-       if (IS_ERR_OR_NULL(larval))
-               goto err;
-
-       crypto_wait_for_test(larval);
-       err = 0;
-
-err:
-       return err;
+       if (IS_ERR(larval))
+               return PTR_ERR(larval);
+       if (larval)
+               crypto_wait_for_test(larval);
+       crypto_remove_final(&algs_to_put);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(crypto_register_instance);
 
@@ -942,6 +974,9 @@ EXPORT_SYMBOL_GPL(crypto_enqueue_request);
 void crypto_enqueue_request_head(struct crypto_queue *queue,
                                 struct crypto_async_request *request)
 {
+       if (unlikely(queue->qlen >= queue->max_qlen))
+               queue->backlog = queue->backlog->prev;
+
        queue->qlen++;
        list_add(&request->list, &queue->list);
 }
@@ -997,77 +1032,6 @@ void crypto_inc(u8 *a, unsigned int size)
 }
 EXPORT_SYMBOL_GPL(crypto_inc);
 
-void __crypto_xor(u8 *dst, const u8 *src1, const u8 *src2, unsigned int len)
-{
-       int relalign = 0;
-
-       if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
-               int size = sizeof(unsigned long);
-               int d = (((unsigned long)dst ^ (unsigned long)src1) |
-                        ((unsigned long)dst ^ (unsigned long)src2)) &
-                       (size - 1);
-
-               relalign = d ? 1 << __ffs(d) : size;
-
-               /*
-                * If we care about alignment, process as many bytes as
-                * needed to advance dst and src to values whose alignments
-                * equal their relative alignment. This will allow us to
-                * process the remainder of the input using optimal strides.
-                */
-               while (((unsigned long)dst & (relalign - 1)) && len > 0) {
-                       *dst++ = *src1++ ^ *src2++;
-                       len--;
-               }
-       }
-
-       while (IS_ENABLED(CONFIG_64BIT) && len >= 8 && !(relalign & 7)) {
-               if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
-                       u64 l = get_unaligned((u64 *)src1) ^
-                               get_unaligned((u64 *)src2);
-                       put_unaligned(l, (u64 *)dst);
-               } else {
-                       *(u64 *)dst = *(u64 *)src1 ^ *(u64 *)src2;
-               }
-               dst += 8;
-               src1 += 8;
-               src2 += 8;
-               len -= 8;
-       }
-
-       while (len >= 4 && !(relalign & 3)) {
-               if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
-                       u32 l = get_unaligned((u32 *)src1) ^
-                               get_unaligned((u32 *)src2);
-                       put_unaligned(l, (u32 *)dst);
-               } else {
-                       *(u32 *)dst = *(u32 *)src1 ^ *(u32 *)src2;
-               }
-               dst += 4;
-               src1 += 4;
-               src2 += 4;
-               len -= 4;
-       }
-
-       while (len >= 2 && !(relalign & 1)) {
-               if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) {
-                       u16 l = get_unaligned((u16 *)src1) ^
-                               get_unaligned((u16 *)src2);
-                       put_unaligned(l, (u16 *)dst);
-               } else {
-                       *(u16 *)dst = *(u16 *)src1 ^ *(u16 *)src2;
-               }
-               dst += 2;
-               src1 += 2;
-               src2 += 2;
-               len -= 2;
-       }
-
-       while (len--)
-               *dst++ = *src1++ ^ *src2++;
-}
-EXPORT_SYMBOL_GPL(__crypto_xor);
-
 unsigned int crypto_alg_extsize(struct crypto_alg *alg)
 {
        return alg->cra_ctxsize +
@@ -1090,221 +1054,11 @@ int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
 }
 EXPORT_SYMBOL_GPL(crypto_type_has_alg);
 
-#ifdef CONFIG_CRYPTO_STATS
-void crypto_stats_init(struct crypto_alg *alg)
-{
-       memset(&alg->stats, 0, sizeof(alg->stats));
-}
-EXPORT_SYMBOL_GPL(crypto_stats_init);
-
-void crypto_stats_get(struct crypto_alg *alg)
-{
-       crypto_alg_get(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_get);
-
-void crypto_stats_aead_encrypt(unsigned int cryptlen, struct crypto_alg *alg,
-                              int ret)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.aead.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.aead.encrypt_cnt);
-               atomic64_add(cryptlen, &alg->stats.aead.encrypt_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_aead_encrypt);
-
-void crypto_stats_aead_decrypt(unsigned int cryptlen, struct crypto_alg *alg,
-                              int ret)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.aead.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.aead.decrypt_cnt);
-               atomic64_add(cryptlen, &alg->stats.aead.decrypt_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_aead_decrypt);
-
-void crypto_stats_akcipher_encrypt(unsigned int src_len, int ret,
-                                  struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.akcipher.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.akcipher.encrypt_cnt);
-               atomic64_add(src_len, &alg->stats.akcipher.encrypt_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_akcipher_encrypt);
-
-void crypto_stats_akcipher_decrypt(unsigned int src_len, int ret,
-                                  struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.akcipher.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.akcipher.decrypt_cnt);
-               atomic64_add(src_len, &alg->stats.akcipher.decrypt_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_akcipher_decrypt);
-
-void crypto_stats_akcipher_sign(int ret, struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY)
-               atomic64_inc(&alg->stats.akcipher.err_cnt);
-       else
-               atomic64_inc(&alg->stats.akcipher.sign_cnt);
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_akcipher_sign);
-
-void crypto_stats_akcipher_verify(int ret, struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY)
-               atomic64_inc(&alg->stats.akcipher.err_cnt);
-       else
-               atomic64_inc(&alg->stats.akcipher.verify_cnt);
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_akcipher_verify);
-
-void crypto_stats_compress(unsigned int slen, int ret, struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.compress.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.compress.compress_cnt);
-               atomic64_add(slen, &alg->stats.compress.compress_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_compress);
-
-void crypto_stats_decompress(unsigned int slen, int ret, struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.compress.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.compress.decompress_cnt);
-               atomic64_add(slen, &alg->stats.compress.decompress_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_decompress);
-
-void crypto_stats_ahash_update(unsigned int nbytes, int ret,
-                              struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY)
-               atomic64_inc(&alg->stats.hash.err_cnt);
-       else
-               atomic64_add(nbytes, &alg->stats.hash.hash_tlen);
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_ahash_update);
-
-void crypto_stats_ahash_final(unsigned int nbytes, int ret,
-                             struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.hash.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.hash.hash_cnt);
-               atomic64_add(nbytes, &alg->stats.hash.hash_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_ahash_final);
-
-void crypto_stats_kpp_set_secret(struct crypto_alg *alg, int ret)
-{
-       if (ret)
-               atomic64_inc(&alg->stats.kpp.err_cnt);
-       else
-               atomic64_inc(&alg->stats.kpp.setsecret_cnt);
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_kpp_set_secret);
-
-void crypto_stats_kpp_generate_public_key(struct crypto_alg *alg, int ret)
-{
-       if (ret)
-               atomic64_inc(&alg->stats.kpp.err_cnt);
-       else
-               atomic64_inc(&alg->stats.kpp.generate_public_key_cnt);
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_kpp_generate_public_key);
-
-void crypto_stats_kpp_compute_shared_secret(struct crypto_alg *alg, int ret)
-{
-       if (ret)
-               atomic64_inc(&alg->stats.kpp.err_cnt);
-       else
-               atomic64_inc(&alg->stats.kpp.compute_shared_secret_cnt);
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_kpp_compute_shared_secret);
-
-void crypto_stats_rng_seed(struct crypto_alg *alg, int ret)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY)
-               atomic64_inc(&alg->stats.rng.err_cnt);
-       else
-               atomic64_inc(&alg->stats.rng.seed_cnt);
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_rng_seed);
-
-void crypto_stats_rng_generate(struct crypto_alg *alg, unsigned int dlen,
-                              int ret)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.rng.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.rng.generate_cnt);
-               atomic64_add(dlen, &alg->stats.rng.generate_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_rng_generate);
-
-void crypto_stats_skcipher_encrypt(unsigned int cryptlen, int ret,
-                                  struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.cipher.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.cipher.encrypt_cnt);
-               atomic64_add(cryptlen, &alg->stats.cipher.encrypt_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_skcipher_encrypt);
-
-void crypto_stats_skcipher_decrypt(unsigned int cryptlen, int ret,
-                                  struct crypto_alg *alg)
-{
-       if (ret && ret != -EINPROGRESS && ret != -EBUSY) {
-               atomic64_inc(&alg->stats.cipher.err_cnt);
-       } else {
-               atomic64_inc(&alg->stats.cipher.decrypt_cnt);
-               atomic64_add(cryptlen, &alg->stats.cipher.decrypt_tlen);
-       }
-       crypto_alg_put(alg);
-}
-EXPORT_SYMBOL_GPL(crypto_stats_skcipher_decrypt);
-#endif
-
 static void __init crypto_start_tests(void)
 {
+       if (IS_ENABLED(CONFIG_CRYPTO_MANAGER_DISABLE_TESTS))
+               return;
+
        for (;;) {
                struct crypto_larval *larval = NULL;
                struct crypto_alg *q;
@@ -1338,7 +1092,7 @@ static void __init crypto_start_tests(void)
                crypto_wait_for_test(larval);
        }
 
-       static_branch_enable(&crypto_boot_test_finished);
+       set_crypto_boot_test_finished();
 }
 
 static int __init crypto_algapi_init(void)