Skip to content

Commit

Permalink
crypto: api - fix unexpectedly getting generic implementation
Browse files Browse the repository at this point in the history
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: 9a8a6b3 ("crypto: testmgr - fuzz hashes against...")
Fixes: d435e10 ("crypto: testmgr - fuzz skciphers against...")
Fixes: 40153b1 ("crypto: testmgr - fuzz AEADs against...")
Reported-by: Eric Biggers <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
Reviewed-by: Eric Biggers <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
herbertx committed Dec 20, 2019
1 parent 76e2277 commit 2bbb337
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 4 deletions.
24 changes: 21 additions & 3 deletions crypto/algapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,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) {
Expand All @@ -307,6 +308,21 @@ void crypto_alg_tested(const char *name, int err)

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;
Expand All @@ -330,10 +346,12 @@ void crypto_alg_tested(const char *name, int err)
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;
}

Expand Down
4 changes: 3 additions & 1 deletion crypto/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 2bbb337

Please sign in to comment.