diff options
author | Eric Biggers <ebiggers@google.com> | 2019-03-13 01:12:52 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-03-22 08:57:28 -0400 |
commit | 6570737c7fa04747d09cbc966972cedd3c0af00b (patch) | |
tree | a78a7e9a2a61a9e686de2e1da8a3e2bcc4b504cb /crypto/testmgr.c | |
parent | 8b8d91d4ce5a1497755eb925f4390da48f01076b (diff) |
crypto: testmgr - test the !may_use_simd() fallback code
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@google.com>
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/testmgr.c')
-rw-r--r-- | crypto/testmgr.c | 116 |
1 files 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 { | |||
234 | * @offset | 234 | * @offset |
235 | * @flush_type: for hashes, whether an update() should be done now vs. | 235 | * @flush_type: for hashes, whether an update() should be done now vs. |
236 | * continuing to accumulate data | 236 | * continuing to accumulate data |
237 | * @nosimd: if doing the pending update(), do it with SIMD disabled? | ||
237 | */ | 238 | */ |
238 | struct test_sg_division { | 239 | struct test_sg_division { |
239 | unsigned int proportion_of_total; | 240 | unsigned int proportion_of_total; |
240 | unsigned int offset; | 241 | unsigned int offset; |
241 | bool offset_relative_to_alignmask; | 242 | bool offset_relative_to_alignmask; |
242 | enum flush_type flush_type; | 243 | enum flush_type flush_type; |
244 | bool nosimd; | ||
243 | }; | 245 | }; |
244 | 246 | ||
245 | /** | 247 | /** |
@@ -259,6 +261,7 @@ struct test_sg_division { | |||
259 | * @iv_offset_relative_to_alignmask: if true, add the algorithm's alignmask to | 261 | * @iv_offset_relative_to_alignmask: if true, add the algorithm's alignmask to |
260 | * the @iv_offset | 262 | * the @iv_offset |
261 | * @finalization_type: what finalization function to use for hashes | 263 | * @finalization_type: what finalization function to use for hashes |
264 | * @nosimd: execute with SIMD disabled? Requires !CRYPTO_TFM_REQ_MAY_SLEEP. | ||
262 | */ | 265 | */ |
263 | struct testvec_config { | 266 | struct testvec_config { |
264 | const char *name; | 267 | const char *name; |
@@ -269,6 +272,7 @@ struct testvec_config { | |||
269 | unsigned int iv_offset; | 272 | unsigned int iv_offset; |
270 | bool iv_offset_relative_to_alignmask; | 273 | bool iv_offset_relative_to_alignmask; |
271 | enum finalization_type finalization_type; | 274 | enum finalization_type finalization_type; |
275 | bool nosimd; | ||
272 | }; | 276 | }; |
273 | 277 | ||
274 | #define TESTVEC_CONFIG_NAMELEN 192 | 278 | #define TESTVEC_CONFIG_NAMELEN 192 |
@@ -420,8 +424,11 @@ static unsigned int count_test_sg_divisions(const struct test_sg_division *divs) | |||
420 | return ndivs; | 424 | return ndivs; |
421 | } | 425 | } |
422 | 426 | ||
427 | #define SGDIVS_HAVE_FLUSHES BIT(0) | ||
428 | #define SGDIVS_HAVE_NOSIMD BIT(1) | ||
429 | |||
423 | static bool valid_sg_divisions(const struct test_sg_division *divs, | 430 | static bool valid_sg_divisions(const struct test_sg_division *divs, |
424 | unsigned int count, bool *any_flushes_ret) | 431 | unsigned int count, int *flags_ret) |
425 | { | 432 | { |
426 | unsigned int total = 0; | 433 | unsigned int total = 0; |
427 | unsigned int i; | 434 | unsigned int i; |
@@ -432,7 +439,9 @@ static bool valid_sg_divisions(const struct test_sg_division *divs, | |||
432 | return false; | 439 | return false; |
433 | total += divs[i].proportion_of_total; | 440 | total += divs[i].proportion_of_total; |
434 | if (divs[i].flush_type != FLUSH_TYPE_NONE) | 441 | if (divs[i].flush_type != FLUSH_TYPE_NONE) |
435 | *any_flushes_ret = true; | 442 | *flags_ret |= SGDIVS_HAVE_FLUSHES; |
443 | if (divs[i].nosimd) | ||
444 | *flags_ret |= SGDIVS_HAVE_NOSIMD; | ||
436 | } | 445 | } |
437 | return total == TEST_SG_TOTAL && | 446 | return total == TEST_SG_TOTAL && |
438 | memchr_inv(&divs[i], 0, (count - i) * sizeof(divs[0])) == NULL; | 447 | 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, | |||
445 | */ | 454 | */ |
446 | static bool valid_testvec_config(const struct testvec_config *cfg) | 455 | static bool valid_testvec_config(const struct testvec_config *cfg) |
447 | { | 456 | { |
448 | bool any_flushes = false; | 457 | int flags = 0; |
449 | 458 | ||
450 | if (cfg->name == NULL) | 459 | if (cfg->name == NULL) |
451 | return false; | 460 | return false; |
452 | 461 | ||
453 | if (!valid_sg_divisions(cfg->src_divs, ARRAY_SIZE(cfg->src_divs), | 462 | if (!valid_sg_divisions(cfg->src_divs, ARRAY_SIZE(cfg->src_divs), |
454 | &any_flushes)) | 463 | &flags)) |
455 | return false; | 464 | return false; |
456 | 465 | ||
457 | if (cfg->dst_divs[0].proportion_of_total) { | 466 | if (cfg->dst_divs[0].proportion_of_total) { |
458 | if (!valid_sg_divisions(cfg->dst_divs, | 467 | if (!valid_sg_divisions(cfg->dst_divs, |
459 | ARRAY_SIZE(cfg->dst_divs), | 468 | ARRAY_SIZE(cfg->dst_divs), &flags)) |
460 | &any_flushes)) | ||
461 | return false; | 469 | return false; |
462 | } else { | 470 | } else { |
463 | if (memchr_inv(cfg->dst_divs, 0, sizeof(cfg->dst_divs))) | 471 | 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) | |||
470 | MAX_ALGAPI_ALIGNMASK + 1) | 478 | MAX_ALGAPI_ALIGNMASK + 1) |
471 | return false; | 479 | return false; |
472 | 480 | ||
473 | if (any_flushes && cfg->finalization_type == FINALIZATION_TYPE_DIGEST) | 481 | if ((flags & (SGDIVS_HAVE_FLUSHES | SGDIVS_HAVE_NOSIMD)) && |
482 | cfg->finalization_type == FINALIZATION_TYPE_DIGEST) | ||
483 | return false; | ||
484 | |||
485 | if ((cfg->nosimd || (flags & SGDIVS_HAVE_NOSIMD)) && | ||
486 | (cfg->req_flags & CRYPTO_TFM_REQ_MAY_SLEEP)) | ||
474 | return false; | 487 | return false; |
475 | 488 | ||
476 | return true; | 489 | return true; |
@@ -731,13 +744,14 @@ static int build_cipher_test_sglists(struct cipher_test_sglists *tsgls, | |||
731 | #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS | 744 | #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS |
732 | static char *generate_random_sgl_divisions(struct test_sg_division *divs, | 745 | static char *generate_random_sgl_divisions(struct test_sg_division *divs, |
733 | size_t max_divs, char *p, char *end, | 746 | size_t max_divs, char *p, char *end, |
734 | bool gen_flushes) | 747 | bool gen_flushes, u32 req_flags) |
735 | { | 748 | { |
736 | struct test_sg_division *div = divs; | 749 | struct test_sg_division *div = divs; |
737 | unsigned int remaining = TEST_SG_TOTAL; | 750 | unsigned int remaining = TEST_SG_TOTAL; |
738 | 751 | ||
739 | do { | 752 | do { |
740 | unsigned int this_len; | 753 | unsigned int this_len; |
754 | const char *flushtype_str; | ||
741 | 755 | ||
742 | if (div == &divs[max_divs - 1] || prandom_u32() % 2 == 0) | 756 | if (div == &divs[max_divs - 1] || prandom_u32() % 2 == 0) |
743 | this_len = remaining; | 757 | this_len = remaining; |
@@ -766,11 +780,31 @@ static char *generate_random_sgl_divisions(struct test_sg_division *divs, | |||
766 | } | 780 | } |
767 | } | 781 | } |
768 | 782 | ||
783 | if (div->flush_type != FLUSH_TYPE_NONE && | ||
784 | !(req_flags & CRYPTO_TFM_REQ_MAY_SLEEP) && | ||
785 | prandom_u32() % 2 == 0) | ||
786 | div->nosimd = true; | ||
787 | |||
788 | switch (div->flush_type) { | ||
789 | case FLUSH_TYPE_FLUSH: | ||
790 | if (div->nosimd) | ||
791 | flushtype_str = "<flush,nosimd>"; | ||
792 | else | ||
793 | flushtype_str = "<flush>"; | ||
794 | break; | ||
795 | case FLUSH_TYPE_REIMPORT: | ||
796 | if (div->nosimd) | ||
797 | flushtype_str = "<reimport,nosimd>"; | ||
798 | else | ||
799 | flushtype_str = "<reimport>"; | ||
800 | break; | ||
801 | default: | ||
802 | flushtype_str = ""; | ||
803 | break; | ||
804 | } | ||
805 | |||
769 | BUILD_BUG_ON(TEST_SG_TOTAL != 10000); /* for "%u.%u%%" */ | 806 | BUILD_BUG_ON(TEST_SG_TOTAL != 10000); /* for "%u.%u%%" */ |
770 | p += scnprintf(p, end - p, "%s%u.%u%%@%s+%u%s", | 807 | p += scnprintf(p, end - p, "%s%u.%u%%@%s+%u%s", flushtype_str, |
771 | div->flush_type == FLUSH_TYPE_NONE ? "" : | ||
772 | div->flush_type == FLUSH_TYPE_FLUSH ? | ||
773 | "<flush> " : "<reimport> ", | ||
774 | this_len / 100, this_len % 100, | 808 | this_len / 100, this_len % 100, |
775 | div->offset_relative_to_alignmask ? | 809 | div->offset_relative_to_alignmask ? |
776 | "alignmask" : "", | 810 | "alignmask" : "", |
@@ -820,18 +854,26 @@ static void generate_random_testvec_config(struct testvec_config *cfg, | |||
820 | break; | 854 | break; |
821 | } | 855 | } |
822 | 856 | ||
857 | if (!(cfg->req_flags & CRYPTO_TFM_REQ_MAY_SLEEP) && | ||
858 | prandom_u32() % 2 == 0) { | ||
859 | cfg->nosimd = true; | ||
860 | p += scnprintf(p, end - p, " nosimd"); | ||
861 | } | ||
862 | |||
823 | p += scnprintf(p, end - p, " src_divs=["); | 863 | p += scnprintf(p, end - p, " src_divs=["); |
824 | p = generate_random_sgl_divisions(cfg->src_divs, | 864 | p = generate_random_sgl_divisions(cfg->src_divs, |
825 | ARRAY_SIZE(cfg->src_divs), p, end, | 865 | ARRAY_SIZE(cfg->src_divs), p, end, |
826 | (cfg->finalization_type != | 866 | (cfg->finalization_type != |
827 | FINALIZATION_TYPE_DIGEST)); | 867 | FINALIZATION_TYPE_DIGEST), |
868 | cfg->req_flags); | ||
828 | p += scnprintf(p, end - p, "]"); | 869 | p += scnprintf(p, end - p, "]"); |
829 | 870 | ||
830 | if (!cfg->inplace && prandom_u32() % 2 == 0) { | 871 | if (!cfg->inplace && prandom_u32() % 2 == 0) { |
831 | p += scnprintf(p, end - p, " dst_divs=["); | 872 | p += scnprintf(p, end - p, " dst_divs=["); |
832 | p = generate_random_sgl_divisions(cfg->dst_divs, | 873 | p = generate_random_sgl_divisions(cfg->dst_divs, |
833 | ARRAY_SIZE(cfg->dst_divs), | 874 | ARRAY_SIZE(cfg->dst_divs), |
834 | p, end, false); | 875 | p, end, false, |
876 | cfg->req_flags); | ||
835 | p += scnprintf(p, end - p, "]"); | 877 | p += scnprintf(p, end - p, "]"); |
836 | } | 878 | } |
837 | 879 | ||
@@ -864,6 +906,23 @@ static void crypto_reenable_simd_for_test(void) | |||
864 | } | 906 | } |
865 | #endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */ | 907 | #endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */ |
866 | 908 | ||
909 | static int do_ahash_op(int (*op)(struct ahash_request *req), | ||
910 | struct ahash_request *req, | ||
911 | struct crypto_wait *wait, bool nosimd) | ||
912 | { | ||
913 | int err; | ||
914 | |||
915 | if (nosimd) | ||
916 | crypto_disable_simd_for_test(); | ||
917 | |||
918 | err = op(req); | ||
919 | |||
920 | if (nosimd) | ||
921 | crypto_reenable_simd_for_test(); | ||
922 | |||
923 | return crypto_wait_req(err, wait); | ||
924 | } | ||
925 | |||
867 | static int check_nonfinal_hash_op(const char *op, int err, | 926 | static int check_nonfinal_hash_op(const char *op, int err, |
868 | u8 *result, unsigned int digestsize, | 927 | u8 *result, unsigned int digestsize, |
869 | const char *driver, unsigned int vec_num, | 928 | const char *driver, unsigned int vec_num, |
@@ -938,7 +997,7 @@ static int test_hash_vec_cfg(const char *driver, | |||
938 | ahash_request_set_callback(req, req_flags, crypto_req_done, | 997 | ahash_request_set_callback(req, req_flags, crypto_req_done, |
939 | &wait); | 998 | &wait); |
940 | ahash_request_set_crypt(req, tsgl->sgl, result, vec->psize); | 999 | ahash_request_set_crypt(req, tsgl->sgl, result, vec->psize); |
941 | err = crypto_wait_req(crypto_ahash_digest(req), &wait); | 1000 | err = do_ahash_op(crypto_ahash_digest, req, &wait, cfg->nosimd); |
942 | if (err) { | 1001 | if (err) { |
943 | pr_err("alg: hash: %s digest() failed with err %d on test vector %u, cfg=\"%s\"\n", | 1002 | pr_err("alg: hash: %s digest() failed with err %d on test vector %u, cfg=\"%s\"\n", |
944 | driver, err, vec_num, cfg->name); | 1003 | driver, err, vec_num, cfg->name); |
@@ -951,7 +1010,7 @@ static int test_hash_vec_cfg(const char *driver, | |||
951 | 1010 | ||
952 | ahash_request_set_callback(req, req_flags, crypto_req_done, &wait); | 1011 | ahash_request_set_callback(req, req_flags, crypto_req_done, &wait); |
953 | ahash_request_set_crypt(req, NULL, result, 0); | 1012 | ahash_request_set_crypt(req, NULL, result, 0); |
954 | err = crypto_wait_req(crypto_ahash_init(req), &wait); | 1013 | err = do_ahash_op(crypto_ahash_init, req, &wait, cfg->nosimd); |
955 | err = check_nonfinal_hash_op("init", err, result, digestsize, | 1014 | err = check_nonfinal_hash_op("init", err, result, digestsize, |
956 | driver, vec_num, cfg); | 1015 | driver, vec_num, cfg); |
957 | if (err) | 1016 | if (err) |
@@ -967,7 +1026,8 @@ static int test_hash_vec_cfg(const char *driver, | |||
967 | crypto_req_done, &wait); | 1026 | crypto_req_done, &wait); |
968 | ahash_request_set_crypt(req, pending_sgl, result, | 1027 | ahash_request_set_crypt(req, pending_sgl, result, |
969 | pending_len); | 1028 | pending_len); |
970 | err = crypto_wait_req(crypto_ahash_update(req), &wait); | 1029 | err = do_ahash_op(crypto_ahash_update, req, &wait, |
1030 | divs[i]->nosimd); | ||
971 | err = check_nonfinal_hash_op("update", err, | 1031 | err = check_nonfinal_hash_op("update", err, |
972 | result, digestsize, | 1032 | result, digestsize, |
973 | driver, vec_num, cfg); | 1033 | driver, vec_num, cfg); |
@@ -1010,12 +1070,12 @@ static int test_hash_vec_cfg(const char *driver, | |||
1010 | ahash_request_set_crypt(req, pending_sgl, result, pending_len); | 1070 | ahash_request_set_crypt(req, pending_sgl, result, pending_len); |
1011 | if (cfg->finalization_type == FINALIZATION_TYPE_FINAL) { | 1071 | if (cfg->finalization_type == FINALIZATION_TYPE_FINAL) { |
1012 | /* finish with update() and final() */ | 1072 | /* finish with update() and final() */ |
1013 | err = crypto_wait_req(crypto_ahash_update(req), &wait); | 1073 | err = do_ahash_op(crypto_ahash_update, req, &wait, cfg->nosimd); |
1014 | err = check_nonfinal_hash_op("update", err, result, digestsize, | 1074 | err = check_nonfinal_hash_op("update", err, result, digestsize, |
1015 | driver, vec_num, cfg); | 1075 | driver, vec_num, cfg); |
1016 | if (err) | 1076 | if (err) |
1017 | return err; | 1077 | return err; |
1018 | err = crypto_wait_req(crypto_ahash_final(req), &wait); | 1078 | err = do_ahash_op(crypto_ahash_final, req, &wait, cfg->nosimd); |
1019 | if (err) { | 1079 | if (err) { |
1020 | pr_err("alg: hash: %s final() failed with err %d on test vector %u, cfg=\"%s\"\n", | 1080 | pr_err("alg: hash: %s final() failed with err %d on test vector %u, cfg=\"%s\"\n", |
1021 | driver, err, vec_num, cfg->name); | 1081 | driver, err, vec_num, cfg->name); |
@@ -1023,7 +1083,7 @@ static int test_hash_vec_cfg(const char *driver, | |||
1023 | } | 1083 | } |
1024 | } else { | 1084 | } else { |
1025 | /* finish with finup() */ | 1085 | /* finish with finup() */ |
1026 | err = crypto_wait_req(crypto_ahash_finup(req), &wait); | 1086 | err = do_ahash_op(crypto_ahash_finup, req, &wait, cfg->nosimd); |
1027 | if (err) { | 1087 | if (err) { |
1028 | pr_err("alg: hash: %s finup() failed with err %d on test vector %u, cfg=\"%s\"\n", | 1088 | pr_err("alg: hash: %s finup() failed with err %d on test vector %u, cfg=\"%s\"\n", |
1029 | driver, err, vec_num, cfg->name); | 1089 | driver, err, vec_num, cfg->name); |
@@ -1259,8 +1319,12 @@ static int test_aead_vec_cfg(const char *driver, int enc, | |||
1259 | aead_request_set_crypt(req, tsgls->src.sgl_ptr, tsgls->dst.sgl_ptr, | 1319 | aead_request_set_crypt(req, tsgls->src.sgl_ptr, tsgls->dst.sgl_ptr, |
1260 | enc ? vec->plen : vec->clen, iv); | 1320 | enc ? vec->plen : vec->clen, iv); |
1261 | aead_request_set_ad(req, vec->alen); | 1321 | aead_request_set_ad(req, vec->alen); |
1262 | err = crypto_wait_req(enc ? crypto_aead_encrypt(req) : | 1322 | if (cfg->nosimd) |
1263 | crypto_aead_decrypt(req), &wait); | 1323 | crypto_disable_simd_for_test(); |
1324 | err = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); | ||
1325 | if (cfg->nosimd) | ||
1326 | crypto_reenable_simd_for_test(); | ||
1327 | err = crypto_wait_req(err, &wait); | ||
1264 | if (err) { | 1328 | if (err) { |
1265 | if (err == -EBADMSG && vec->novrfy) | 1329 | if (err == -EBADMSG && vec->novrfy) |
1266 | return 0; | 1330 | return 0; |
@@ -1594,8 +1658,12 @@ static int test_skcipher_vec_cfg(const char *driver, int enc, | |||
1594 | skcipher_request_set_callback(req, req_flags, crypto_req_done, &wait); | 1658 | skcipher_request_set_callback(req, req_flags, crypto_req_done, &wait); |
1595 | skcipher_request_set_crypt(req, tsgls->src.sgl_ptr, tsgls->dst.sgl_ptr, | 1659 | skcipher_request_set_crypt(req, tsgls->src.sgl_ptr, tsgls->dst.sgl_ptr, |
1596 | vec->len, iv); | 1660 | vec->len, iv); |
1597 | err = crypto_wait_req(enc ? crypto_skcipher_encrypt(req) : | 1661 | if (cfg->nosimd) |
1598 | crypto_skcipher_decrypt(req), &wait); | 1662 | crypto_disable_simd_for_test(); |
1663 | err = enc ? crypto_skcipher_encrypt(req) : crypto_skcipher_decrypt(req); | ||
1664 | if (cfg->nosimd) | ||
1665 | crypto_reenable_simd_for_test(); | ||
1666 | err = crypto_wait_req(err, &wait); | ||
1599 | if (err) { | 1667 | if (err) { |
1600 | pr_err("alg: skcipher: %s %s failed with err %d on test vector %u, cfg=\"%s\"\n", | 1668 | pr_err("alg: skcipher: %s %s failed with err %d on test vector %u, cfg=\"%s\"\n", |
1601 | driver, op, err, vec_num, cfg->name); | 1669 | driver, op, err, vec_num, cfg->name); |