crypto: api - Add crypto_clone_tfm
authorHerbert Xu <herbert@gondor.apana.org.au>
Thu, 13 Apr 2023 06:24:17 +0000 (14:24 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 20 Apr 2023 10:20:04 +0000 (18:20 +0800)
This patch adds the helper crypto_clone_tfm.  The purpose is to
allocate a tfm object with GFP_ATOMIC.  As we cannot sleep, the
object has to be cloned from an existing tfm object.

This allows code paths that cannot otherwise allocate a crypto_tfm
object to do so.  Once a new tfm has been obtained its key could
then be changed without impacting other users.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/api.c
crypto/internal.h

index f509d73fa682986622732b38a39fec6e3464e145..d375e8cd770d17db043c61c6601aaa9cf8e1d73d 100644 (file)
@@ -488,28 +488,44 @@ err:
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_base);
 
-void *crypto_create_tfm_node(struct crypto_alg *alg,
-                       const struct crypto_type *frontend,
-                       int node)
+static void *crypto_alloc_tfmmem(struct crypto_alg *alg,
+                                const struct crypto_type *frontend, int node,
+                                gfp_t gfp)
 {
-       char *mem;
-       struct crypto_tfm *tfm = NULL;
+       struct crypto_tfm *tfm;
        unsigned int tfmsize;
        unsigned int total;
-       int err = -ENOMEM;
+       char *mem;
 
        tfmsize = frontend->tfmsize;
        total = tfmsize + sizeof(*tfm) + frontend->extsize(alg);
 
-       mem = kzalloc_node(total, GFP_KERNEL, node);
+       mem = kzalloc_node(total, gfp, node);
        if (mem == NULL)
-               goto out_err;
+               return ERR_PTR(-ENOMEM);
 
        tfm = (struct crypto_tfm *)(mem + tfmsize);
        tfm->__crt_alg = alg;
        tfm->node = node;
        refcount_set(&tfm->refcnt, 1);
 
+       return mem;
+}
+
+void *crypto_create_tfm_node(struct crypto_alg *alg,
+                            const struct crypto_type *frontend,
+                            int node)
+{
+       struct crypto_tfm *tfm;
+       char *mem;
+       int err;
+
+       mem = crypto_alloc_tfmmem(alg, frontend, node, GFP_KERNEL);
+       if (IS_ERR(mem))
+               goto out;
+
+       tfm = (struct crypto_tfm *)(mem + frontend->tfmsize);
+
        err = frontend->init_tfm(tfm);
        if (err)
                goto out_free_tfm;
@@ -525,13 +541,38 @@ out_free_tfm:
        if (err == -EAGAIN)
                crypto_shoot_alg(alg);
        kfree(mem);
-out_err:
        mem = ERR_PTR(err);
 out:
        return mem;
 }
 EXPORT_SYMBOL_GPL(crypto_create_tfm_node);
 
+void *crypto_clone_tfm(const struct crypto_type *frontend,
+                      struct crypto_tfm *otfm)
+{
+       struct crypto_alg *alg = otfm->__crt_alg;
+       struct crypto_tfm *tfm;
+       char *mem;
+
+       mem = ERR_PTR(-ESTALE);
+       if (unlikely(!crypto_mod_get(alg)))
+               goto out;
+
+       mem = crypto_alloc_tfmmem(alg, frontend, otfm->node, GFP_ATOMIC);
+       if (IS_ERR(mem)) {
+               crypto_mod_put(alg);
+               goto out;
+       }
+
+       tfm = (struct crypto_tfm *)(mem + frontend->tfmsize);
+       tfm->crt_flags = otfm->crt_flags;
+       tfm->exit = otfm->exit;
+
+out:
+       return mem;
+}
+EXPORT_SYMBOL_GPL(crypto_clone_tfm);
+
 struct crypto_alg *crypto_find_alg(const char *alg_name,
                                   const struct crypto_type *frontend,
                                   u32 type, u32 mask)
index 5eee009ee494d02cf53307e3e008e4b3f6bd6cf0..8dd746b1130b6ef588665bee1ceeb9566efd4c5f 100644 (file)
@@ -106,6 +106,8 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
                                      u32 mask);
 void *crypto_create_tfm_node(struct crypto_alg *alg,
                        const struct crypto_type *frontend, int node);
+void *crypto_clone_tfm(const struct crypto_type *frontend,
+                      struct crypto_tfm *otfm);
 
 static inline void *crypto_create_tfm(struct crypto_alg *alg,
                        const struct crypto_type *frontend)