summaryrefslogtreecommitdiffstats
path: root/crypto/algapi.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2019-12-07 15:15:17 +0100
committerHerbert Xu <herbert@gondor.apana.org.au>2019-12-11 09:48:39 +0100
commit4f87ee118d16b4b2116a477229573ed5003b0d78 (patch)
treea57cbf2d901e3de04719901be7d194d561613a97 /crypto/algapi.c
parentcrypto: api - Fix race condition in crypto_spawn_alg (diff)
downloadlinux-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.c22
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;
}