summaryrefslogtreecommitdiffstats
path: root/crypto/testmgr.c
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-03-13 01:12:52 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2019-03-22 08:57:28 -0400
commit6570737c7fa04747d09cbc966972cedd3c0af00b (patch)
treea78a7e9a2a61a9e686de2e1da8a3e2bcc4b504cb /crypto/testmgr.c
parent8b8d91d4ce5a1497755eb925f4390da48f01076b (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.c116
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 */
238struct test_sg_division { 239struct 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 */
263struct testvec_config { 266struct 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
423static bool valid_sg_divisions(const struct test_sg_division *divs, 430static 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 */
446static bool valid_testvec_config(const struct testvec_config *cfg) 455static 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
732static char *generate_random_sgl_divisions(struct test_sg_division *divs, 745static 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
909static 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
867static int check_nonfinal_hash_op(const char *op, int err, 926static 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);