aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-01-27 22:09:59 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2009-01-27 22:09:59 -0500
commitb8e15992b420d09dae831125a623c474c8637cee (patch)
treefd482644b09b3c8fe580f596f134e07cac937794
parent516280e735b034216de97eb7ba080ec6acbfc58f (diff)
crypto: api - Fix algorithm test race that broke aead initialisation
When we complete a test we'll notify everyone waiting on it, drop the mutex, and then remove the test larval (after reacquiring the mutex). If one of the notified parties tries to register another algorithm with the same driver name prior to the removal of the test larval, they will fail with EEXIST as only one algorithm of a given name can be tested at any time. This broke the initialisation of aead and givcipher algorithms as they will register two algorithms with the same driver name, in sequence. This patch fixes the problem by marking the larval as dead before we drop the mutex, and also ignoring all dead or dying algorithms on the registration path. Tested-by: Andreas Steffen <andreas.steffen@strongswan.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/algapi.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 7c41e7405c41..56c62e2858d5 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -149,6 +149,9 @@ static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
149 if (q == alg) 149 if (q == alg)
150 goto err; 150 goto err;
151 151
152 if (crypto_is_moribund(q))
153 continue;
154
152 if (crypto_is_larval(q)) { 155 if (crypto_is_larval(q)) {
153 if (!strcmp(alg->cra_driver_name, q->cra_driver_name)) 156 if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
154 goto err; 157 goto err;
@@ -197,7 +200,7 @@ void crypto_alg_tested(const char *name, int err)
197 200
198 down_write(&crypto_alg_sem); 201 down_write(&crypto_alg_sem);
199 list_for_each_entry(q, &crypto_alg_list, cra_list) { 202 list_for_each_entry(q, &crypto_alg_list, cra_list) {
200 if (!crypto_is_larval(q)) 203 if (crypto_is_moribund(q) || !crypto_is_larval(q))
201 continue; 204 continue;
202 205
203 test = (struct crypto_larval *)q; 206 test = (struct crypto_larval *)q;
@@ -210,6 +213,7 @@ void crypto_alg_tested(const char *name, int err)
210 goto unlock; 213 goto unlock;
211 214
212found: 215found:
216 q->cra_flags |= CRYPTO_ALG_DEAD;
213 alg = test->adult; 217 alg = test->adult;
214 if (err || list_empty(&alg->cra_list)) 218 if (err || list_empty(&alg->cra_list))
215 goto complete; 219 goto complete;