crypto: api - Do not zap spawn->alg
authorHerbert Xu <herbert@gondor.apana.org.au>
Sat, 7 Dec 2019 14:15:17 +0000 (22:15 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Wed, 11 Dec 2019 08:48:39 +0000 (16:48 +0800)
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>
crypto/algapi.c
include/crypto/algapi.h

index 54e844a..e858946 100644 (file)
@@ -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;
        }
index 5cd846d..771a295 100644 (file)
@@ -70,6 +70,7 @@ struct crypto_spawn {
        struct crypto_instance *inst;
        const struct crypto_type *frontend;
        u32 mask;
+       bool dead;
 };
 
 struct crypto_queue {