Skip to content

Commit

Permalink
crypto: nx - respect sg limit bounds when building sg lists for SHA
Browse files Browse the repository at this point in the history
Commit 0008511 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: 0008511 ("crypto: nx - Fix SHA concurrence issue and sg
		      limit bounds")
Signed-off-by: Jan Stancek <jstancek@redhat.com>
Cc: stable@vger.kernel.org
Cc: Leonidas Da Silva Barbosa <leosilva@linux.vnet.ibm.com>
Cc: Marcelo Henrique Cerri <mhcerri@linux.vnet.ibm.com>
Cc: Fionnuala Gunter <fin@linux.vnet.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
Jan Stancek authored and Herbert Xu committed Aug 11, 2015
1 parent 443c0d7 commit d3392f4
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 23 deletions.
27 changes: 16 additions & 11 deletions drivers/crypto/nx/nx-sha256.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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);
Expand All @@ -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;

/*
Expand Down
28 changes: 16 additions & 12 deletions drivers/crypto/nx/nx-sha512.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -114,27 +112,33 @@ 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);

if (data_len != buf_len) {
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);
Expand All @@ -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;

/*
Expand Down

0 comments on commit d3392f4

Please sign in to comment.