summaryrefslogtreecommitdiff
path: root/crypto/testmgr.c
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2022-03-26 00:11:59 -0700
committerHerbert Xu <herbert@gondor.apana.org.au>2022-04-08 16:25:19 +0800
commitf17f9e9069f20f4400ae0bb3ee830d34104ff8f7 (patch)
tree8da45b390dccac99e638d680c35b25e1c182c1a3 /crypto/testmgr.c
parentf16a005cde3b1f31cad5ecba0cc810652c3874ec (diff)
crypto: testmgr - test in-place en/decryption with two sglists
As was established in the thread https://lore.kernel.org/linux-crypto/20220223080400.139367-1-gilad@benyossef.com/T/#u, many crypto API users doing in-place en/decryption don't use the same scatterlist pointers for the source and destination, but rather use separate scatterlists that point to the same memory. This case isn't tested by the self-tests, resulting in bugs. This is the natural usage of the crypto API in some cases, so requiring API users to avoid this usage is not reasonable. Therefore, update the self-tests to start testing this case. Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/testmgr.c')
-rw-r--r--crypto/testmgr.c75
1 files changed, 63 insertions, 12 deletions
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 4948201065cc..5801a8f9f713 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -232,6 +232,20 @@ enum finalization_type {
FINALIZATION_TYPE_DIGEST, /* use digest() */
};
+/*
+ * Whether the crypto operation will occur in-place, and if so whether the
+ * source and destination scatterlist pointers will coincide (req->src ==
+ * req->dst), or whether they'll merely point to two separate scatterlists
+ * (req->src != req->dst) that reference the same underlying memory.
+ *
+ * This is only relevant for algorithm types that support in-place operation.
+ */
+enum inplace_mode {
+ OUT_OF_PLACE,
+ INPLACE_ONE_SGLIST,
+ INPLACE_TWO_SGLISTS,
+};
+
#define TEST_SG_TOTAL 10000
/**
@@ -265,7 +279,7 @@ struct test_sg_division {
* crypto test vector can be tested.
*
* @name: name of this config, logged for debugging purposes if a test fails
- * @inplace: operate on the data in-place, if applicable for the algorithm type?
+ * @inplace_mode: whether and how to operate on the data in-place, if applicable
* @req_flags: extra request_flags, e.g. CRYPTO_TFM_REQ_MAY_SLEEP
* @src_divs: description of how to arrange the source scatterlist
* @dst_divs: description of how to arrange the dst scatterlist, if applicable
@@ -282,7 +296,7 @@ struct test_sg_division {
*/
struct testvec_config {
const char *name;
- bool inplace;
+ enum inplace_mode inplace_mode;
u32 req_flags;
struct test_sg_division src_divs[XBUFSIZE];
struct test_sg_division dst_divs[XBUFSIZE];
@@ -307,11 +321,16 @@ struct testvec_config {
/* Configs for skciphers and aeads */
static const struct testvec_config default_cipher_testvec_configs[] = {
{
- .name = "in-place",
- .inplace = true,
+ .name = "in-place (one sglist)",
+ .inplace_mode = INPLACE_ONE_SGLIST,
+ .src_divs = { { .proportion_of_total = 10000 } },
+ }, {
+ .name = "in-place (two sglists)",
+ .inplace_mode = INPLACE_TWO_SGLISTS,
.src_divs = { { .proportion_of_total = 10000 } },
}, {
.name = "out-of-place",
+ .inplace_mode = OUT_OF_PLACE,
.src_divs = { { .proportion_of_total = 10000 } },
}, {
.name = "unaligned buffer, offset=1",
@@ -349,7 +368,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
.key_offset = 3,
}, {
.name = "misaligned splits crossing pages, inplace",
- .inplace = true,
+ .inplace_mode = INPLACE_ONE_SGLIST,
.src_divs = {
{
.proportion_of_total = 7500,
@@ -749,18 +768,39 @@ static int build_cipher_test_sglists(struct cipher_test_sglists *tsgls,
iov_iter_kvec(&input, WRITE, inputs, nr_inputs, src_total_len);
err = build_test_sglist(&tsgls->src, cfg->src_divs, alignmask,
- cfg->inplace ?
+ cfg->inplace_mode != OUT_OF_PLACE ?
max(dst_total_len, src_total_len) :
src_total_len,
&input, NULL);
if (err)
return err;
- if (cfg->inplace) {
+ /*
+ * In-place crypto operations can use the same scatterlist for both the
+ * source and destination (req->src == req->dst), or can use separate
+ * scatterlists (req->src != req->dst) which point to the same
+ * underlying memory. Make sure to test both cases.
+ */
+ if (cfg->inplace_mode == INPLACE_ONE_SGLIST) {
tsgls->dst.sgl_ptr = tsgls->src.sgl;
tsgls->dst.nents = tsgls->src.nents;
return 0;
}
+ if (cfg->inplace_mode == INPLACE_TWO_SGLISTS) {
+ /*
+ * For now we keep it simple and only test the case where the
+ * two scatterlists have identical entries, rather than
+ * different entries that split up the same memory differently.
+ */
+ memcpy(tsgls->dst.sgl, tsgls->src.sgl,
+ tsgls->src.nents * sizeof(tsgls->src.sgl[0]));
+ memcpy(tsgls->dst.sgl_saved, tsgls->src.sgl,
+ tsgls->src.nents * sizeof(tsgls->src.sgl[0]));
+ tsgls->dst.sgl_ptr = tsgls->dst.sgl;
+ tsgls->dst.nents = tsgls->src.nents;
+ return 0;
+ }
+ /* Out of place */
return build_test_sglist(&tsgls->dst,
cfg->dst_divs[0].proportion_of_total ?
cfg->dst_divs : cfg->src_divs,
@@ -995,9 +1035,19 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
p += scnprintf(p, end - p, "random:");
- if (prandom_u32() % 2 == 0) {
- cfg->inplace = true;
- p += scnprintf(p, end - p, " inplace");
+ switch (prandom_u32() % 4) {
+ case 0:
+ case 1:
+ cfg->inplace_mode = OUT_OF_PLACE;
+ break;
+ case 2:
+ cfg->inplace_mode = INPLACE_ONE_SGLIST;
+ p += scnprintf(p, end - p, " inplace_one_sglist");
+ break;
+ default:
+ cfg->inplace_mode = INPLACE_TWO_SGLISTS;
+ p += scnprintf(p, end - p, " inplace_two_sglists");
+ break;
}
if (prandom_u32() % 2 == 0) {
@@ -1034,7 +1084,7 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
cfg->req_flags);
p += scnprintf(p, end - p, "]");
- if (!cfg->inplace && prandom_u32() % 2 == 0) {
+ if (cfg->inplace_mode == OUT_OF_PLACE && prandom_u32() % 2 == 0) {
p += scnprintf(p, end - p, " dst_divs=[");
p = generate_random_sgl_divisions(cfg->dst_divs,
ARRAY_SIZE(cfg->dst_divs),
@@ -2085,7 +2135,8 @@ static int test_aead_vec_cfg(int enc, const struct aead_testvec *vec,
/* Check for the correct output (ciphertext or plaintext) */
err = verify_correct_output(&tsgls->dst, enc ? vec->ctext : vec->ptext,
enc ? vec->clen : vec->plen,
- vec->alen, enc || !cfg->inplace);
+ vec->alen,
+ enc || cfg->inplace_mode == OUT_OF_PLACE);
if (err == -EOVERFLOW) {
pr_err("alg: aead: %s %s overran dst buffer on test vector %s, cfg=\"%s\"\n",
driver, op, vec_name, cfg->name);