Commit 4f87ee11 authored by Herbert Xu's avatar Herbert Xu

crypto: api - Do not zap spawn->alg

Currently when a spawn is removed we will zap its alg field.
This is racy because the spawn could belong to an unregistered
instance which may dereference the spawn->alg field.

This patch fixes this by keeping spawn->alg constant and instead
adding a new spawn->dead field to indicate that a spawn is going
away.
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 73669cc5
...@@ -93,15 +93,17 @@ static struct list_head *crypto_more_spawns(struct crypto_alg *alg, ...@@ -93,15 +93,17 @@ static struct list_head *crypto_more_spawns(struct crypto_alg *alg,
if (!spawn) if (!spawn)
return NULL; return NULL;
n = list_next_entry(spawn, list); n = list_prev_entry(spawn, list);
list_move(&spawn->list, secondary_spawns);
if (spawn->alg && &n->list != stack && !n->alg) if (list_is_last(&n->list, stack))
n->alg = (n->list.next == stack) ? alg : return top;
&list_next_entry(n, list)->inst->alg;
list_move(&spawn->list, secondary_spawns); n = list_next_entry(n, list);
if (!spawn->dead)
n->dead = false;
return &n->list == stack ? top : &n->inst->alg.cra_users; return &n->inst->alg.cra_users;
} }
static void crypto_remove_instance(struct crypto_instance *inst, static void crypto_remove_instance(struct crypto_instance *inst,
...@@ -160,7 +162,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, ...@@ -160,7 +162,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
if (&inst->alg == nalg) if (&inst->alg == nalg)
break; break;
spawn->alg = NULL; spawn->dead = true;
spawns = &inst->alg.cra_users; spawns = &inst->alg.cra_users;
/* /*
...@@ -179,7 +181,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, ...@@ -179,7 +181,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list,
&secondary_spawns))); &secondary_spawns)));
list_for_each_entry_safe(spawn, n, &secondary_spawns, list) { list_for_each_entry_safe(spawn, n, &secondary_spawns, list) {
if (spawn->alg) if (!spawn->dead)
list_move(&spawn->list, &spawn->alg->cra_users); list_move(&spawn->list, &spawn->alg->cra_users);
else else
crypto_remove_instance(spawn->inst, list); crypto_remove_instance(spawn->inst, list);
...@@ -670,7 +672,7 @@ EXPORT_SYMBOL_GPL(crypto_grab_spawn); ...@@ -670,7 +672,7 @@ EXPORT_SYMBOL_GPL(crypto_grab_spawn);
void crypto_drop_spawn(struct crypto_spawn *spawn) void crypto_drop_spawn(struct crypto_spawn *spawn)
{ {
down_write(&crypto_alg_sem); down_write(&crypto_alg_sem);
if (spawn->alg) if (!spawn->dead)
list_del(&spawn->list); list_del(&spawn->list);
up_write(&crypto_alg_sem); up_write(&crypto_alg_sem);
} }
...@@ -682,7 +684,7 @@ static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn) ...@@ -682,7 +684,7 @@ static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn)
down_read(&crypto_alg_sem); down_read(&crypto_alg_sem);
alg = spawn->alg; alg = spawn->alg;
if (alg && !crypto_mod_get(alg)) { if (!spawn->dead && !crypto_mod_get(alg)) {
alg->cra_flags |= CRYPTO_ALG_DYING; alg->cra_flags |= CRYPTO_ALG_DYING;
alg = NULL; alg = NULL;
} }
......
...@@ -70,6 +70,7 @@ struct crypto_spawn { ...@@ -70,6 +70,7 @@ struct crypto_spawn {
struct crypto_instance *inst; struct crypto_instance *inst;
const struct crypto_type *frontend; const struct crypto_type *frontend;
u32 mask; u32 mask;
bool dead;
}; };
struct crypto_queue { struct crypto_queue {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment