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>
This commit is contained in:
parent
f16a005cde
commit
f17f9e9069
|
@ -232,6 +232,20 @@ enum finalization_type {
|
||||||
FINALIZATION_TYPE_DIGEST, /* use digest() */
|
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
|
#define TEST_SG_TOTAL 10000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -265,7 +279,7 @@ struct test_sg_division {
|
||||||
* crypto test vector can be tested.
|
* crypto test vector can be tested.
|
||||||
*
|
*
|
||||||
* @name: name of this config, logged for debugging purposes if a test fails
|
* @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
|
* @req_flags: extra request_flags, e.g. CRYPTO_TFM_REQ_MAY_SLEEP
|
||||||
* @src_divs: description of how to arrange the source scatterlist
|
* @src_divs: description of how to arrange the source scatterlist
|
||||||
* @dst_divs: description of how to arrange the dst scatterlist, if applicable
|
* @dst_divs: description of how to arrange the dst scatterlist, if applicable
|
||||||
|
@ -282,7 +296,7 @@ struct test_sg_division {
|
||||||
*/
|
*/
|
||||||
struct testvec_config {
|
struct testvec_config {
|
||||||
const char *name;
|
const char *name;
|
||||||
bool inplace;
|
enum inplace_mode inplace_mode;
|
||||||
u32 req_flags;
|
u32 req_flags;
|
||||||
struct test_sg_division src_divs[XBUFSIZE];
|
struct test_sg_division src_divs[XBUFSIZE];
|
||||||
struct test_sg_division dst_divs[XBUFSIZE];
|
struct test_sg_division dst_divs[XBUFSIZE];
|
||||||
|
@ -307,11 +321,16 @@ struct testvec_config {
|
||||||
/* Configs for skciphers and aeads */
|
/* Configs for skciphers and aeads */
|
||||||
static const struct testvec_config default_cipher_testvec_configs[] = {
|
static const struct testvec_config default_cipher_testvec_configs[] = {
|
||||||
{
|
{
|
||||||
.name = "in-place",
|
.name = "in-place (one sglist)",
|
||||||
.inplace = true,
|
.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 } },
|
.src_divs = { { .proportion_of_total = 10000 } },
|
||||||
}, {
|
}, {
|
||||||
.name = "out-of-place",
|
.name = "out-of-place",
|
||||||
|
.inplace_mode = OUT_OF_PLACE,
|
||||||
.src_divs = { { .proportion_of_total = 10000 } },
|
.src_divs = { { .proportion_of_total = 10000 } },
|
||||||
}, {
|
}, {
|
||||||
.name = "unaligned buffer, offset=1",
|
.name = "unaligned buffer, offset=1",
|
||||||
|
@ -349,7 +368,7 @@ static const struct testvec_config default_cipher_testvec_configs[] = {
|
||||||
.key_offset = 3,
|
.key_offset = 3,
|
||||||
}, {
|
}, {
|
||||||
.name = "misaligned splits crossing pages, inplace",
|
.name = "misaligned splits crossing pages, inplace",
|
||||||
.inplace = true,
|
.inplace_mode = INPLACE_ONE_SGLIST,
|
||||||
.src_divs = {
|
.src_divs = {
|
||||||
{
|
{
|
||||||
.proportion_of_total = 7500,
|
.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);
|
iov_iter_kvec(&input, WRITE, inputs, nr_inputs, src_total_len);
|
||||||
err = build_test_sglist(&tsgls->src, cfg->src_divs, alignmask,
|
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) :
|
max(dst_total_len, src_total_len) :
|
||||||
src_total_len,
|
src_total_len,
|
||||||
&input, NULL);
|
&input, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return 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.sgl_ptr = tsgls->src.sgl;
|
||||||
tsgls->dst.nents = tsgls->src.nents;
|
tsgls->dst.nents = tsgls->src.nents;
|
||||||
return 0;
|
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,
|
return build_test_sglist(&tsgls->dst,
|
||||||
cfg->dst_divs[0].proportion_of_total ?
|
cfg->dst_divs[0].proportion_of_total ?
|
||||||
cfg->dst_divs : cfg->src_divs,
|
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:");
|
p += scnprintf(p, end - p, "random:");
|
||||||
|
|
||||||
if (prandom_u32() % 2 == 0) {
|
switch (prandom_u32() % 4) {
|
||||||
cfg->inplace = true;
|
case 0:
|
||||||
p += scnprintf(p, end - p, " inplace");
|
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) {
|
if (prandom_u32() % 2 == 0) {
|
||||||
|
@ -1034,7 +1084,7 @@ static void generate_random_testvec_config(struct testvec_config *cfg,
|
||||||
cfg->req_flags);
|
cfg->req_flags);
|
||||||
p += scnprintf(p, end - p, "]");
|
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 += scnprintf(p, end - p, " dst_divs=[");
|
||||||
p = generate_random_sgl_divisions(cfg->dst_divs,
|
p = generate_random_sgl_divisions(cfg->dst_divs,
|
||||||
ARRAY_SIZE(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) */
|
/* Check for the correct output (ciphertext or plaintext) */
|
||||||
err = verify_correct_output(&tsgls->dst, enc ? vec->ctext : vec->ptext,
|
err = verify_correct_output(&tsgls->dst, enc ? vec->ctext : vec->ptext,
|
||||||
enc ? vec->clen : vec->plen,
|
enc ? vec->clen : vec->plen,
|
||||||
vec->alen, enc || !cfg->inplace);
|
vec->alen,
|
||||||
|
enc || cfg->inplace_mode == OUT_OF_PLACE);
|
||||||
if (err == -EOVERFLOW) {
|
if (err == -EOVERFLOW) {
|
||||||
pr_err("alg: aead: %s %s overran dst buffer on test vector %s, cfg=\"%s\"\n",
|
pr_err("alg: aead: %s %s overran dst buffer on test vector %s, cfg=\"%s\"\n",
|
||||||
driver, op, vec_name, cfg->name);
|
driver, op, vec_name, cfg->name);
|
||||||
|
|
Loading…
Reference in New Issue