diff options
author | Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com> | 2014-10-28 13:44:30 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2014-11-06 10:15:00 -0500 |
commit | 9247f0b05572da01721b105558a25d3a413ca0a1 (patch) | |
tree | 1562bd20096159db88b5946425ec90d3192345b2 /drivers/crypto | |
parent | ac0f0a8a87642bc0dd589a6ead58d273a02d98e4 (diff) |
crypto: nx - Moving NX-AES-CCM to be processed logic and sg_list bounds
The previous limits were estimated locally in a single step
basead on bound values, however it was not correct since
when given certain scatterlist the function nx_build_sg_lists
was consuming more sg entries than allocated causing a
memory corruption and crashes.
This patch removes the old logic and replaces it into nx_sg_build_lists in
order to build a correct nx_sg list using the correct sg_max limit and
bounds.
Signed-off-by: Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/crypto')
-rw-r--r-- | drivers/crypto/nx/nx-aes-ccm.c | 61 |
1 files changed, 27 insertions, 34 deletions
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c index 5ecd4c2414aa..67f80813a06f 100644 --- a/drivers/crypto/nx/nx-aes-ccm.c +++ b/drivers/crypto/nx/nx-aes-ccm.c | |||
@@ -181,6 +181,7 @@ static int generate_pat(u8 *iv, | |||
181 | unsigned int iauth_len = 0; | 181 | unsigned int iauth_len = 0; |
182 | u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL; | 182 | u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL; |
183 | int rc; | 183 | int rc; |
184 | unsigned int max_sg_len; | ||
184 | 185 | ||
185 | /* zero the ctr value */ | 186 | /* zero the ctr value */ |
186 | memset(iv + 15 - iv[0], 0, iv[0] + 1); | 187 | memset(iv + 15 - iv[0], 0, iv[0] + 1); |
@@ -248,10 +249,19 @@ static int generate_pat(u8 *iv, | |||
248 | if (!req->assoclen) { | 249 | if (!req->assoclen) { |
249 | return rc; | 250 | return rc; |
250 | } else if (req->assoclen <= 14) { | 251 | } else if (req->assoclen <= 14) { |
251 | nx_insg = nx_build_sg_list(nx_insg, b1, 16, nx_ctx->ap->sglen); | 252 | unsigned int len = 16; |
252 | nx_outsg = nx_build_sg_list(nx_outsg, tmp, 16, | 253 | |
254 | nx_insg = nx_build_sg_list(nx_insg, b1, &len, nx_ctx->ap->sglen); | ||
255 | |||
256 | if (len != 16) | ||
257 | return -EINVAL; | ||
258 | |||
259 | nx_outsg = nx_build_sg_list(nx_outsg, tmp, &len, | ||
253 | nx_ctx->ap->sglen); | 260 | nx_ctx->ap->sglen); |
254 | 261 | ||
262 | if (len != 16) | ||
263 | return -EINVAL; | ||
264 | |||
255 | /* inlen should be negative, indicating to phyp that its a | 265 | /* inlen should be negative, indicating to phyp that its a |
256 | * pointer to an sg list */ | 266 | * pointer to an sg list */ |
257 | nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * | 267 | nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * |
@@ -273,21 +283,24 @@ static int generate_pat(u8 *iv, | |||
273 | atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes)); | 283 | atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes)); |
274 | 284 | ||
275 | } else { | 285 | } else { |
276 | u32 max_sg_len; | ||
277 | unsigned int processed = 0, to_process; | 286 | unsigned int processed = 0, to_process; |
278 | 287 | ||
279 | /* page_limit: number of sg entries that fit on one page */ | ||
280 | max_sg_len = min_t(u32, | ||
281 | nx_driver.of.max_sg_len/sizeof(struct nx_sg), | ||
282 | nx_ctx->ap->sglen); | ||
283 | |||
284 | processed += iauth_len; | 288 | processed += iauth_len; |
285 | 289 | ||
290 | /* page_limit: number of sg entries that fit on one page */ | ||
291 | max_sg_len = min_t(u64, nx_ctx->ap->sglen, | ||
292 | nx_driver.of.max_sg_len/sizeof(struct nx_sg)); | ||
293 | max_sg_len = min_t(u64, max_sg_len, | ||
294 | nx_ctx->ap->databytelen/NX_PAGE_SIZE); | ||
295 | |||
286 | do { | 296 | do { |
287 | to_process = min_t(u32, req->assoclen - processed, | 297 | to_process = min_t(u32, req->assoclen - processed, |
288 | nx_ctx->ap->databytelen); | 298 | nx_ctx->ap->databytelen); |
289 | to_process = min_t(u64, to_process, | 299 | |
290 | NX_PAGE_SIZE * (max_sg_len - 1)); | 300 | nx_insg = nx_walk_and_build(nx_ctx->in_sg, |
301 | nx_ctx->ap->sglen, | ||
302 | req->assoc, processed, | ||
303 | &to_process); | ||
291 | 304 | ||
292 | if ((to_process + processed) < req->assoclen) { | 305 | if ((to_process + processed) < req->assoclen) { |
293 | NX_CPB_FDM(nx_ctx->csbcpb_aead) |= | 306 | NX_CPB_FDM(nx_ctx->csbcpb_aead) |= |
@@ -297,10 +310,6 @@ static int generate_pat(u8 *iv, | |||
297 | ~NX_FDM_INTERMEDIATE; | 310 | ~NX_FDM_INTERMEDIATE; |
298 | } | 311 | } |
299 | 312 | ||
300 | nx_insg = nx_walk_and_build(nx_ctx->in_sg, | ||
301 | nx_ctx->ap->sglen, | ||
302 | req->assoc, processed, | ||
303 | to_process); | ||
304 | 313 | ||
305 | nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) * | 314 | nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) * |
306 | sizeof(struct nx_sg); | 315 | sizeof(struct nx_sg); |
@@ -343,7 +352,6 @@ static int ccm_nx_decrypt(struct aead_request *req, | |||
343 | struct nx_ccm_priv *priv = &nx_ctx->priv.ccm; | 352 | struct nx_ccm_priv *priv = &nx_ctx->priv.ccm; |
344 | unsigned long irq_flags; | 353 | unsigned long irq_flags; |
345 | unsigned int processed = 0, to_process; | 354 | unsigned int processed = 0, to_process; |
346 | u32 max_sg_len; | ||
347 | int rc = -1; | 355 | int rc = -1; |
348 | 356 | ||
349 | spin_lock_irqsave(&nx_ctx->lock, irq_flags); | 357 | spin_lock_irqsave(&nx_ctx->lock, irq_flags); |
@@ -360,19 +368,12 @@ static int ccm_nx_decrypt(struct aead_request *req, | |||
360 | if (rc) | 368 | if (rc) |
361 | goto out; | 369 | goto out; |
362 | 370 | ||
363 | /* page_limit: number of sg entries that fit on one page */ | ||
364 | max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg), | ||
365 | nx_ctx->ap->sglen); | ||
366 | |||
367 | do { | 371 | do { |
368 | 372 | ||
369 | /* to_process: the AES_BLOCK_SIZE data chunk to process in this | 373 | /* to_process: the AES_BLOCK_SIZE data chunk to process in this |
370 | * update. This value is bound by sg list limits. | 374 | * update. This value is bound by sg list limits. |
371 | */ | 375 | */ |
372 | to_process = min_t(u64, nbytes - processed, | 376 | to_process = nbytes - processed; |
373 | nx_ctx->ap->databytelen); | ||
374 | to_process = min_t(u64, to_process, | ||
375 | NX_PAGE_SIZE * (max_sg_len - 1)); | ||
376 | 377 | ||
377 | if ((to_process + processed) < nbytes) | 378 | if ((to_process + processed) < nbytes) |
378 | NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; | 379 | NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; |
@@ -382,7 +383,7 @@ static int ccm_nx_decrypt(struct aead_request *req, | |||
382 | NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT; | 383 | NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT; |
383 | 384 | ||
384 | rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, | 385 | rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, |
385 | to_process, processed, | 386 | &to_process, processed, |
386 | csbcpb->cpb.aes_ccm.iv_or_ctr); | 387 | csbcpb->cpb.aes_ccm.iv_or_ctr); |
387 | if (rc) | 388 | if (rc) |
388 | goto out; | 389 | goto out; |
@@ -427,7 +428,6 @@ static int ccm_nx_encrypt(struct aead_request *req, | |||
427 | unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req)); | 428 | unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req)); |
428 | unsigned long irq_flags; | 429 | unsigned long irq_flags; |
429 | unsigned int processed = 0, to_process; | 430 | unsigned int processed = 0, to_process; |
430 | u32 max_sg_len; | ||
431 | int rc = -1; | 431 | int rc = -1; |
432 | 432 | ||
433 | spin_lock_irqsave(&nx_ctx->lock, irq_flags); | 433 | spin_lock_irqsave(&nx_ctx->lock, irq_flags); |
@@ -437,18 +437,11 @@ static int ccm_nx_encrypt(struct aead_request *req, | |||
437 | if (rc) | 437 | if (rc) |
438 | goto out; | 438 | goto out; |
439 | 439 | ||
440 | /* page_limit: number of sg entries that fit on one page */ | ||
441 | max_sg_len = min_t(u32, nx_driver.of.max_sg_len/sizeof(struct nx_sg), | ||
442 | nx_ctx->ap->sglen); | ||
443 | |||
444 | do { | 440 | do { |
445 | /* to process: the AES_BLOCK_SIZE data chunk to process in this | 441 | /* to process: the AES_BLOCK_SIZE data chunk to process in this |
446 | * update. This value is bound by sg list limits. | 442 | * update. This value is bound by sg list limits. |
447 | */ | 443 | */ |
448 | to_process = min_t(u64, nbytes - processed, | 444 | to_process = nbytes - processed; |
449 | nx_ctx->ap->databytelen); | ||
450 | to_process = min_t(u64, to_process, | ||
451 | NX_PAGE_SIZE * (max_sg_len - 1)); | ||
452 | 445 | ||
453 | if ((to_process + processed) < nbytes) | 446 | if ((to_process + processed) < nbytes) |
454 | NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; | 447 | NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE; |
@@ -458,7 +451,7 @@ static int ccm_nx_encrypt(struct aead_request *req, | |||
458 | NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT; | 451 | NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT; |
459 | 452 | ||
460 | rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, | 453 | rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, |
461 | to_process, processed, | 454 | &to_process, processed, |
462 | csbcpb->cpb.aes_ccm.iv_or_ctr); | 455 | csbcpb->cpb.aes_ccm.iv_or_ctr); |
463 | if (rc) | 456 | if (rc) |
464 | goto out; | 457 | goto out; |