]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
crypto: api - fix unexpectedly getting generic implementation
authorHerbert Xu <herbert@gondor.apana.org.au>
Wed, 11 Dec 2019 02:50:11 +0000 (10:50 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 Feb 2020 12:35:30 +0000 (04:35 -0800)
commit 2bbb3375d967155bccc86a5887d4a6e29c56b683 upstream.

When CONFIG_CRYPTO_MANAGER_EXTRA_TESTS=y, the first lookup of an
algorithm that needs to be instantiated using a template will always get
the generic implementation, even when an accelerated one is available.

This happens because the extra self-tests for the accelerated
implementation allocate the generic implementation for comparison
purposes, and then crypto_alg_tested() for the generic implementation
"fulfills" the original request (i.e. sets crypto_larval::adult).

This patch fixes this by only fulfilling the original request if
we are currently the best outstanding larval as judged by the
priority.  If we're not the best then we will ask all waiters on
that larval request to retry the lookup.

Note that this patch introduces a behaviour change when the module
providing the new algorithm is unregistered during the process.
Previously we would have failed with ENOENT, after the patch we
will instead redo the lookup.

Fixes: 9a8a6b3f0950 ("crypto: testmgr - fuzz hashes against...")
Fixes: d435e10e67be ("crypto: testmgr - fuzz skciphers against...")
Fixes: 40153b10d91c ("crypto: testmgr - fuzz AEADs against...")
Reported-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
crypto/algapi.c
crypto/api.c

index b860889ec99d29c00e8540dddf02d13ea322a570..5167a4f6f0ed2b55fa40ddbe9f884a9b0c734acc 100644 (file)
@@ -257,6 +257,7 @@ void crypto_alg_tested(const char *name, int err)
        struct crypto_alg *alg;
        struct crypto_alg *q;
        LIST_HEAD(list);
+       bool best;
 
        down_write(&crypto_alg_sem);
        list_for_each_entry(q, &crypto_alg_list, cra_list) {
@@ -280,6 +281,21 @@ found:
 
        alg->cra_flags |= CRYPTO_ALG_TESTED;
 
+       /* Only satisfy larval waiters if we are the best. */
+       best = true;
+       list_for_each_entry(q, &crypto_alg_list, cra_list) {
+               if (crypto_is_moribund(q) || !crypto_is_larval(q))
+                       continue;
+
+               if (strcmp(alg->cra_name, q->cra_name))
+                       continue;
+
+               if (q->cra_priority > alg->cra_priority) {
+                       best = false;
+                       break;
+               }
+       }
+
        list_for_each_entry(q, &crypto_alg_list, cra_list) {
                if (q == alg)
                        continue;
@@ -303,10 +319,12 @@ found:
                                continue;
                        if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
                                continue;
-                       if (!crypto_mod_get(alg))
-                               continue;
 
-                       larval->adult = alg;
+                       if (best && crypto_mod_get(alg))
+                               larval->adult = alg;
+                       else
+                               larval->adult = ERR_PTR(-EAGAIN);
+
                        continue;
                }
 
index d8ba541426200a41cd1edb00b7d808999a1d4ed7..9f99d0e703843907831cd516ecb67a60b2026bc2 100644 (file)
@@ -97,7 +97,7 @@ static void crypto_larval_destroy(struct crypto_alg *alg)
        struct crypto_larval *larval = (void *)alg;
 
        BUG_ON(!crypto_is_larval(alg));
-       if (larval->adult)
+       if (!IS_ERR_OR_NULL(larval->adult))
                crypto_mod_put(larval->adult);
        kfree(larval);
 }
@@ -178,6 +178,8 @@ static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
                alg = ERR_PTR(-ETIMEDOUT);
        else if (!alg)
                alg = ERR_PTR(-ENOENT);
+       else if (IS_ERR(alg))
+               ;
        else if (crypto_is_test_larval(larval) &&
                 !(alg->cra_flags & CRYPTO_ALG_TESTED))
                alg = ERR_PTR(-EAGAIN);