aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/crypto
diff options
context:
space:
mode:
authorHarald Freudenberger <freude@linux.vnet.ibm.com>2014-01-22 07:01:33 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2014-01-30 08:45:14 -0500
commitee97dc7db4cbda33e4241c2d85b42d1835bc8a35 (patch)
tree14232912769ade751a61a61984bf1aaf2dc2fb24 /arch/s390/crypto
parentadc3fcf1552b6e406d172fd9690bbd1395053d13 (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.c69
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
27static u8 *ctrblk; 27static u8 *ctrblk;
28static DEFINE_SPINLOCK(ctrblk_lock);
28 29
29struct s390_des_ctx { 30struct 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
372static 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
371static int ctr_desall_crypt(struct blkcipher_desc *desc, long func, 385static 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