crypto: skcipher - Avoid infinite loop when cipher fails selftest
Herbert Xu [Wed, 18 Feb 2009 12:33:55 +0000 (20:33 +0800)]
When an skcipher constructed through crypto_givcipher_default fails
its selftest, we'll loop forever trying to construct new skcipher
objects but failing because it already exists.

The crux of the issue is that once a givcipher fails the selftest,
we'll ignore it on the next run through crypto_skcipher_lookup and
attempt to construct a new givcipher.

We should instead return an error to the caller if we find a
givcipher that has failed the test.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

crypto/ablkcipher.c
crypto/blkcipher.c

index 94140b3..e11ce37 100644 (file)
@@ -282,6 +282,25 @@ static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type,
                                          alg->cra_ablkcipher.ivsize))
                return alg;
 
+       crypto_mod_put(alg);
+       alg = crypto_alg_mod_lookup(name, type | CRYPTO_ALG_TESTED,
+                                   mask & ~CRYPTO_ALG_TESTED);
+       if (IS_ERR(alg))
+               return alg;
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_GIVCIPHER) {
+               if ((alg->cra_flags ^ type ^ ~mask) & CRYPTO_ALG_TESTED) {
+                       crypto_mod_put(alg);
+                       alg = ERR_PTR(-ENOENT);
+               }
+               return alg;
+       }
+
+       BUG_ON(!((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+                CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
+                                            alg->cra_ablkcipher.ivsize));
+
        return ERR_PTR(crypto_givcipher_default(alg, type, mask));
 }
 
index d70a41c..90d26c9 100644 (file)
@@ -521,7 +521,7 @@ static int crypto_grab_nivcipher(struct crypto_skcipher_spawn *spawn,
        int err;
 
        type = crypto_skcipher_type(type);
-       mask = crypto_skcipher_mask(mask) | CRYPTO_ALG_GENIV;
+       mask = crypto_skcipher_mask(mask)| CRYPTO_ALG_GENIV;
 
        alg = crypto_alg_mod_lookup(name, type, mask);
        if (IS_ERR(alg))