diff options
author | Harald Freudenberger <freude@linux.vnet.ibm.com> | 2014-01-22 07:01:33 -0500 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2014-01-30 08:45:14 -0500 |
commit | ee97dc7db4cbda33e4241c2d85b42d1835bc8a35 (patch) | |
tree | 14232912769ade751a61a61984bf1aaf2dc2fb24 /arch/s390/crypto | |
parent | adc3fcf1552b6e406d172fd9690bbd1395053d13 (diff) |
crypto: s390 - fix des and des3_ede ctr concurrency issue
In s390 des and 3des ctr mode there is one preallocated page
used to speed up the en/decryption. This page is not protected
against concurrent usage and thus there is a potential of data
corruption with multiple threads.
The fix introduces locking/unlocking the ctr page and a slower
fallback solution at concurrency situations.
Cc: stable@vger.kernel.org
Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'arch/s390/crypto')
-rw-r--r-- | arch/s390/crypto/des_s390.c | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index 82a0a2ad2494..0a5aac8a9412 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) | 25 | #define DES3_KEY_SIZE (3 * DES_KEY_SIZE) |
26 | 26 | ||
27 | static u8 *ctrblk; | 27 | static u8 *ctrblk; |
28 | static DEFINE_SPINLOCK(ctrblk_lock); | ||
28 | 29 | ||
29 | struct s390_des_ctx { | 30 | struct s390_des_ctx { |
30 | u8 iv[DES_BLOCK_SIZE]; | 31 | u8 iv[DES_BLOCK_SIZE]; |
@@ -368,54 +369,80 @@ static struct crypto_alg cbc_des3_alg = { | |||
368 | } | 369 | } |
369 | }; | 370 | }; |
370 | 371 | ||
372 | static unsigned int __ctrblk_init(u8 *ctrptr, unsigned int nbytes) | ||
373 | { | ||
374 | unsigned int i, n; | ||
375 | |||
376 | /* align to block size, max. PAGE_SIZE */ | ||
377 | n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : nbytes & ~(DES_BLOCK_SIZE - 1); | ||
378 | for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { | ||
379 | memcpy(ctrptr + i, ctrptr + i - DES_BLOCK_SIZE, DES_BLOCK_SIZE); | ||
380 | crypto_inc(ctrptr + i, DES_BLOCK_SIZE); | ||
381 | } | ||
382 | return n; | ||
383 | } | ||
384 | |||
371 | static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, | 385 | static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, |
372 | struct s390_des_ctx *ctx, struct blkcipher_walk *walk) | 386 | struct s390_des_ctx *ctx, |
387 | struct blkcipher_walk *walk) | ||
373 | { | 388 | { |
374 | int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); | 389 | int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE); |
375 | unsigned int i, n, nbytes; | 390 | unsigned int n, nbytes; |
376 | u8 buf[DES_BLOCK_SIZE]; | 391 | u8 buf[DES_BLOCK_SIZE], ctrbuf[DES_BLOCK_SIZE]; |
377 | u8 *out, *in; | 392 | u8 *out, *in, *ctrptr = ctrbuf; |
393 | |||
394 | if (!walk->nbytes) | ||
395 | return ret; | ||
378 | 396 | ||
379 | memcpy(ctrblk, walk->iv, DES_BLOCK_SIZE); | 397 | if (spin_trylock(&ctrblk_lock)) |
398 | ctrptr = ctrblk; | ||
399 | |||
400 | memcpy(ctrptr, walk->iv, DES_BLOCK_SIZE); | ||
380 | while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { | 401 | while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) { |
381 | out = walk->dst.virt.addr; | 402 | out = walk->dst.virt.addr; |
382 | in = walk->src.virt.addr; | 403 | in = walk->src.virt.addr; |
383 | while (nbytes >= DES_BLOCK_SIZE) { | 404 | while (nbytes >= DES_BLOCK_SIZE) { |
384 | /* align to block size, max. PAGE_SIZE */ | 405 | if (ctrptr == ctrblk) |
385 | n = (nbytes > PAGE_SIZE) ? PAGE_SIZE : | 406 | n = __ctrblk_init(ctrptr, nbytes); |
386 | nbytes & ~(DES_BLOCK_SIZE - 1); | 407 | else |
387 | for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) { | 408 | n = DES_BLOCK_SIZE; |
388 | memcpy(ctrblk + i, ctrblk + i - DES_BLOCK_SIZE, | 409 | ret = crypt_s390_kmctr(func, ctx->key, out, in, |
389 | DES_BLOCK_SIZE); | 410 | n, ctrptr); |
390 | crypto_inc(ctrblk + i, DES_BLOCK_SIZE); | 411 | if (ret < 0 || ret != n) { |
391 | } | 412 | if (ctrptr == ctrblk) |
392 | ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrblk); | 413 | spin_unlock(&ctrblk_lock); |
393 | if (ret < 0 || ret != n) | ||
394 | return -EIO; | 414 | return -EIO; |
415 | } | ||
395 | if (n > DES_BLOCK_SIZE) | 416 | if (n > DES_BLOCK_SIZE) |
396 | memcpy(ctrblk, ctrblk + n - DES_BLOCK_SIZE, | 417 | memcpy(ctrptr, ctrptr + n - DES_BLOCK_SIZE, |
397 | DES_BLOCK_SIZE); | 418 | DES_BLOCK_SIZE); |
398 | crypto_inc(ctrblk, DES_BLOCK_SIZE); | 419 | crypto_inc(ctrptr, DES_BLOCK_SIZE); |
399 | out += n; | 420 | out += n; |
400 | in += n; | 421 | in += n; |
401 | nbytes -= n; | 422 | nbytes -= n; |
402 | } | 423 | } |
403 | ret = blkcipher_walk_done(desc, walk, nbytes); | 424 | ret = blkcipher_walk_done(desc, walk, nbytes); |
404 | } | 425 | } |
405 | 426 | if (ctrptr == ctrblk) { | |
427 | if (nbytes) | ||
428 | memcpy(ctrbuf, ctrptr, DES_BLOCK_SIZE); | ||
429 | else | ||
430 | memcpy(walk->iv, ctrptr, DES_BLOCK_SIZE); | ||
431 | spin_unlock(&ctrblk_lock); | ||
432 | } | ||
406 | /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ | 433 | /* final block may be < DES_BLOCK_SIZE, copy only nbytes */ |
407 | if (nbytes) { | 434 | if (nbytes) { |
408 | out = walk->dst.virt.addr; | 435 | out = walk->dst.virt.addr; |
409 | in = walk->src.virt.addr; | 436 | in = walk->src.virt.addr; |
410 | ret = crypt_s390_kmctr(func, ctx->key, buf, in, | 437 | ret = crypt_s390_kmctr(func, ctx->key, buf, in, |
411 | DES_BLOCK_SIZE, ctrblk); | 438 | DES_BLOCK_SIZE, ctrbuf); |
412 | if (ret < 0 || ret != DES_BLOCK_SIZE) | 439 | if (ret < 0 || ret != DES_BLOCK_SIZE) |
413 | return -EIO; | 440 | return -EIO; |
414 | memcpy(out, buf, nbytes); | 441 | memcpy(out, buf, nbytes); |
415 | crypto_inc(ctrblk, DES_BLOCK_SIZE); | 442 | crypto_inc(ctrbuf, DES_BLOCK_SIZE); |
416 | ret = blkcipher_walk_done(desc, walk, 0); | 443 | ret = blkcipher_walk_done(desc, walk, 0); |
444 | memcpy(walk->iv, ctrbuf, DES_BLOCK_SIZE); | ||
417 | } | 445 | } |
418 | memcpy(walk->iv, ctrblk, DES_BLOCK_SIZE); | ||
419 | return ret; | 446 | return ret; |
420 | } | 447 | } |
421 | 448 | ||