forked from Minki/linux
eed93e0ce3
Currently we manually filter out internal algorithms using a list in testmgr. This is dangerous as internal algorithms cannot be safely used even by testmgr. This patch ensures that they're never processed by testmgr at all. This patch also removes an obsolete bypass for nivciphers which no longer exist. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
303 lines
6.0 KiB
C
303 lines
6.0 KiB
C
/*
|
|
* Create default crypto algorithm instances.
|
|
*
|
|
* Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
*/
|
|
|
|
#include <crypto/internal/aead.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/err.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/module.h>
|
|
#include <linux/notifier.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
|
|
#include "internal.h"
|
|
|
|
struct cryptomgr_param {
|
|
struct rtattr *tb[CRYPTO_MAX_ATTRS + 2];
|
|
|
|
struct {
|
|
struct rtattr attr;
|
|
struct crypto_attr_type data;
|
|
} type;
|
|
|
|
union {
|
|
struct rtattr attr;
|
|
struct {
|
|
struct rtattr attr;
|
|
struct crypto_attr_alg data;
|
|
} alg;
|
|
struct {
|
|
struct rtattr attr;
|
|
struct crypto_attr_u32 data;
|
|
} nu32;
|
|
} attrs[CRYPTO_MAX_ATTRS];
|
|
|
|
char template[CRYPTO_MAX_ALG_NAME];
|
|
|
|
struct crypto_larval *larval;
|
|
|
|
u32 otype;
|
|
u32 omask;
|
|
};
|
|
|
|
struct crypto_test_param {
|
|
char driver[CRYPTO_MAX_ALG_NAME];
|
|
char alg[CRYPTO_MAX_ALG_NAME];
|
|
u32 type;
|
|
};
|
|
|
|
static int cryptomgr_probe(void *data)
|
|
{
|
|
struct cryptomgr_param *param = data;
|
|
struct crypto_template *tmpl;
|
|
struct crypto_instance *inst;
|
|
int err;
|
|
|
|
tmpl = crypto_lookup_template(param->template);
|
|
if (!tmpl)
|
|
goto out;
|
|
|
|
do {
|
|
if (tmpl->create) {
|
|
err = tmpl->create(tmpl, param->tb);
|
|
continue;
|
|
}
|
|
|
|
inst = tmpl->alloc(param->tb);
|
|
if (IS_ERR(inst))
|
|
err = PTR_ERR(inst);
|
|
else if ((err = crypto_register_instance(tmpl, inst)))
|
|
tmpl->free(inst);
|
|
} while (err == -EAGAIN && !signal_pending(current));
|
|
|
|
crypto_tmpl_put(tmpl);
|
|
|
|
out:
|
|
complete_all(¶m->larval->completion);
|
|
crypto_alg_put(¶m->larval->alg);
|
|
kfree(param);
|
|
module_put_and_exit(0);
|
|
}
|
|
|
|
static int cryptomgr_schedule_probe(struct crypto_larval *larval)
|
|
{
|
|
struct task_struct *thread;
|
|
struct cryptomgr_param *param;
|
|
const char *name = larval->alg.cra_name;
|
|
const char *p;
|
|
unsigned int len;
|
|
int i;
|
|
|
|
if (!try_module_get(THIS_MODULE))
|
|
goto err;
|
|
|
|
param = kzalloc(sizeof(*param), GFP_KERNEL);
|
|
if (!param)
|
|
goto err_put_module;
|
|
|
|
for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
|
|
;
|
|
|
|
len = p - name;
|
|
if (!len || *p != '(')
|
|
goto err_free_param;
|
|
|
|
memcpy(param->template, name, len);
|
|
|
|
i = 0;
|
|
for (;;) {
|
|
int notnum = 0;
|
|
|
|
name = ++p;
|
|
len = 0;
|
|
|
|
for (; isalnum(*p) || *p == '-' || *p == '_'; p++)
|
|
notnum |= !isdigit(*p);
|
|
|
|
if (*p == '(') {
|
|
int recursion = 0;
|
|
|
|
for (;;) {
|
|
if (!*++p)
|
|
goto err_free_param;
|
|
if (*p == '(')
|
|
recursion++;
|
|
else if (*p == ')' && !recursion--)
|
|
break;
|
|
}
|
|
|
|
notnum = 1;
|
|
p++;
|
|
}
|
|
|
|
len = p - name;
|
|
if (!len)
|
|
goto err_free_param;
|
|
|
|
if (notnum) {
|
|
param->attrs[i].alg.attr.rta_len =
|
|
sizeof(param->attrs[i].alg);
|
|
param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG;
|
|
memcpy(param->attrs[i].alg.data.name, name, len);
|
|
} else {
|
|
param->attrs[i].nu32.attr.rta_len =
|
|
sizeof(param->attrs[i].nu32);
|
|
param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32;
|
|
param->attrs[i].nu32.data.num =
|
|
simple_strtol(name, NULL, 0);
|
|
}
|
|
|
|
param->tb[i + 1] = ¶m->attrs[i].attr;
|
|
i++;
|
|
|
|
if (i >= CRYPTO_MAX_ATTRS)
|
|
goto err_free_param;
|
|
|
|
if (*p == ')')
|
|
break;
|
|
|
|
if (*p != ',')
|
|
goto err_free_param;
|
|
}
|
|
|
|
if (!i)
|
|
goto err_free_param;
|
|
|
|
param->tb[i + 1] = NULL;
|
|
|
|
param->type.attr.rta_len = sizeof(param->type);
|
|
param->type.attr.rta_type = CRYPTOA_TYPE;
|
|
param->type.data.type = larval->alg.cra_flags & ~CRYPTO_ALG_TESTED;
|
|
param->type.data.mask = larval->mask & ~CRYPTO_ALG_TESTED;
|
|
param->tb[0] = ¶m->type.attr;
|
|
|
|
param->otype = larval->alg.cra_flags;
|
|
param->omask = larval->mask;
|
|
|
|
crypto_alg_get(&larval->alg);
|
|
param->larval = larval;
|
|
|
|
thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe");
|
|
if (IS_ERR(thread))
|
|
goto err_put_larval;
|
|
|
|
wait_for_completion_interruptible(&larval->completion);
|
|
|
|
return NOTIFY_STOP;
|
|
|
|
err_put_larval:
|
|
crypto_alg_put(&larval->alg);
|
|
err_free_param:
|
|
kfree(param);
|
|
err_put_module:
|
|
module_put(THIS_MODULE);
|
|
err:
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static int cryptomgr_test(void *data)
|
|
{
|
|
struct crypto_test_param *param = data;
|
|
u32 type = param->type;
|
|
int err = 0;
|
|
|
|
#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
|
|
goto skiptest;
|
|
#endif
|
|
|
|
if (type & CRYPTO_ALG_TESTED)
|
|
goto skiptest;
|
|
|
|
err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED);
|
|
|
|
skiptest:
|
|
crypto_alg_tested(param->driver, err);
|
|
|
|
kfree(param);
|
|
module_put_and_exit(0);
|
|
}
|
|
|
|
static int cryptomgr_schedule_test(struct crypto_alg *alg)
|
|
{
|
|
struct task_struct *thread;
|
|
struct crypto_test_param *param;
|
|
u32 type;
|
|
|
|
if (!try_module_get(THIS_MODULE))
|
|
goto err;
|
|
|
|
param = kzalloc(sizeof(*param), GFP_KERNEL);
|
|
if (!param)
|
|
goto err_put_module;
|
|
|
|
memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver));
|
|
memcpy(param->alg, alg->cra_name, sizeof(param->alg));
|
|
type = alg->cra_flags;
|
|
|
|
/* Do not test internal algorithms. */
|
|
if (type & CRYPTO_ALG_INTERNAL)
|
|
type |= CRYPTO_ALG_TESTED;
|
|
|
|
param->type = type;
|
|
|
|
thread = kthread_run(cryptomgr_test, param, "cryptomgr_test");
|
|
if (IS_ERR(thread))
|
|
goto err_free_param;
|
|
|
|
return NOTIFY_STOP;
|
|
|
|
err_free_param:
|
|
kfree(param);
|
|
err_put_module:
|
|
module_put(THIS_MODULE);
|
|
err:
|
|
return NOTIFY_OK;
|
|
}
|
|
|
|
static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
|
|
void *data)
|
|
{
|
|
switch (msg) {
|
|
case CRYPTO_MSG_ALG_REQUEST:
|
|
return cryptomgr_schedule_probe(data);
|
|
case CRYPTO_MSG_ALG_REGISTER:
|
|
return cryptomgr_schedule_test(data);
|
|
}
|
|
|
|
return NOTIFY_DONE;
|
|
}
|
|
|
|
static struct notifier_block cryptomgr_notifier = {
|
|
.notifier_call = cryptomgr_notify,
|
|
};
|
|
|
|
static int __init cryptomgr_init(void)
|
|
{
|
|
return crypto_register_notifier(&cryptomgr_notifier);
|
|
}
|
|
|
|
static void __exit cryptomgr_exit(void)
|
|
{
|
|
int err = crypto_unregister_notifier(&cryptomgr_notifier);
|
|
BUG_ON(err);
|
|
}
|
|
|
|
subsys_initcall(cryptomgr_init);
|
|
module_exit(cryptomgr_exit);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DESCRIPTION("Crypto Algorithm Manager");
|