crypto: api - Do not displace newly registered algorithms
We have a mechanism where newly registered algorithms of a higher priority can displace existing instances that use a different implementation of the same algorithm with a lower priority. Unfortunately the same mechanism can cause a newly registered algorithm to displace itself if it depends on an existing version of the same algorithm. This patch fixes this by keeping all algorithms that the newly reigstered algorithm depends on, thus protecting them from being removed. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
a367b17f34
commit
2bf2901669
1 changed files with 63 additions and 14 deletions
|
@ -81,16 +81,35 @@ static void crypto_destroy_instance(struct crypto_alg *alg)
|
||||||
crypto_tmpl_put(tmpl);
|
crypto_tmpl_put(tmpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
|
||||||
|
struct list_head *stack,
|
||||||
|
struct list_head *top,
|
||||||
|
struct list_head *secondary_spawns)
|
||||||
|
{
|
||||||
|
struct crypto_spawn *spawn, *n;
|
||||||
|
|
||||||
|
if (list_empty(stack))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
spawn = list_first_entry(stack, struct crypto_spawn, list);
|
||||||
|
n = list_entry(spawn->list.next, struct crypto_spawn, list);
|
||||||
|
|
||||||
|
if (spawn->alg && &n->list != stack && !n->alg)
|
||||||
|
n->alg = (n->list.next == stack) ? alg :
|
||||||
|
&list_entry(n->list.next, struct crypto_spawn,
|
||||||
|
list)->inst->alg;
|
||||||
|
|
||||||
|
list_move(&spawn->list, secondary_spawns);
|
||||||
|
|
||||||
|
return &n->list == stack ? top : &n->inst->alg.cra_users;
|
||||||
|
}
|
||||||
|
|
||||||
static void crypto_remove_spawn(struct crypto_spawn *spawn,
|
static void crypto_remove_spawn(struct crypto_spawn *spawn,
|
||||||
struct list_head *list,
|
struct list_head *list)
|
||||||
struct list_head *secondary_spawns)
|
|
||||||
{
|
{
|
||||||
struct crypto_instance *inst = spawn->inst;
|
struct crypto_instance *inst = spawn->inst;
|
||||||
struct crypto_template *tmpl = inst->tmpl;
|
struct crypto_template *tmpl = inst->tmpl;
|
||||||
|
|
||||||
list_del_init(&spawn->list);
|
|
||||||
spawn->alg = NULL;
|
|
||||||
|
|
||||||
if (crypto_is_dead(&inst->alg))
|
if (crypto_is_dead(&inst->alg))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -106,25 +125,55 @@ static void crypto_remove_spawn(struct crypto_spawn *spawn,
|
||||||
hlist_del(&inst->list);
|
hlist_del(&inst->list);
|
||||||
inst->alg.cra_destroy = crypto_destroy_instance;
|
inst->alg.cra_destroy = crypto_destroy_instance;
|
||||||
|
|
||||||
list_splice(&inst->alg.cra_users, secondary_spawns);
|
BUG_ON(!list_empty(&inst->alg.cra_users));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void crypto_remove_spawns(struct list_head *spawns,
|
static void crypto_remove_spawns(struct crypto_alg *alg,
|
||||||
struct list_head *list, u32 new_type)
|
struct list_head *list,
|
||||||
|
struct crypto_alg *nalg)
|
||||||
{
|
{
|
||||||
|
u32 new_type = (nalg ?: alg)->cra_flags;
|
||||||
struct crypto_spawn *spawn, *n;
|
struct crypto_spawn *spawn, *n;
|
||||||
LIST_HEAD(secondary_spawns);
|
LIST_HEAD(secondary_spawns);
|
||||||
|
struct list_head *spawns;
|
||||||
|
LIST_HEAD(stack);
|
||||||
|
LIST_HEAD(top);
|
||||||
|
|
||||||
|
spawns = &alg->cra_users;
|
||||||
list_for_each_entry_safe(spawn, n, spawns, list) {
|
list_for_each_entry_safe(spawn, n, spawns, list) {
|
||||||
if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
|
if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
crypto_remove_spawn(spawn, list, &secondary_spawns);
|
list_move(&spawn->list, &top);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!list_empty(&secondary_spawns)) {
|
spawns = ⊤
|
||||||
list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
|
do {
|
||||||
crypto_remove_spawn(spawn, list, &secondary_spawns);
|
while (!list_empty(spawns)) {
|
||||||
|
struct crypto_instance *inst;
|
||||||
|
|
||||||
|
spawn = list_first_entry(spawns, struct crypto_spawn,
|
||||||
|
list);
|
||||||
|
inst = spawn->inst;
|
||||||
|
|
||||||
|
BUG_ON(&inst->alg == alg);
|
||||||
|
|
||||||
|
list_move(&spawn->list, &stack);
|
||||||
|
|
||||||
|
if (&inst->alg == nalg)
|
||||||
|
break;
|
||||||
|
|
||||||
|
spawn->alg = NULL;
|
||||||
|
spawns = &inst->alg.cra_users;
|
||||||
|
}
|
||||||
|
} while ((spawns = crypto_more_spawns(alg, &stack, &top,
|
||||||
|
&secondary_spawns)));
|
||||||
|
|
||||||
|
list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
|
||||||
|
if (spawn->alg)
|
||||||
|
list_move(&spawn->list, &spawn->alg->cra_users);
|
||||||
|
else
|
||||||
|
crypto_remove_spawn(spawn, list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +307,7 @@ void crypto_alg_tested(const char *name, int err)
|
||||||
q->cra_priority > alg->cra_priority)
|
q->cra_priority > alg->cra_priority)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags);
|
crypto_remove_spawns(q, &list, alg);
|
||||||
}
|
}
|
||||||
|
|
||||||
complete:
|
complete:
|
||||||
|
@ -330,7 +379,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
|
||||||
|
|
||||||
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
|
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
|
||||||
list_del_init(&alg->cra_list);
|
list_del_init(&alg->cra_list);
|
||||||
crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
|
crypto_remove_spawns(alg, list, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue