[PATCH 8/8] crypto: testmgr - test the !may_use_simd() fallback code

Ard Biesheuvel ard.biesheuvel at linaro.org
Wed Mar 13 03:35:35 PDT 2019


On Wed, 13 Mar 2019 at 06:15, Eric Biggers <ebiggers at kernel.org> wrote:
>
> From: Eric Biggers <ebiggers at google.com>
>
> All crypto API algorithms are supposed to support the case where they
> are called in a context where SIMD instructions are unusable, e.g. IRQ
> context on some architectures.  However, this isn't tested for by the
> self-tests, causing bugs to go undetected.
>
> Now that all algorithms have been converted to use crypto_simd_usable(),
> update the self-tests to test the no-SIMD case.  First, a bool
> testvec_config::nosimd is added.  When set, the crypto operation is
> executed with preemption disabled and with crypto_simd_usable() mocked
> out to return false on the current CPU.
>
> A bool test_sg_division::nosimd is also added.  For hash algorithms it's
> honored by the corresponding ->update().  By setting just a subset of
> these bools, the case where some ->update()s are done in SIMD context
> and some are done in no-SIMD context is also tested.
>
> These bools are then randomly set by generate_random_testvec_config().
>
> For now, all no-SIMD testing is limited to the extra crypto self-tests,
> because it might be a bit too invasive for the regular self-tests.
> But this could be changed later.
>
> This has already found bugs in the arm64 AES-GCM and ChaCha algorithms.
> This would have found some past bugs as well.
>
> Signed-off-by: Eric Biggers <ebiggers at google.com>

Acked-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>

