From 443c0d7ed9d3815b3425ca12d65337d52b9a0c34 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 7 Aug 2015 16:00:04 +0800 Subject: [PATCH 1/3] crypto: authencesn - Fix breakage with new ESP code The ESP code has been updated to generate a completely linear AD SG list. This unfortunately broke authencesn which expects the AD to be divided into at least three parts. This patch fixes it to cope with the new format. Later we will fix it properly to accept arbitrary input and not rely on the input being linear as part of the AEAD conversion. Fixes: 7021b2e1cddd ("esp4: Switch to new AEAD interface") Signed-off-by: Herbert Xu --- crypto/authencesn.c | 44 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/crypto/authencesn.c b/crypto/authencesn.c index a3da6770bc9e..b8efe36ce114 100644 --- a/crypto/authencesn.c +++ b/crypto/authencesn.c @@ -393,8 +393,6 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv, struct scatterlist *cipher = areq_ctx->cipher; struct scatterlist *hsg = areq_ctx->hsg; struct scatterlist *tsg = areq_ctx->tsg; - struct scatterlist *assoc1; - struct scatterlist *assoc2; unsigned int ivsize = crypto_aead_ivsize(authenc_esn); unsigned int cryptlen = req->cryptlen; struct page *dstp; @@ -412,27 +410,19 @@ static int crypto_authenc_esn_genicv(struct aead_request *req, u8 *iv, cryptlen += ivsize; } - if (sg_is_last(assoc)) - return -EINVAL; - - assoc1 = assoc + 1; - if (sg_is_last(assoc1)) - return -EINVAL; - - assoc2 = assoc + 2; - if (!sg_is_last(assoc2)) + if (assoc->length < 12) return -EINVAL; sg_init_table(hsg, 2); - sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset); - sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset); + sg_set_page(hsg, sg_page(assoc), 4, assoc->offset); + sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8); sg_init_table(tsg, 1); - sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset); + sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4); areq_ctx->cryptlen = cryptlen; - areq_ctx->headlen = assoc->length + assoc2->length; - areq_ctx->trailen = assoc1->length; + areq_ctx->headlen = 8; + areq_ctx->trailen = 4; areq_ctx->sg = dst; areq_ctx->complete = authenc_esn_geniv_ahash_done; @@ -563,8 +553,6 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv, struct scatterlist *cipher = areq_ctx->cipher; struct scatterlist *hsg = areq_ctx->hsg; struct scatterlist *tsg = areq_ctx->tsg; - struct scatterlist *assoc1; - struct scatterlist *assoc2; unsigned int ivsize = crypto_aead_ivsize(authenc_esn); struct page *srcp; u8 *vsrc; @@ -580,27 +568,19 @@ static int crypto_authenc_esn_iverify(struct aead_request *req, u8 *iv, cryptlen += ivsize; } - if (sg_is_last(assoc)) - return -EINVAL; - - assoc1 = assoc + 1; - if (sg_is_last(assoc1)) - return -EINVAL; - - assoc2 = assoc + 2; - if (!sg_is_last(assoc2)) + if (assoc->length < 12) return -EINVAL; sg_init_table(hsg, 2); - sg_set_page(hsg, sg_page(assoc), assoc->length, assoc->offset); - sg_set_page(hsg + 1, sg_page(assoc2), assoc2->length, assoc2->offset); + sg_set_page(hsg, sg_page(assoc), 4, assoc->offset); + sg_set_page(hsg + 1, sg_page(assoc), 4, assoc->offset + 8); sg_init_table(tsg, 1); - sg_set_page(tsg, sg_page(assoc1), assoc1->length, assoc1->offset); + sg_set_page(tsg, sg_page(assoc), 4, assoc->offset + 4); areq_ctx->cryptlen = cryptlen; - areq_ctx->headlen = assoc->length + assoc2->length; - areq_ctx->trailen = assoc1->length; + areq_ctx->headlen = 8; + areq_ctx->trailen = 4; areq_ctx->sg = src; areq_ctx->complete = authenc_esn_verify_ahash_done; From d3392f41f6d3cd0a034bd0aca47fabea2b47218e Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Sat, 8 Aug 2015 08:47:28 +0200 Subject: [PATCH 2/3] crypto: nx - respect sg limit bounds when building sg lists for SHA Commit 000851119e80 changed sha256/512 update functions to pass more data to nx_build_sg_list(), which ends with sg list overflows and usually with update functions failing for data larger than max_sg_len * NX_PAGE_SIZE. This happens because: - both "total" and "to_process" are updated, which leads to "to_process" getting overflowed for some data lengths For example: In first iteration "total" is 50, and let's assume "to_process" is 30 due to sg limits. At the end of first iteration "total" is set to 20. At start of 2nd iteration "to_process" overflows on: to_process = total - to_process; - "in_sg" is not reset to nx_ctx->in_sg after each iteration - nx_build_sg_list() is hitting overflow because the amount of data passed to it would require more than sgmax elements - as consequence of previous item, data stored in overflowed sg list may no longer be aligned to SHA*_BLOCK_SIZE This patch changes sha256/512 update functions so that "to_process" respects sg limits and never tries to pass more data to nx_build_sg_list() to avoid overflows. "to_process" is calculated as minimum of "total" and sg limits at start of every iteration. Fixes: 000851119e80 ("crypto: nx - Fix SHA concurrence issue and sg limit bounds") Signed-off-by: Jan Stancek Cc: stable@vger.kernel.org Cc: Leonidas Da Silva Barbosa Cc: Marcelo Henrique Cerri Cc: Fionnuala Gunter Cc: "David S. Miller" Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx-sha256.c | 27 ++++++++++++++++----------- drivers/crypto/nx/nx-sha512.c | 28 ++++++++++++++++------------ 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c index 08f8d5cd6334..becb738c897b 100644 --- a/drivers/crypto/nx/nx-sha256.c +++ b/drivers/crypto/nx/nx-sha256.c @@ -71,7 +71,6 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, struct sha256_state *sctx = shash_desc_ctx(desc); struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb; - struct nx_sg *in_sg; struct nx_sg *out_sg; u64 to_process = 0, leftover, total; unsigned long irq_flags; @@ -97,7 +96,6 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION; - in_sg = nx_ctx->in_sg; max_sg_len = min_t(u64, nx_ctx->ap->sglen, nx_driver.of.max_sg_len/sizeof(struct nx_sg)); max_sg_len = min_t(u64, max_sg_len, @@ -114,17 +112,12 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, } do { - /* - * to_process: the SHA256_BLOCK_SIZE data chunk to process in - * this update. This value is also restricted by the sg list - * limits. - */ - to_process = total - to_process; - to_process = to_process & ~(SHA256_BLOCK_SIZE - 1); + int used_sgs = 0; + struct nx_sg *in_sg = nx_ctx->in_sg; if (buf_len) { data_len = buf_len; - in_sg = nx_build_sg_list(nx_ctx->in_sg, + in_sg = nx_build_sg_list(in_sg, (u8 *) sctx->buf, &data_len, max_sg_len); @@ -133,15 +126,27 @@ static int nx_sha256_update(struct shash_desc *desc, const u8 *data, rc = -EINVAL; goto out; } + used_sgs = in_sg - nx_ctx->in_sg; } + /* to_process: SHA256_BLOCK_SIZE aligned chunk to be + * processed in this iteration. This value is restricted + * by sg list limits and number of sgs we already used + * for leftover data. (see above) + * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len, + * but because data may not be aligned, we need to account + * for that too. */ + to_process = min_t(u64, total, + (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE); + to_process = to_process & ~(SHA256_BLOCK_SIZE - 1); + data_len = to_process - buf_len; in_sg = nx_build_sg_list(in_sg, (u8 *) data, &data_len, max_sg_len); nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg); - to_process = (data_len + buf_len); + to_process = data_len + buf_len; leftover = total - to_process; /* diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c index aff0fe58eac0..b6e183d58d73 100644 --- a/drivers/crypto/nx/nx-sha512.c +++ b/drivers/crypto/nx/nx-sha512.c @@ -71,7 +71,6 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, struct sha512_state *sctx = shash_desc_ctx(desc); struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base); struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb; - struct nx_sg *in_sg; struct nx_sg *out_sg; u64 to_process, leftover = 0, total; unsigned long irq_flags; @@ -97,7 +96,6 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION; - in_sg = nx_ctx->in_sg; max_sg_len = min_t(u64, nx_ctx->ap->sglen, nx_driver.of.max_sg_len/sizeof(struct nx_sg)); max_sg_len = min_t(u64, max_sg_len, @@ -114,18 +112,12 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, } do { - /* - * to_process: the SHA512_BLOCK_SIZE data chunk to process in - * this update. This value is also restricted by the sg list - * limits. - */ - to_process = total - leftover; - to_process = to_process & ~(SHA512_BLOCK_SIZE - 1); - leftover = total - to_process; + int used_sgs = 0; + struct nx_sg *in_sg = nx_ctx->in_sg; if (buf_len) { data_len = buf_len; - in_sg = nx_build_sg_list(nx_ctx->in_sg, + in_sg = nx_build_sg_list(in_sg, (u8 *) sctx->buf, &data_len, max_sg_len); @@ -133,8 +125,20 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, rc = -EINVAL; goto out; } + used_sgs = in_sg - nx_ctx->in_sg; } + /* to_process: SHA512_BLOCK_SIZE aligned chunk to be + * processed in this iteration. This value is restricted + * by sg list limits and number of sgs we already used + * for leftover data. (see above) + * In ideal case, we could allow NX_PAGE_SIZE * max_sg_len, + * but because data may not be aligned, we need to account + * for that too. */ + to_process = min_t(u64, total, + (max_sg_len - 1 - used_sgs) * NX_PAGE_SIZE); + to_process = to_process & ~(SHA512_BLOCK_SIZE - 1); + data_len = to_process - buf_len; in_sg = nx_build_sg_list(in_sg, (u8 *) data, &data_len, max_sg_len); @@ -146,7 +150,7 @@ static int nx_sha512_update(struct shash_desc *desc, const u8 *data, goto out; } - to_process = (data_len + buf_len); + to_process = data_len + buf_len; leftover = total - to_process; /* From b310c178e6d897f82abb9da3af1cd7c02b09f592 Mon Sep 17 00:00:00 2001 From: Horia Geant? Date: Tue, 11 Aug 2015 20:19:20 +0300 Subject: [PATCH 3/3] crypto: caam - fix memory corruption in ahash_final_ctx When doing pointer operation for accessing the HW S/G table, a value representing number of entries (and not number of bytes) must be used. Cc: # 3.6+ Fixes: 045e36780f115 ("crypto: caam - ahash hmac support") Signed-off-by: Horia Geant? Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index dae1e8099969..f9c78751989e 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -909,13 +909,14 @@ static int ahash_final_ctx(struct ahash_request *req) state->buflen_1; u32 *sh_desc = ctx->sh_desc_fin, *desc; dma_addr_t ptr = ctx->sh_desc_fin_dma; - int sec4_sg_bytes; + int sec4_sg_bytes, sec4_sg_src_index; int digestsize = crypto_ahash_digestsize(ahash); struct ahash_edesc *edesc; int ret = 0; int sh_len; - sec4_sg_bytes = (1 + (buflen ? 1 : 0)) * sizeof(struct sec4_sg_entry); + sec4_sg_src_index = 1 + (buflen ? 1 : 0); + sec4_sg_bytes = sec4_sg_src_index * sizeof(struct sec4_sg_entry); /* allocate space for base edesc and hw desc commands, link tables */ edesc = kmalloc(sizeof(struct ahash_edesc) + DESC_JOB_IO_LEN + @@ -942,7 +943,7 @@ static int ahash_final_ctx(struct ahash_request *req) state->buf_dma = try_buf_map_to_sec4_sg(jrdev, edesc->sec4_sg + 1, buf, state->buf_dma, buflen, last_buflen); - (edesc->sec4_sg + sec4_sg_bytes - 1)->len |= SEC4_SG_LEN_FIN; + (edesc->sec4_sg + sec4_sg_src_index - 1)->len |= SEC4_SG_LEN_FIN; edesc->sec4_sg_dma = dma_map_single(jrdev, edesc->sec4_sg, sec4_sg_bytes, DMA_TO_DEVICE);