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 | |
| 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>
| -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 | ||