> ---
>  crypto/testmgr.c | 116 +++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 92 insertions(+), 24 deletions(-)
>
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 52417dde811f..2c2ddebb48d3 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -234,12 +234,14 @@ enum finalization_type {
>   *                               @offset
>   * @flush_type: for hashes, whether an update() should be done now vs.
>   *             continuing to accumulate data
> + * @nosimd: if doing the pending update(), do it with SIMD disabled?
>   */
>  struct test_sg_division {
>         unsigned int proportion_of_total;
>         unsigned int offset;
>         bool offset_relative_to_alignmask;
>         enum flush_type flush_type;
> +       bool nosimd;
>  };
>
>  /**
> @@ -259,6 +261,7 @@ struct test_sg_division {
>   * @iv_offset_relative_to_alignmask: if true, add the algorithm's alignmask to
>   *                                  the @iv_offset
>   * @finalization_type: what finalization function to use for hashes
> + * @nosimd: execute with SIMD disabled?  Requires !CRYPTO_TFM_REQ_MAY_SLEEP.
>   */
>  struct testvec_config {
>         const char *name;
> @@ -269,6 +272,7 @@ struct testvec_config {
>         unsigned int iv_offset;
>         bool iv_offset_relative_to_alignmask;
>         enum finalization_type finalization_type;
> +       bool nosimd;
>  };
>
>  #define TESTVEC_CONFIG_NAMELEN 192
> @@ -420,8 +424,11 @@ static unsigned int count_test_sg_divisions(const struct test_sg_division *divs)
>         return ndivs;
>  }
>
> +#define SGDIVS_HAVE_FLUSHES    BIT(0)
> +#define SGDIVS_HAVE_NOSIMD     BIT(1)
> +
>  static bool valid_sg_divisions(const struct test_sg_division *divs,
> -                              unsigned int count, bool *any_flushes_ret)
> +                              unsigned int count, int *flags_ret)
>  {
>         unsigned int total = 0;
>         unsigned int i;
> @@ -432,7 +439,9 @@ static bool valid_sg_divisions(const struct test_sg_division *divs,
>                         return false;
>                 total += divs[i].proportion_of_total;
>                 if (divs[i].flush_type != FLUSH_TYPE_NONE)
> -                       *any_flushes_ret = true;
> +                       *flags_ret |= SGDIVS_HAVE_FLUSHES;
> +               if (divs[i].nosimd)
> +                       *flags_ret |= SGDIVS_HAVE_NOSIMD;
>         }
>         return total == TEST_SG_TOTAL &&
>                 memchr_inv(&divs[i], 0, (count - i) * sizeof(divs[0])) == NULL;
> @@ -445,19 +454,18 @@ static bool valid_sg_divisions(const struct test_sg_division *divs,
>   */
>  static bool valid_testvec_config(const struct testvec_config *cfg)
>  {
> -       bool any_flushes = false;
> +       int flags = 0;
>
>         if (cfg->name == NULL)
>                 return false;
>
>         if (!valid_sg_divisions(cfg->src_divs, ARRAY_SIZE(cfg->src_divs),
> -                               &any_flushes))
> +                               &flags))
>                 return false;
>
>         if (cfg->dst_divs[0].proportion_of_total) {
>                 if (!valid_sg_divisions(cfg->dst_divs,
> -                                       ARRAY_SIZE(cfg->dst_divs),
> -                                       &any_flushes))
> +                                       ARRAY_SIZE(cfg->dst_divs), &flags))
>                         return false;
>         } else {
>                 if (memchr_inv(cfg->dst_divs, 0, sizeof(cfg->dst_divs)))
> @@ -470,7 +478,12 @@ static bool valid_testvec_config(const struct testvec_config *cfg)
>             MAX_ALGAPI_ALIGNMASK + 1)
>                 return false;
>
> -       if (any_flushes && cfg->finalization_type == FINALIZATION_TYPE_DIGEST)
> +       if ((flags & (SGDIVS_HAVE_FLUSHES | SGDIVS_HAVE_NOSIMD)) &&
> +           cfg->finalization_type == FINALIZATION_TYPE_DIGEST)
> +               return false;
> +
> +       if ((cfg->nosimd || (flags & SGDIVS_HAVE_NOSIMD)) &&
> +           (cfg->req_flags & CRYPTO_TFM_REQ_MAY_SLEEP))
>                 return false;
>
>         return true;
> @@ -731,13 +744,14 @@ static int build_cipher_test_sglists(struct cipher_test_sglists *tsgls,
>  #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
>  static char *generate_random_sgl_divisions(struct test_sg_division *divs,
>                                            size_t max_divs, char *p, char *end,
> -                                          bool gen_flushes)
> +                                          bool gen_flushes, u32 req_flags)
>  {
>         struct test_sg_division *div = divs;
>         unsigned int remaining = TEST_SG_TOTAL;
>
>         do {
>                 unsigned int this_len;
> +               const char *flushtype_str;
>
>                 if (div == &divs[max_divs - 1] || prandom_u32() % 2 == 0)
>                         this_len = remaining;
> @@ -766,11 +780,31 @@ static char *generate_random_sgl_divisions(struct test_sg_division *divs,
>                         }
>                 }
>
> +               if (div->flush_type != FLUSH_TYPE_NONE &&
> +                   !(req_flags & CRYPTO_TFM_REQ_MAY_SLEEP) &&
> +                   prandom_u32() % 2 == 0)
> +                       div->nosimd = true;
> +
> +               switch (div->flush_type) {
> +               case FLUSH_TYPE_FLUSH:
> +                       if (div->nosimd)
> +                               flushtype_str = "<flush,nosimd>";
> +                       else
> +                               flushtype_str = "<flush>";
> +                       break;
> +               case FLUSH_TYPE_REIMPORT:
> +                       if (div->nosimd)
> +                               flushtype_str = "<reimport,nosimd>";
> +                       else
> +                               flushtype_str = "<reimport>";
> +                       break;
> +               default:
> +                       flushtype_str = "";
> +                       break;
> +               }
> +
>                 BUILD_BUG_ON(TEST_SG_TOTAL != 10000); /* for "%u.%u%%" */
> -               p += scnprintf(p, end - p, "%s%u.%u%%@%s+%u%s",
> -                              div->flush_type == FLUSH_TYPE_NONE ? "" :
> -                              div->flush_type == FLUSH_TYPE_FLUSH ?
> -                              "<flush> " : "<reimport> ",
> +               p += scnprintf(p, end - p, "%s%u.%u%%@%s+%u%s", flushtype_str,
>                                this_len / 100, this_len % 100,
>                                div->offset_relative_to_alignmask ?
>                                         "alignmask" : "",
> @@ -820,18 +854,26 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
>                 break;
>         }
>
> +       if (!(cfg->req_flags & CRYPTO_TFM_REQ_MAY_SLEEP) &&
> +           prandom_u32() % 2 == 0) {
> +               cfg->nosimd = true;
> +               p += scnprintf(p, end - p, " nosimd");
> +       }
> +
>         p += scnprintf(p, end - p, " src_divs=[");
>         p = generate_random_sgl_divisions(cfg->src_divs,
>                                           ARRAY_SIZE(cfg->src_divs), p, end,
>                                           (cfg->finalization_type !=
> -                                          FINALIZATION_TYPE_DIGEST));
> +                                          FINALIZATION_TYPE_DIGEST),
> +                                         cfg->req_flags);
>         p += scnprintf(p, end - p, "]");
>
>         if (!cfg->inplace && prandom_u32() % 2 == 0) {
>                 p += scnprintf(p, end - p, " dst_divs=[");
>                 p = generate_random_sgl_divisions(cfg->dst_divs,
>                                                   ARRAY_SIZE(cfg->dst_divs),
> -                                                 p, end, false);
> +                                                 p, end, false,
> +                                                 cfg->req_flags);
>                 p += scnprintf(p, end - p, "]");
>         }
>
> @@ -864,6 +906,23 @@ static void crypto_reenable_simd_for_test(void)
>  }
>  #endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
>
> +static int do_ahash_op(int (*op)(struct ahash_request *req),
> +                      struct ahash_request *req,
> +                      struct crypto_wait *wait, bool nosimd)
> +{
> +       int err;
> +
> +       if (nosimd)
> +               crypto_disable_simd_for_test();
> +
> +       err = op(req);
> +
> +       if (nosimd)
> +               crypto_reenable_simd_for_test();
> +
> +       return crypto_wait_req(err, wait);
> +}
> +
>  static int check_nonfinal_hash_op(const char *op, int err,
>                                   u8 *result, unsigned int digestsize,
>                                   const char *driver, unsigned int vec_num,
> @@ -938,7 +997,7 @@ static int test_hash_vec_cfg(const char *driver,
>                 ahash_request_set_callback(req, req_flags, crypto_req_done,
>                                            &wait);
>                 ahash_request_set_crypt(req, tsgl->sgl, result, vec->psize);
> -               err = crypto_wait_req(crypto_ahash_digest(req), &wait);
> +               err = do_ahash_op(crypto_ahash_digest, req, &wait, cfg->nosimd);
>                 if (err) {
>                         pr_err("alg: hash: %s digest() failed with err %d on test vector %u, cfg=\"%s\"\n",
>                                driver, err, vec_num, cfg->name);
> @@ -951,7 +1010,7 @@ static int test_hash_vec_cfg(const char *driver,
>
>         ahash_request_set_callback(req, req_flags, crypto_req_done, &wait);
>         ahash_request_set_crypt(req, NULL, result, 0);
> -       err = crypto_wait_req(crypto_ahash_init(req), &wait);
> +       err = do_ahash_op(crypto_ahash_init, req, &wait, cfg->nosimd);
>         err = check_nonfinal_hash_op("init", err, result, digestsize,
>                                      driver, vec_num, cfg);
>         if (err)
> @@ -967,7 +1026,8 @@ static int test_hash_vec_cfg(const char *driver,
>                                                    crypto_req_done, &wait);
>                         ahash_request_set_crypt(req, pending_sgl, result,
>                                                 pending_len);
> -                       err = crypto_wait_req(crypto_ahash_update(req), &wait);
> +                       err = do_ahash_op(crypto_ahash_update, req, &wait,
> +                                         divs[i]->nosimd);
>                         err = check_nonfinal_hash_op("update", err,
>                                                      result, digestsize,
>                                                      driver, vec_num, cfg);
> @@ -1010,12 +1070,12 @@ static int test_hash_vec_cfg(const char *driver,
>         ahash_request_set_crypt(req, pending_sgl, result, pending_len);
>         if (cfg->finalization_type == FINALIZATION_TYPE_FINAL) {
>                 /* finish with update() and final() */
> -               err = crypto_wait_req(crypto_ahash_update(req), &wait);
> +               err = do_ahash_op(crypto_ahash_update, req, &wait, cfg->nosimd);
>                 err = check_nonfinal_hash_op("update", err, result, digestsize,
>                                              driver, vec_num, cfg);
>                 if (err)
>                         return err;
> -               err = crypto_wait_req(crypto_ahash_final(req), &wait);
> +               err = do_ahash_op(crypto_ahash_final, req, &wait, cfg->nosimd);
>                 if (err) {
>                         pr_err("alg: hash: %s final() failed with err %d on test vector %u, cfg=\"%s\"\n",
>                                driver, err, vec_num, cfg->name);
> @@ -1023,7 +1083,7 @@ static int test_hash_vec_cfg(const char *driver,
>                 }
>         } else {
>                 /* finish with finup() */
> -               err = crypto_wait_req(crypto_ahash_finup(req), &wait);
> +               err = do_ahash_op(crypto_ahash_finup, req, &wait, cfg->nosimd);
>                 if (err) {
>                         pr_err("alg: hash: %s finup() failed with err %d on test vector %u, cfg=\"%s\"\n",
>                                driver, err, vec_num, cfg->name);
> @@ -1259,8 +1319,12 @@ static int test_aead_vec_cfg(const char *driver, int enc,
>         aead_request_set_crypt(req, tsgls->src.sgl_ptr, tsgls->dst.sgl_ptr,
>                                enc ? vec->plen : vec->clen, iv);
>         aead_request_set_ad(req, vec->alen);
> -       err = crypto_wait_req(enc ? crypto_aead_encrypt(req) :
> -                             crypto_aead_decrypt(req), &wait);
> +       if (cfg->nosimd)
> +               crypto_disable_simd_for_test();
> +       err = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);
> +       if (cfg->nosimd)
> +               crypto_reenable_simd_for_test();
> +       err = crypto_wait_req(err, &wait);
>         if (err) {
>                 if (err == -EBADMSG && vec->novrfy)
>                         return 0;
> @@ -1594,8 +1658,12 @@ static int test_skcipher_vec_cfg(const char *driver, int enc,
>         skcipher_request_set_callback(req, req_flags, crypto_req_done, &wait);
>         skcipher_request_set_crypt(req, tsgls->src.sgl_ptr, tsgls->dst.sgl_ptr,
>                                    vec->len, iv);
> -       err = crypto_wait_req(enc ? crypto_skcipher_encrypt(req) :
> -                             crypto_skcipher_decrypt(req), &wait);
> +       if (cfg->nosimd)
> +               crypto_disable_simd_for_test();
> +       err = enc ? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req);
> +       if (cfg->nosimd)
> +               crypto_reenable_simd_for_test();
> +       err = crypto_wait_req(err, &wait);
>         if (err) {
>                 pr_err("alg: skcipher: %s %s failed with err %d on test vector %u, cfg=\"%s\"\n",
>                        driver, op, err, vec_num, cfg->name);
> --
> 2.21.0
>



More information about the linux-arm-kernel mailing list