diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2019-12-07 15:15:17 +0100 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-12-11 09:48:39 +0100 |
commit | 4f87ee118d16b4b2116a477229573ed5003b0d78 (patch) | |
tree | a57cbf2d901e3de04719901be7d194d561613a97 /crypto/algapi.c | |
parent | crypto: api - Fix race condition in crypto_spawn_alg (diff) | |
download | linux-4f87ee118d16b4b2116a477229573ed5003b0d78.tar.xz linux-4f87ee118d16b4b2116a477229573ed5003b0d78.zip |
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: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r-- | crypto/algapi.c | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c index 54e844ad9364..e858946adeed 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -93,15 +93,17 @@ static struct list_head *crypto_more_spawns(struct crypto_alg *alg, if (!spawn) 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) - n->alg = (n->list.next == stack) ? alg : - &list_next_entry(n, list)->inst->alg; + if (list_is_last(&n->list, stack)) + return top; - 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, @@ -160,7 +162,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, if (&inst->alg == nalg) break; - spawn->alg = NULL; + spawn->dead = true; spawns = &inst->alg.cra_users; /* @@ -179,7 +181,7 @@ void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, &secondary_spawns))); list_for_each_entry_safe(spawn, n, &secondary_spawns, list) { - if (spawn->alg) + if (!spawn->dead) list_move(&spawn->list, &spawn->alg->cra_users); else crypto_remove_instance(spawn->inst, list); @@ -670,7 +672,7 @@ EXPORT_SYMBOL_GPL(crypto_grab_spawn); void crypto_drop_spawn(struct crypto_spawn *spawn) { down_write(&crypto_alg_sem); - if (spawn->alg) + if (!spawn->dead) list_del(&spawn->list); up_write(&crypto_alg_sem); } @@ -682,7 +684,7 @@ static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn) down_read(&crypto_alg_sem); alg = spawn->alg; - if (alg && !crypto_mod_get(alg)) { + if (!spawn->dead && !crypto_mod_get(alg)) { alg->cra_flags |= CRYPTO_ALG_DYING; alg = NULL; } |