* [PATCH 0/4] Fix synchronous fallback path for request chaining
@ 2025-03-21 8:43 Herbert Xu
2025-03-21 8:43 ` [PATCH 1/4] crypto: hash - Fix synchronous ahash chaining fallback Herbert Xu
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Herbert Xu @ 2025-03-21 8:43 UTC (permalink / raw)
To: Linux Crypto Mailing List; +Cc: Cabiddu, Giovanni
It turns out that the fallback path for synchronous algorithms
is broken for ahash and acomp. It was difficult to identify
because a separate fast path already is normally used for shash
and scomp. So to reproduce this crash, you would either have to
create a new algorithm that is synchronous, or disable the fast
path for scomp and shash.
This patch series fixes that particular fallback path and adds
multibuffer testing for ahash and acomp. Note that you may not
be able to reproduce the crash without disabling the fast paths
or adding your own custom synchronous acomp/ahash algorithm that
does not support chaining.
Herbert Xu (4):
crypto: hash - Fix synchronous ahash chaining fallback
crypto: testmgr - Add multibuffer hash testing
crypto: acomp - Fix synchronous acomp chaining fallback
crypto: testmgr - Add multibuffer acomp testing
crypto/acompress.c | 33 ++---
crypto/ahash.c | 60 +++++----
crypto/testmgr.c | 302 ++++++++++++++++++++++++++++++++-------------
3 files changed, 254 insertions(+), 141 deletions(-)
--
2.39.5
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/4] crypto: hash - Fix synchronous ahash chaining fallback
2025-03-21 8:43 [PATCH 0/4] Fix synchronous fallback path for request chaining Herbert Xu
@ 2025-03-21 8:43 ` Herbert Xu
2025-03-21 8:43 ` [PATCH 2/4] crypto: testmgr - Add multibuffer hash testing Herbert Xu
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Herbert Xu @ 2025-03-21 8:43 UTC (permalink / raw)
To: Linux Crypto Mailing List; +Cc: Cabiddu, Giovanni
The synchronous ahash fallback code paths are broken because the
ahash_restore_req assumes there is always a state object. Fix this
by removing the state from ahash_restore_req and localising it to
the asynchronous completion callback.
Also add a missing synchronous finish call in ahash_def_digest_finish.
Fixes: f2ffe5a9183d ("crypto: hash - Add request chaining API")
Fixes: 439963cdc3aa ("crypto: ahash - Add virtual address support")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/ahash.c | 60 +++++++++++++++++++++++---------------------------
1 file changed, 28 insertions(+), 32 deletions(-)
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 9c26175c21a8..f0068c72a9e1 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -57,8 +57,9 @@ struct ahash_save_req_state {
static void ahash_reqchain_done(void *data, int err);
static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt);
-static void ahash_restore_req(struct ahash_save_req_state *state);
+static void ahash_restore_req(struct ahash_request *req);
static void ahash_def_finup_done1(void *data, int err);
+static int ahash_def_finup_finish1(struct ahash_request *req, int err);
static int ahash_def_finup(struct ahash_request *req);
static int hash_walk_next(struct crypto_hash_walk *walk)
@@ -357,14 +358,15 @@ static int ahash_reqchain_virt(struct ahash_save_req_state *state,
return err;
}
-static int ahash_reqchain_finish(struct ahash_save_req_state *state,
+static int ahash_reqchain_finish(struct ahash_request *req0,
+ struct ahash_save_req_state *state,
int err, u32 mask)
{
- struct ahash_request *req0 = state->req0;
struct ahash_request *req = state->cur;
struct crypto_ahash *tfm;
struct ahash_request *n;
bool update;
+ u8 *page;
err = ahash_reqchain_virt(state, err, mask);
if (err == -EINPROGRESS || err == -EBUSY)
@@ -418,7 +420,12 @@ static int ahash_reqchain_finish(struct ahash_save_req_state *state,
list_add_tail(&req->base.list, &req0->base.list);
}
- ahash_restore_req(state);
+ page = state->page;
+ if (page) {
+ memset(page, 0, PAGE_SIZE);
+ free_page((unsigned long)page);
+ }
+ ahash_restore_req(req0);
out:
return err;
@@ -437,7 +444,8 @@ static void ahash_reqchain_done(void *data, int err)
goto notify;
}
- err = ahash_reqchain_finish(state, err, CRYPTO_TFM_REQ_MAY_BACKLOG);
+ err = ahash_reqchain_finish(state->req0, state, err,
+ CRYPTO_TFM_REQ_MAY_BACKLOG);
if (err == -EBUSY)
return;
@@ -513,13 +521,10 @@ static int ahash_do_req_chain(struct ahash_request *req,
if (err == -EBUSY || err == -EINPROGRESS)
return -EBUSY;
- return ahash_reqchain_finish(state, err, ~0);
+ return ahash_reqchain_finish(req, state, err, ~0);
out_free_page:
- if (page) {
- memset(page, 0, PAGE_SIZE);
- free_page((unsigned long)page);
- }
+ free_page((unsigned long)page);
out_set_chain:
req->base.err = err;
@@ -578,18 +583,15 @@ static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
req->base.complete = cplt;
req->base.data = state;
state->req0 = req;
- state->page = NULL;
return 0;
}
-static void ahash_restore_req(struct ahash_save_req_state *state)
+static void ahash_restore_req(struct ahash_request *req)
{
- struct ahash_request *req = state->req0;
+ struct ahash_save_req_state *state;
struct crypto_ahash *tfm;
- free_page((unsigned long)state->page);
-
tfm = crypto_ahash_reqtfm(req);
if (!ahash_is_async(tfm))
return;
@@ -680,9 +682,8 @@ int crypto_ahash_finup(struct ahash_request *req)
}
EXPORT_SYMBOL_GPL(crypto_ahash_finup);
-static int ahash_def_digest_finish(struct ahash_save_req_state *state, int err)
+static int ahash_def_digest_finish(struct ahash_request *req, int err)
{
- struct ahash_request *req = state->req0;
struct crypto_ahash *tfm;
if (err)
@@ -696,8 +697,10 @@ static int ahash_def_digest_finish(struct ahash_save_req_state *state, int err)
if (err == -EINPROGRESS || err == -EBUSY)
return err;
+ return ahash_def_finup_finish1(req, err);
+
out:
- ahash_restore_req(state);
+ ahash_restore_req(req);
return err;
}
@@ -714,7 +717,7 @@ static void ahash_def_digest_done(void *data, int err)
areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- err = ahash_def_digest_finish(state0, err);
+ err = ahash_def_digest_finish(areq, err);
if (err == -EINPROGRESS || err == -EBUSY)
return;
@@ -724,20 +727,17 @@ static void ahash_def_digest_done(void *data, int err)
static int ahash_def_digest(struct ahash_request *req)
{
- struct ahash_save_req_state *state;
int err;
err = ahash_save_req(req, ahash_def_digest_done);
if (err)
return err;
- state = req->base.data;
-
err = crypto_ahash_init(req);
if (err == -EINPROGRESS || err == -EBUSY)
return err;
- return ahash_def_digest_finish(state, err);
+ return ahash_def_digest_finish(req, err);
}
int crypto_ahash_digest(struct ahash_request *req)
@@ -779,13 +779,12 @@ static void ahash_def_finup_done2(void *data, int err)
if (err == -EINPROGRESS)
return;
- ahash_restore_req(state);
+ ahash_restore_req(areq);
ahash_request_complete(areq, err);
}
-static int ahash_def_finup_finish1(struct ahash_save_req_state *state, int err)
+static int ahash_def_finup_finish1(struct ahash_request *req, int err)
{
- struct ahash_request *req = state->req0;
struct crypto_ahash *tfm;
if (err)
@@ -800,7 +799,7 @@ static int ahash_def_finup_finish1(struct ahash_save_req_state *state, int err)
return err;
out:
- ahash_restore_req(state);
+ ahash_restore_req(req);
return err;
}
@@ -817,7 +816,7 @@ static void ahash_def_finup_done1(void *data, int err)
areq->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
- err = ahash_def_finup_finish1(state0, err);
+ err = ahash_def_finup_finish1(areq, err);
if (err == -EINPROGRESS || err == -EBUSY)
return;
@@ -827,20 +826,17 @@ static void ahash_def_finup_done1(void *data, int err)
static int ahash_def_finup(struct ahash_request *req)
{
- struct ahash_save_req_state *state;
int err;
err = ahash_save_req(req, ahash_def_finup_done1);
if (err)
return err;
- state = req->base.data;
-
err = crypto_ahash_update(req);
if (err == -EINPROGRESS || err == -EBUSY)
return err;
- return ahash_def_finup_finish1(state, err);
+ return ahash_def_finup_finish1(req, err);
}
int crypto_ahash_export(struct ahash_request *req, void *out)
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 2/4] crypto: testmgr - Add multibuffer hash testing
2025-03-21 8:43 [PATCH 0/4] Fix synchronous fallback path for request chaining Herbert Xu
2025-03-21 8:43 ` [PATCH 1/4] crypto: hash - Fix synchronous ahash chaining fallback Herbert Xu
@ 2025-03-21 8:43 ` Herbert Xu
2025-03-21 8:43 ` [PATCH 3/4] crypto: acomp - Fix synchronous acomp chaining fallback Herbert Xu
2025-03-21 8:43 ` [PATCH 4/4] crypto: testmgr - Add multibuffer acomp testing Herbert Xu
3 siblings, 0 replies; 5+ messages in thread
From: Herbert Xu @ 2025-03-21 8:43 UTC (permalink / raw)
To: Linux Crypto Mailing List; +Cc: Cabiddu, Giovanni
This is based on a patch by Eric Biggers <ebiggers@google.com>.
Add limited self-test for multibuffer hash code path. This tests
only a single request in chain of a random length. The other
requests are either all of the same length as the one being tested,
or random lengths between 0 and PAGE_SIZE * 2 * XBUFSIZE.
Potential extension include testing all requests rather than just
the single one.
Link: https://lore.kernel.org/all/20241001153718.111665-3-ebiggers@kernel.org/
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/testmgr.c | 160 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 136 insertions(+), 24 deletions(-)
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 140872765dcd..5694901e5242 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -58,6 +58,9 @@ module_param(fuzz_iterations, uint, 0644);
MODULE_PARM_DESC(fuzz_iterations, "number of fuzz test iterations");
#endif
+/* Multibuffer is unlimited. Set arbitrary limit for testing. */
+#define MAX_MB_MSGS 16
+
#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
/* a perfect nop */
@@ -299,6 +302,13 @@ struct test_sg_division {
* @key_offset_relative_to_alignmask: if true, add the algorithm's alignmask to
* the @key_offset
* @finalization_type: what finalization function to use for hashes
+ * @multibuffer: test with multibuffer
+ * @multibuffer_index: random number used to generate the message index to use
+ * for multibuffer.
+ * @multibuffer_uneven: test with multibuffer using uneven lengths
+ * @multibuffer_lens: random lengths to make chained request uneven
+ * @multibuffer_count: random number used to generate the num_msgs parameter
+ * for multibuffer
* @nosimd: execute with SIMD disabled? Requires !CRYPTO_TFM_REQ_MAY_SLEEP.
* This applies to the parts of the operation that aren't controlled
* individually by @nosimd_setkey or @src_divs[].nosimd.
@@ -318,6 +328,11 @@ struct testvec_config {
enum finalization_type finalization_type;
bool nosimd;
bool nosimd_setkey;
+ bool multibuffer;
+ unsigned int multibuffer_index;
+ unsigned int multibuffer_count;
+ bool multibuffer_uneven;
+ unsigned int multibuffer_lens[MAX_MB_MSGS];
};
#define TESTVEC_CONFIG_NAMELEN 192
@@ -557,6 +572,7 @@ struct test_sglist {
char *bufs[XBUFSIZE];
struct scatterlist sgl[XBUFSIZE];
struct scatterlist sgl_saved[XBUFSIZE];
+ struct scatterlist full_sgl[XBUFSIZE];
struct scatterlist *sgl_ptr;
unsigned int nents;
};
@@ -670,6 +686,11 @@ static int build_test_sglist(struct test_sglist *tsgl,
sg_mark_end(&tsgl->sgl[tsgl->nents - 1]);
tsgl->sgl_ptr = tsgl->sgl;
memcpy(tsgl->sgl_saved, tsgl->sgl, tsgl->nents * sizeof(tsgl->sgl[0]));
+
+ sg_init_table(tsgl->full_sgl, XBUFSIZE);
+ for (i = 0; i < XBUFSIZE; i++)
+ sg_set_buf(tsgl->full_sgl, tsgl->bufs[i], PAGE_SIZE * 2);
+
return 0;
}
@@ -1146,6 +1167,27 @@ static void generate_random_testvec_config(struct rnd_state *rng,
break;
}
+ if (prandom_bool(rng)) {
+ int i;
+
+ cfg->multibuffer = true;
+ cfg->multibuffer_count = prandom_u32_state(rng);
+ cfg->multibuffer_count %= MAX_MB_MSGS;
+ if (cfg->multibuffer_count++) {
+ cfg->multibuffer_index = prandom_u32_state(rng);
+ cfg->multibuffer_index %= cfg->multibuffer_count;
+ }
+
+ cfg->multibuffer_uneven = prandom_bool(rng);
+ for (i = 0; i < MAX_MB_MSGS; i++)
+ cfg->multibuffer_lens[i] =
+ generate_random_length(rng, PAGE_SIZE * 2 * XBUFSIZE);
+
+ p += scnprintf(p, end - p, " multibuffer(%d/%d%s)",
+ cfg->multibuffer_index, cfg->multibuffer_count,
+ cfg->multibuffer_uneven ? "/uneven" : "");
+ }
+
if (!(cfg->req_flags & CRYPTO_TFM_REQ_MAY_SLEEP)) {
if (prandom_bool(rng)) {
cfg->nosimd = true;
@@ -1450,6 +1492,7 @@ static int do_ahash_op(int (*op)(struct ahash_request *req),
struct ahash_request *req,
struct crypto_wait *wait, bool nosimd)
{
+ struct ahash_request *r2;
int err;
if (nosimd)
@@ -1460,7 +1503,15 @@ static int do_ahash_op(int (*op)(struct ahash_request *req),
if (nosimd)
crypto_reenable_simd_for_test();
- return crypto_wait_req(err, wait);
+ err = crypto_wait_req(err, wait);
+ if (err)
+ return err;
+
+ list_for_each_entry(r2, &req->base.list, base.list)
+ if (r2->base.err)
+ return r2->base.err;
+
+ return 0;
}
static int check_nonfinal_ahash_op(const char *op, int err,
@@ -1481,20 +1532,65 @@ static int check_nonfinal_ahash_op(const char *op, int err,
return 0;
}
+static void setup_ahash_multibuffer(
+ struct ahash_request *reqs[MAX_MB_MSGS],
+ const struct testvec_config *cfg,
+ struct test_sglist *tsgl)
+{
+ struct scatterlist *sg = tsgl->full_sgl;
+ static u8 trash[HASH_MAX_DIGESTSIZE];
+ struct ahash_request *req = reqs[0];
+ unsigned int num_msgs;
+ unsigned int msg_idx;
+ int i;
+
+ if (!cfg->multibuffer)
+ return;
+
+ num_msgs = cfg->multibuffer_count;
+ if (num_msgs == 1)
+ return;
+
+ msg_idx = cfg->multibuffer_index;
+ for (i = 1; i < num_msgs; i++) {
+ struct ahash_request *r2 = reqs[i];
+ unsigned int nbytes = req->nbytes;
+
+ if (cfg->multibuffer_uneven)
+ nbytes = cfg->multibuffer_lens[i];
+
+ ahash_request_set_callback(r2, req->base.flags, NULL, NULL);
+ ahash_request_set_crypt(r2, sg, trash, nbytes);
+ ahash_request_chain(r2, req);
+ }
+
+ if (msg_idx) {
+ reqs[msg_idx]->src = req->src;
+ reqs[msg_idx]->nbytes = req->nbytes;
+ reqs[msg_idx]->result = req->result;
+ req->src = sg;
+ if (cfg->multibuffer_uneven)
+ req->nbytes = cfg->multibuffer_lens[0];
+ req->result = trash;
+ }
+}
+
/* Test one hash test vector in one configuration, using the ahash API */
static int test_ahash_vec_cfg(const struct hash_testvec *vec,
const char *vec_name,
const struct testvec_config *cfg,
- struct ahash_request *req,
+ struct ahash_request *reqs[MAX_MB_MSGS],
struct test_sglist *tsgl,
u8 *hashstate)
{
+ struct ahash_request *req = reqs[0];
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
const unsigned int digestsize = crypto_ahash_digestsize(tfm);
const unsigned int statesize = crypto_ahash_statesize(tfm);
const char *driver = crypto_ahash_driver_name(tfm);
const u32 req_flags = CRYPTO_TFM_REQ_MAY_BACKLOG | cfg->req_flags;
const struct test_sg_division *divs[XBUFSIZE];
+ struct ahash_request *reqi = req;
DECLARE_CRYPTO_WAIT(wait);
unsigned int i;
struct scatterlist *pending_sgl;
@@ -1502,6 +1598,9 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
u8 result[HASH_MAX_DIGESTSIZE + TESTMGR_POISON_LEN];
int err;
+ if (cfg->multibuffer)
+ reqi = reqs[cfg->multibuffer_index];
+
/* Set the key, if specified */
if (vec->ksize) {
err = do_setkey(crypto_ahash_setkey, tfm, vec->key, vec->ksize,
@@ -1531,7 +1630,7 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
/* Do the actual hashing */
- testmgr_poison(req->__ctx, crypto_ahash_reqsize(tfm));
+ testmgr_poison(reqi->__ctx, crypto_ahash_reqsize(tfm));
testmgr_poison(result, digestsize + TESTMGR_POISON_LEN);
if (cfg->finalization_type == FINALIZATION_TYPE_DIGEST ||
@@ -1540,6 +1639,7 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
ahash_request_set_callback(req, req_flags, crypto_req_done,
&wait);
ahash_request_set_crypt(req, tsgl->sgl, result, vec->psize);
+ setup_ahash_multibuffer(reqs, cfg, tsgl);
err = do_ahash_op(crypto_ahash_digest, req, &wait, cfg->nosimd);
if (err) {
if (err == vec->digest_error)
@@ -1561,6 +1661,7 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
ahash_request_set_callback(req, req_flags, crypto_req_done, &wait);
ahash_request_set_crypt(req, NULL, result, 0);
+ setup_ahash_multibuffer(reqs, cfg, tsgl);
err = do_ahash_op(crypto_ahash_init, req, &wait, cfg->nosimd);
err = check_nonfinal_ahash_op("init", err, result, digestsize,
driver, vec_name, cfg);
@@ -1577,6 +1678,7 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
crypto_req_done, &wait);
ahash_request_set_crypt(req, pending_sgl, result,
pending_len);
+ setup_ahash_multibuffer(reqs, cfg, tsgl);
err = do_ahash_op(crypto_ahash_update, req, &wait,
divs[i]->nosimd);
err = check_nonfinal_ahash_op("update", err,
@@ -1591,7 +1693,7 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
/* Test ->export() and ->import() */
testmgr_poison(hashstate + statesize,
TESTMGR_POISON_LEN);
- err = crypto_ahash_export(req, hashstate);
+ err = crypto_ahash_export(reqi, hashstate);
err = check_nonfinal_ahash_op("export", err,
result, digestsize,
driver, vec_name, cfg);
@@ -1604,8 +1706,8 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
return -EOVERFLOW;
}
- testmgr_poison(req->__ctx, crypto_ahash_reqsize(tfm));
- err = crypto_ahash_import(req, hashstate);
+ testmgr_poison(reqi->__ctx, crypto_ahash_reqsize(tfm));
+ err = crypto_ahash_import(reqi, hashstate);
err = check_nonfinal_ahash_op("import", err,
result, digestsize,
driver, vec_name, cfg);
@@ -1619,6 +1721,7 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
ahash_request_set_callback(req, req_flags, crypto_req_done, &wait);
ahash_request_set_crypt(req, pending_sgl, result, pending_len);
+ setup_ahash_multibuffer(reqs, cfg, tsgl);
if (cfg->finalization_type == FINALIZATION_TYPE_FINAL) {
/* finish with update() and final() */
err = do_ahash_op(crypto_ahash_update, req, &wait, cfg->nosimd);
@@ -1650,7 +1753,7 @@ static int test_ahash_vec_cfg(const struct hash_testvec *vec,
static int test_hash_vec_cfg(const struct hash_testvec *vec,
const char *vec_name,
const struct testvec_config *cfg,
- struct ahash_request *req,
+ struct ahash_request *reqs[MAX_MB_MSGS],
struct shash_desc *desc,
struct test_sglist *tsgl,
u8 *hashstate)
@@ -1670,11 +1773,12 @@ static int test_hash_vec_cfg(const struct hash_testvec *vec,
return err;
}
- return test_ahash_vec_cfg(vec, vec_name, cfg, req, tsgl, hashstate);
+ return test_ahash_vec_cfg(vec, vec_name, cfg, reqs, tsgl, hashstate);
}
static int test_hash_vec(const struct hash_testvec *vec, unsigned int vec_num,
- struct ahash_request *req, struct shash_desc *desc,
+ struct ahash_request *reqs[MAX_MB_MSGS],
+ struct shash_desc *desc,
struct test_sglist *tsgl, u8 *hashstate)
{
char vec_name[16];
@@ -1686,7 +1790,7 @@ static int test_hash_vec(const struct hash_testvec *vec, unsigned int vec_num,
for (i = 0; i < ARRAY_SIZE(default_hash_testvec_configs); i++) {
err = test_hash_vec_cfg(vec, vec_name,
&default_hash_testvec_configs[i],
- req, desc, tsgl, hashstate);
+ reqs, desc, tsgl, hashstate);
if (err)
return err;
}
@@ -1703,7 +1807,7 @@ static int test_hash_vec(const struct hash_testvec *vec, unsigned int vec_num,
generate_random_testvec_config(&rng, &cfg, cfgname,
sizeof(cfgname));
err = test_hash_vec_cfg(vec, vec_name, &cfg,
- req, desc, tsgl, hashstate);
+ reqs, desc, tsgl, hashstate);
if (err)
return err;
cond_resched();
@@ -1762,11 +1866,12 @@ static void generate_random_hash_testvec(struct rnd_state *rng,
*/
static int test_hash_vs_generic_impl(const char *generic_driver,
unsigned int maxkeysize,
- struct ahash_request *req,
+ struct ahash_request *reqs[MAX_MB_MSGS],
struct shash_desc *desc,
struct test_sglist *tsgl,
u8 *hashstate)
{
+ struct ahash_request *req = reqs[0];
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
const unsigned int digestsize = crypto_ahash_digestsize(tfm);
const unsigned int blocksize = crypto_ahash_blocksize(tfm);
@@ -1864,7 +1969,7 @@ static int test_hash_vs_generic_impl(const char *generic_driver,
sizeof(cfgname));
err = test_hash_vec_cfg(&vec, vec_name, cfg,
- req, desc, tsgl, hashstate);
+ reqs, desc, tsgl, hashstate);
if (err)
goto out;
cond_resched();
@@ -1882,7 +1987,7 @@ static int test_hash_vs_generic_impl(const char *generic_driver,
#else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
static int test_hash_vs_generic_impl(const char *generic_driver,
unsigned int maxkeysize,
- struct ahash_request *req,
+ struct ahash_request *reqs[MAX_MB_MSGS],
struct shash_desc *desc,
struct test_sglist *tsgl,
u8 *hashstate)
@@ -1929,8 +2034,8 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
u32 type, u32 mask,
const char *generic_driver, unsigned int maxkeysize)
{
+ struct ahash_request *reqs[MAX_MB_MSGS] = {};
struct crypto_ahash *atfm = NULL;
- struct ahash_request *req = NULL;
struct crypto_shash *stfm = NULL;
struct shash_desc *desc = NULL;
struct test_sglist *tsgl = NULL;
@@ -1954,12 +2059,14 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
}
driver = crypto_ahash_driver_name(atfm);
- req = ahash_request_alloc(atfm, GFP_KERNEL);
- if (!req) {
- pr_err("alg: hash: failed to allocate request for %s\n",
- driver);
- err = -ENOMEM;
- goto out;
+ for (i = 0; i < MAX_MB_MSGS; i++) {
+ reqs[i] = ahash_request_alloc(atfm, GFP_KERNEL);
+ if (!reqs[i]) {
+ pr_err("alg: hash: failed to allocate request for %s\n",
+ driver);
+ err = -ENOMEM;
+ goto out;
+ }
}
/*
@@ -1995,12 +2102,12 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
if (fips_enabled && vecs[i].fips_skip)
continue;
- err = test_hash_vec(&vecs[i], i, req, desc, tsgl, hashstate);
+ err = test_hash_vec(&vecs[i], i, reqs, desc, tsgl, hashstate);
if (err)
goto out;
cond_resched();
}
- err = test_hash_vs_generic_impl(generic_driver, maxkeysize, req,
+ err = test_hash_vs_generic_impl(generic_driver, maxkeysize, reqs,
desc, tsgl, hashstate);
out:
kfree(hashstate);
@@ -2010,7 +2117,12 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
}
kfree(desc);
crypto_free_shash(stfm);
- ahash_request_free(req);
+ if (reqs[0]) {
+ ahash_request_set_callback(reqs[0], 0, NULL, NULL);
+ for (i = 1; i < MAX_MB_MSGS && reqs[i]; i++)
+ ahash_request_chain(reqs[i], reqs[0]);
+ ahash_request_free(reqs[0]);
+ }
crypto_free_ahash(atfm);
return err;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 3/4] crypto: acomp - Fix synchronous acomp chaining fallback
2025-03-21 8:43 [PATCH 0/4] Fix synchronous fallback path for request chaining Herbert Xu
2025-03-21 8:43 ` [PATCH 1/4] crypto: hash - Fix synchronous ahash chaining fallback Herbert Xu
2025-03-21 8:43 ` [PATCH 2/4] crypto: testmgr - Add multibuffer hash testing Herbert Xu
@ 2025-03-21 8:43 ` Herbert Xu
2025-03-21 8:43 ` [PATCH 4/4] crypto: testmgr - Add multibuffer acomp testing Herbert Xu
3 siblings, 0 replies; 5+ messages in thread
From: Herbert Xu @ 2025-03-21 8:43 UTC (permalink / raw)
To: Linux Crypto Mailing List; +Cc: Cabiddu, Giovanni
The synchronous acomp fallback code path is broken because the
completion code path assumes that the state object is always set
but this is only done for asynchronous algorithms.
First of all remove the assumption on the completion code path
by passing in req0 instead of the state. However, also remove
the conditional setting of the state since it's always in the
request object anyway.
Fixes: b67a02600372 ("crypto: acomp - Add request chaining and virtual addresses")
Reported-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/acompress.c | 33 +++++++++++----------------------
1 file changed, 11 insertions(+), 22 deletions(-)
diff --git a/crypto/acompress.c b/crypto/acompress.c
index 45444e99a9db..beeae34990d3 100644
--- a/crypto/acompress.c
+++ b/crypto/acompress.c
@@ -141,12 +141,8 @@ static bool acomp_request_has_nondma(struct acomp_req *req)
static void acomp_save_req(struct acomp_req *req, crypto_completion_t cplt)
{
- struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
struct acomp_req_chain *state = &req->chain;
- if (!acomp_is_async(tfm))
- return;
-
state->compl = req->base.complete;
state->data = req->base.data;
req->base.complete = cplt;
@@ -154,14 +150,9 @@ static void acomp_save_req(struct acomp_req *req, crypto_completion_t cplt)
state->req0 = req;
}
-static void acomp_restore_req(struct acomp_req_chain *state)
+static void acomp_restore_req(struct acomp_req *req)
{
- struct acomp_req *req = state->req0;
- struct crypto_acomp *tfm;
-
- tfm = crypto_acomp_reqtfm(req);
- if (!acomp_is_async(tfm))
- return;
+ struct acomp_req_chain *state = req->base.data;
req->base.complete = state->compl;
req->base.data = state->data;
@@ -207,10 +198,9 @@ static void acomp_virt_to_sg(struct acomp_req *req)
}
}
-static int acomp_reqchain_finish(struct acomp_req_chain *state,
- int err, u32 mask)
+static int acomp_reqchain_finish(struct acomp_req *req0, int err, u32 mask)
{
- struct acomp_req *req0 = state->req0;
+ struct acomp_req_chain *state = req0->base.data;
struct acomp_req *req = state->cur;
struct acomp_req *n;
@@ -243,7 +233,7 @@ static int acomp_reqchain_finish(struct acomp_req_chain *state,
list_add_tail(&req->base.list, &req0->base.list);
}
- acomp_restore_req(state);
+ acomp_restore_req(req0);
out:
return err;
@@ -262,7 +252,8 @@ static void acomp_reqchain_done(void *data, int err)
goto notify;
}
- err = acomp_reqchain_finish(state, err, CRYPTO_TFM_REQ_MAY_BACKLOG);
+ err = acomp_reqchain_finish(state->req0, err,
+ CRYPTO_TFM_REQ_MAY_BACKLOG);
if (err == -EBUSY)
return;
@@ -274,7 +265,7 @@ static int acomp_do_req_chain(struct acomp_req *req,
int (*op)(struct acomp_req *req))
{
struct crypto_acomp *tfm = crypto_acomp_reqtfm(req);
- struct acomp_req_chain *state = &req->chain;
+ struct acomp_req_chain *state;
int err;
if (crypto_acomp_req_chain(tfm) ||
@@ -289,10 +280,8 @@ static int acomp_do_req_chain(struct acomp_req *req,
if (acomp_request_has_nondma(req))
return -EINVAL;
- if (acomp_is_async(tfm)) {
- acomp_save_req(req, acomp_reqchain_done);
- state = req->base.data;
- }
+ acomp_save_req(req, acomp_reqchain_done);
+ state = req->base.data;
state->op = op;
state->cur = req;
@@ -305,7 +294,7 @@ static int acomp_do_req_chain(struct acomp_req *req,
if (err == -EBUSY || err == -EINPROGRESS)
return -EBUSY;
- return acomp_reqchain_finish(state, err, ~0);
+ return acomp_reqchain_finish(req, err, ~0);
}
int crypto_acomp_compress(struct acomp_req *req)
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH 4/4] crypto: testmgr - Add multibuffer acomp testing
2025-03-21 8:43 [PATCH 0/4] Fix synchronous fallback path for request chaining Herbert Xu
` (2 preceding siblings ...)
2025-03-21 8:43 ` [PATCH 3/4] crypto: acomp - Fix synchronous acomp chaining fallback Herbert Xu
@ 2025-03-21 8:43 ` Herbert Xu
3 siblings, 0 replies; 5+ messages in thread
From: Herbert Xu @ 2025-03-21 8:43 UTC (permalink / raw)
To: Linux Crypto Mailing List; +Cc: Cabiddu, Giovanni
Add rudimentary multibuffer acomp testing. Testing coverage is
extended to compression vectors only. However, as the compression
vectors are compressed and then decompressed, this covers both
compression and decompression.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
crypto/testmgr.c | 142 ++++++++++++++++++++++++++---------------------
1 file changed, 79 insertions(+), 63 deletions(-)
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5694901e5242..02016ae7c7dd 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3544,27 +3544,48 @@ static int test_acomp(struct crypto_acomp *tfm,
int ctcount, int dtcount)
{
const char *algo = crypto_tfm_alg_driver_name(crypto_acomp_tfm(tfm));
- unsigned int i;
- char *output, *decomp_out;
- int ret;
- struct scatterlist src, dst;
- struct acomp_req *req;
+ struct scatterlist *src = NULL, *dst = NULL;
+ struct acomp_req *reqs[MAX_MB_MSGS] = {};
+ char *decomp_out[MAX_MB_MSGS] = {};
+ char *output[MAX_MB_MSGS] = {};
struct crypto_wait wait;
+ struct acomp_req *req;
+ int ret = -ENOMEM;
+ unsigned int i;
- output = kmalloc(COMP_BUF_SIZE, GFP_KERNEL);
- if (!output)
- return -ENOMEM;
+ src = kmalloc_array(MAX_MB_MSGS, sizeof(*src), GFP_KERNEL);
+ if (!src)
+ goto out;
+ dst = kmalloc_array(MAX_MB_MSGS, sizeof(*dst), GFP_KERNEL);
+ if (!dst)
+ goto out;
- decomp_out = kmalloc(COMP_BUF_SIZE, GFP_KERNEL);
- if (!decomp_out) {
- kfree(output);
- return -ENOMEM;
+ for (i = 0; i < MAX_MB_MSGS; i++) {
+ reqs[i] = acomp_request_alloc(tfm);
+ if (!reqs[i])
+ goto out;
+
+ acomp_request_set_callback(reqs[i],
+ CRYPTO_TFM_REQ_MAY_SLEEP |
+ CRYPTO_TFM_REQ_MAY_BACKLOG,
+ crypto_req_done, &wait);
+ if (i)
+ acomp_request_chain(reqs[i], reqs[0]);
+
+ output[i] = kmalloc(COMP_BUF_SIZE, GFP_KERNEL);
+ if (!output[i])
+ goto out;
+
+ decomp_out[i] = kmalloc(COMP_BUF_SIZE, GFP_KERNEL);
+ if (!decomp_out[i])
+ goto out;
}
for (i = 0; i < ctcount; i++) {
unsigned int dlen = COMP_BUF_SIZE;
int ilen = ctemplate[i].inlen;
void *input_vec;
+ int j;
input_vec = kmemdup(ctemplate[i].input, ilen, GFP_KERNEL);
if (!input_vec) {
@@ -3572,70 +3593,61 @@ static int test_acomp(struct crypto_acomp *tfm,
goto out;
}
- memset(output, 0, dlen);
crypto_init_wait(&wait);
- sg_init_one(&src, input_vec, ilen);
- sg_init_one(&dst, output, dlen);
+ sg_init_one(src, input_vec, ilen);
- req = acomp_request_alloc(tfm);
- if (!req) {
- pr_err("alg: acomp: request alloc failed for %s\n",
- algo);
- kfree(input_vec);
- ret = -ENOMEM;
- goto out;
+ for (j = 0; j < MAX_MB_MSGS; j++) {
+ sg_init_one(dst + j, output[j], dlen);
+ acomp_request_set_params(reqs[j], src, dst + j, ilen, dlen);
}
- acomp_request_set_params(req, &src, &dst, ilen, dlen);
- acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
- crypto_req_done, &wait);
-
+ req = reqs[0];
ret = crypto_wait_req(crypto_acomp_compress(req), &wait);
if (ret) {
pr_err("alg: acomp: compression failed on test %d for %s: ret=%d\n",
i + 1, algo, -ret);
kfree(input_vec);
- acomp_request_free(req);
goto out;
}
ilen = req->dlen;
dlen = COMP_BUF_SIZE;
- sg_init_one(&src, output, ilen);
- sg_init_one(&dst, decomp_out, dlen);
crypto_init_wait(&wait);
- acomp_request_set_params(req, &src, &dst, ilen, dlen);
-
- ret = crypto_wait_req(crypto_acomp_decompress(req), &wait);
- if (ret) {
- pr_err("alg: acomp: compression failed on test %d for %s: ret=%d\n",
- i + 1, algo, -ret);
- kfree(input_vec);
- acomp_request_free(req);
- goto out;
+ for (j = 0; j < MAX_MB_MSGS; j++) {
+ sg_init_one(src + j, output[j], ilen);
+ sg_init_one(dst + j, decomp_out[j], dlen);
+ acomp_request_set_params(reqs[j], src + j, dst + j, ilen, dlen);
}
- if (req->dlen != ctemplate[i].inlen) {
- pr_err("alg: acomp: Compression test %d failed for %s: output len = %d\n",
- i + 1, algo, req->dlen);
- ret = -EINVAL;
- kfree(input_vec);
- acomp_request_free(req);
- goto out;
- }
+ crypto_wait_req(crypto_acomp_decompress(req), &wait);
+ for (j = 0; j < MAX_MB_MSGS; j++) {
+ ret = reqs[j]->base.err;
+ if (ret) {
+ pr_err("alg: acomp: compression failed on test %d (%d) for %s: ret=%d\n",
+ i + 1, j, algo, -ret);
+ kfree(input_vec);
+ goto out;
+ }
- if (memcmp(input_vec, decomp_out, req->dlen)) {
- pr_err("alg: acomp: Compression test %d failed for %s\n",
- i + 1, algo);
- hexdump(output, req->dlen);
- ret = -EINVAL;
- kfree(input_vec);
- acomp_request_free(req);
- goto out;
+ if (reqs[j]->dlen != ctemplate[i].inlen) {
+ pr_err("alg: acomp: Compression test %d (%d) failed for %s: output len = %d\n",
+ i + 1, j, algo, reqs[j]->dlen);
+ ret = -EINVAL;
+ kfree(input_vec);
+ goto out;
+ }
+
+ if (memcmp(input_vec, decomp_out[j], reqs[j]->dlen)) {
+ pr_err("alg: acomp: Compression test %d (%d) failed for %s\n",
+ i + 1, j, algo);
+ hexdump(output[j], reqs[j]->dlen);
+ ret = -EINVAL;
+ kfree(input_vec);
+ goto out;
+ }
}
kfree(input_vec);
- acomp_request_free(req);
}
for (i = 0; i < dtcount; i++) {
@@ -3649,10 +3661,9 @@ static int test_acomp(struct crypto_acomp *tfm,
goto out;
}
- memset(output, 0, dlen);
crypto_init_wait(&wait);
- sg_init_one(&src, input_vec, ilen);
- sg_init_one(&dst, output, dlen);
+ sg_init_one(src, input_vec, ilen);
+ sg_init_one(dst, output[0], dlen);
req = acomp_request_alloc(tfm);
if (!req) {
@@ -3663,7 +3674,7 @@ static int test_acomp(struct crypto_acomp *tfm,
goto out;
}
- acomp_request_set_params(req, &src, &dst, ilen, dlen);
+ acomp_request_set_params(req, src, dst, ilen, dlen);
acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);
@@ -3685,10 +3696,10 @@ static int test_acomp(struct crypto_acomp *tfm,
goto out;
}
- if (memcmp(output, dtemplate[i].output, req->dlen)) {
+ if (memcmp(output[0], dtemplate[i].output, req->dlen)) {
pr_err("alg: acomp: Decompression test %d failed for %s\n",
i + 1, algo);
- hexdump(output, req->dlen);
+ hexdump(output[0], req->dlen);
ret = -EINVAL;
kfree(input_vec);
acomp_request_free(req);
@@ -3702,8 +3713,13 @@ static int test_acomp(struct crypto_acomp *tfm,
ret = 0;
out:
- kfree(decomp_out);
- kfree(output);
+ acomp_request_free(reqs[0]);
+ for (i = 0; i < MAX_MB_MSGS; i++) {
+ kfree(output[i]);
+ kfree(decomp_out[i]);
+ }
+ kfree(dst);
+ kfree(src);
return ret;
}
--
2.39.5
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-03-21 8:43 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-21 8:43 [PATCH 0/4] Fix synchronous fallback path for request chaining Herbert Xu
2025-03-21 8:43 ` [PATCH 1/4] crypto: hash - Fix synchronous ahash chaining fallback Herbert Xu
2025-03-21 8:43 ` [PATCH 2/4] crypto: testmgr - Add multibuffer hash testing Herbert Xu
2025-03-21 8:43 ` [PATCH 3/4] crypto: acomp - Fix synchronous acomp chaining fallback Herbert Xu
2025-03-21 8:43 ` [PATCH 4/4] crypto: testmgr - Add multibuffer acomp testing Herbert Xu
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.