aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/api.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/api.c')
-rw-r--r--crypto/api.c105
1 files changed, 83 insertions, 22 deletions
diff --git a/crypto/api.c b/crypto/api.c
index 7d71a9b10e5f..64f2d365a8e9 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -12,6 +12,7 @@
#include <linux/err.h>
#include <linux/errno.h>
+#include <linux/jump_label.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/module.h>
@@ -30,6 +31,9 @@ EXPORT_SYMBOL_GPL(crypto_alg_sem);
BLOCKING_NOTIFIER_HEAD(crypto_chain);
EXPORT_SYMBOL_GPL(crypto_chain);
+DEFINE_STATIC_KEY_FALSE(crypto_boot_test_finished);
+EXPORT_SYMBOL_GPL(crypto_boot_test_finished);
+
static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg);
struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
@@ -47,11 +51,6 @@ void crypto_mod_put(struct crypto_alg *alg)
}
EXPORT_SYMBOL_GPL(crypto_mod_put);
-static inline int crypto_is_test_larval(struct crypto_larval *larval)
-{
- return larval->alg.cra_driver_name[0];
-}
-
static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type,
u32 mask)
{
@@ -115,7 +114,7 @@ struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask)
larval->alg.cra_priority = -1;
larval->alg.cra_destroy = crypto_larval_destroy;
- strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
+ strscpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
init_completion(&larval->completion);
return larval;
@@ -163,11 +162,52 @@ void crypto_larval_kill(struct crypto_alg *alg)
}
EXPORT_SYMBOL_GPL(crypto_larval_kill);
+void crypto_wait_for_test(struct crypto_larval *larval)
+{
+ int err;
+
+ err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
+ if (WARN_ON_ONCE(err != NOTIFY_STOP))
+ goto out;
+
+ 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);
+}
+EXPORT_SYMBOL_GPL(crypto_wait_for_test);
+
+static void crypto_start_test(struct crypto_larval *larval)
+{
+ if (!crypto_is_test_larval(larval))
+ return;
+
+ if (larval->test_started)
+ return;
+
+ down_write(&crypto_alg_sem);
+ if (larval->test_started) {
+ up_write(&crypto_alg_sem);
+ return;
+ }
+
+ larval->test_started = true;
+ up_write(&crypto_alg_sem);
+
+ crypto_wait_for_test(larval);
+}
+
static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
{
struct crypto_larval *larval = (void *)alg;
long timeout;
+ if (!static_branch_likely(&crypto_boot_test_finished))
+ crypto_start_test(larval);
+
timeout = wait_for_completion_killable_timeout(
&larval->completion, 60 * HZ);
@@ -183,6 +223,8 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
else if (crypto_is_test_larval(larval) &&
!(alg->cra_flags & CRYPTO_ALG_TESTED))
alg = ERR_PTR(-EAGAIN);
+ else if (alg->cra_flags & CRYPTO_ALG_FIPS_INTERNAL)
+ alg = ERR_PTR(-EAGAIN);
else if (!crypto_mod_get(alg))
alg = ERR_PTR(-EAGAIN);
crypto_mod_put(&larval->alg);
@@ -193,6 +235,7 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
u32 mask)
{
+ const u32 fips = CRYPTO_ALG_FIPS_INTERNAL;
struct crypto_alg *alg;
u32 test = 0;
@@ -200,8 +243,20 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
test |= CRYPTO_ALG_TESTED;
down_read(&crypto_alg_sem);
- alg = __crypto_alg_lookup(name, type | test, mask | test);
- if (!alg && test) {
+ alg = __crypto_alg_lookup(name, (type | test) & ~fips,
+ (mask | test) & ~fips);
+ if (alg) {
+ if (((type | mask) ^ fips) & fips)
+ mask |= fips;
+ mask &= fips;
+
+ if (!crypto_is_larval(alg) &&
+ ((type ^ alg->cra_flags) & mask)) {
+ /* Algorithm is disallowed in FIPS mode. */
+ crypto_mod_put(alg);
+ alg = ERR_PTR(-ENOENT);
+ }
+ } else if (test) {
alg = __crypto_alg_lookup(name, type, mask);
if (alg && !crypto_is_larval(alg)) {
/* Test failed */
@@ -266,7 +321,7 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
/*
* If the internal flag is set for a cipher, require a caller to
- * to invoke the cipher with the internal flag to use that cipher.
+ * invoke the cipher with the internal flag to use that cipher.
* Also, if a caller wants to allocate a cipher that may or may
* not be an internal cipher, use type | CRYPTO_ALG_INTERNAL and
* !(mask & CRYPTO_ALG_INTERNAL).
@@ -333,12 +388,13 @@ static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask)
return len;
}
-static void crypto_shoot_alg(struct crypto_alg *alg)
+void crypto_shoot_alg(struct crypto_alg *alg)
{
down_write(&crypto_alg_sem);
alg->cra_flags |= CRYPTO_ALG_DYING;
up_write(&crypto_alg_sem);
}
+EXPORT_SYMBOL_GPL(crypto_shoot_alg);
struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
u32 mask)
@@ -432,8 +488,9 @@ err:
}
EXPORT_SYMBOL_GPL(crypto_alloc_base);
-void *crypto_create_tfm(struct crypto_alg *alg,
- const struct crypto_type *frontend)
+void *crypto_create_tfm_node(struct crypto_alg *alg,
+ const struct crypto_type *frontend,
+ int node)
{
char *mem;
struct crypto_tfm *tfm = NULL;
@@ -444,12 +501,13 @@ void *crypto_create_tfm(struct crypto_alg *alg,
tfmsize = frontend->tfmsize;
total = tfmsize + sizeof(*tfm) + frontend->extsize(alg);
- mem = kzalloc(total, GFP_KERNEL);
+ mem = kzalloc_node(total, GFP_KERNEL, node);
if (mem == NULL)
goto out_err;
tfm = (struct crypto_tfm *)(mem + tfmsize);
tfm->__crt_alg = alg;
+ tfm->node = node;
err = frontend->init_tfm(tfm);
if (err)
@@ -471,7 +529,7 @@ out_err:
out:
return mem;
}
-EXPORT_SYMBOL_GPL(crypto_create_tfm);
+EXPORT_SYMBOL_GPL(crypto_create_tfm_node);
struct crypto_alg *crypto_find_alg(const char *alg_name,
const struct crypto_type *frontend,
@@ -489,11 +547,13 @@ struct crypto_alg *crypto_find_alg(const char *alg_name,
EXPORT_SYMBOL_GPL(crypto_find_alg);
/*
- * crypto_alloc_tfm - Locate algorithm and allocate transform
+ * crypto_alloc_tfm_node - Locate algorithm and allocate transform
* @alg_name: Name of algorithm
* @frontend: Frontend algorithm type
* @type: Type of algorithm
* @mask: Mask for type comparison
+ * @node: NUMA node in which users desire to put requests, if node is
+ * NUMA_NO_NODE, it means users have no special requirement.
*
* crypto_alloc_tfm() will first attempt to locate an already loaded
* algorithm. If that fails and the kernel supports dynamically loadable
@@ -508,8 +568,10 @@ EXPORT_SYMBOL_GPL(crypto_find_alg);
*
* In case of error the return value is an error pointer.
*/
-void *crypto_alloc_tfm(const char *alg_name,
- const struct crypto_type *frontend, u32 type, u32 mask)
+
+void *crypto_alloc_tfm_node(const char *alg_name,
+ const struct crypto_type *frontend, u32 type, u32 mask,
+ int node)
{
void *tfm;
int err;
@@ -523,7 +585,7 @@ void *crypto_alloc_tfm(const char *alg_name,
goto err;
}
- tfm = crypto_create_tfm(alg, frontend);
+ tfm = crypto_create_tfm_node(alg, frontend, node);
if (!IS_ERR(tfm))
return tfm;
@@ -541,7 +603,7 @@ err:
return ERR_PTR(err);
}
-EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
+EXPORT_SYMBOL_GPL(crypto_alloc_tfm_node);
/*
* crypto_destroy_tfm - Free crypto transform
@@ -555,7 +617,7 @@ void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
{
struct crypto_alg *alg;
- if (unlikely(!mem))
+ if (IS_ERR_OR_NULL(mem))
return;
alg = tfm->__crt_alg;
@@ -564,7 +626,7 @@ void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
alg->cra_exit(tfm);
crypto_exit_ops(tfm);
crypto_mod_put(alg);
- kzfree(mem);
+ kfree_sensitive(mem);
}
EXPORT_SYMBOL_GPL(crypto_destroy_tfm);
@@ -596,4 +658,3 @@ EXPORT_SYMBOL_GPL(crypto_req_done);
MODULE_DESCRIPTION("Cryptographic core API");
MODULE_LICENSE("GPL");
-MODULE_SOFTDEP("pre: cryptomgr");