Skip to content

Commit

Permalink
crypto: api - Do not displace newly registered algorithms
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
herbertx committed Aug 31, 2009
1 parent a367b17 commit 2bf2901
Showing 1 changed file with 63 additions and 14 deletions.
77 changes: 63 additions & 14 deletions crypto/algapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,35 @@ static void crypto_destroy_instance(struct crypto_alg *alg)
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,
struct list_head *list,
struct list_head *secondary_spawns)
struct list_head *list)
{
struct crypto_instance *inst = spawn->inst;
struct crypto_template *tmpl = inst->tmpl;

list_del_init(&spawn->list);
spawn->alg = NULL;

if (crypto_is_dead(&inst->alg))
return;

Expand All @@ -106,25 +125,55 @@ static void crypto_remove_spawn(struct crypto_spawn *spawn,
hlist_del(&inst->list);
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,
struct list_head *list, u32 new_type)
static void crypto_remove_spawns(struct crypto_alg *alg,
struct list_head *list,
struct crypto_alg *nalg)
{
u32 new_type = (nalg ?: alg)->cra_flags;
struct crypto_spawn *spawn, *n;
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) {
if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
continue;

crypto_remove_spawn(spawn, list, &secondary_spawns);
list_move(&spawn->list, &top);
}

while (!list_empty(&secondary_spawns)) {
list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
crypto_remove_spawn(spawn, list, &secondary_spawns);
spawns = &top;
do {
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);
}
}

Expand Down Expand Up @@ -258,7 +307,7 @@ void crypto_alg_tested(const char *name, int err)
q->cra_priority > alg->cra_priority)
continue;

crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags);
crypto_remove_spawns(q, &list, alg);
}

complete:
Expand Down Expand Up @@ -330,7 +379,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)

crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
list_del_init(&alg->cra_list);
crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
crypto_remove_spawns(alg, list, NULL);

return 0;
}
Expand Down

0 comments on commit 2bf2901

Please sign in to comment.