Commit f262f0f5 authored by Herbert Xu's avatar Herbert Xu

crypto: s390 - Fix aes-cbc IV corruption

The cbc-aes-s390 algorithm incorrectly places the IV in the tfm
data structure.  As the tfm is shared between multiple threads,
this introduces a possibility of data corruption.

This patch fixes this by moving the parameter block containing
the IV and key onto the stack (the block is 48 bytes long).

The same bug exists elsewhere in the s390 crypto system and they
will be fixed in subsequent patches.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 8ed49c76
...@@ -35,7 +35,6 @@ static u8 *ctrblk; ...@@ -35,7 +35,6 @@ static u8 *ctrblk;
static char keylen_flag; static char keylen_flag;
struct s390_aes_ctx { struct s390_aes_ctx {
u8 iv[AES_BLOCK_SIZE];
u8 key[AES_MAX_KEY_SIZE]; u8 key[AES_MAX_KEY_SIZE];
long enc; long enc;
long dec; long dec;
...@@ -441,30 +440,36 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, ...@@ -441,30 +440,36 @@ static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
return aes_set_key(tfm, in_key, key_len); return aes_set_key(tfm, in_key, key_len);
} }
static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param, static int cbc_aes_crypt(struct blkcipher_desc *desc, long func,
struct blkcipher_walk *walk) struct blkcipher_walk *walk)
{ {
struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
int ret = blkcipher_walk_virt(desc, walk); int ret = blkcipher_walk_virt(desc, walk);
unsigned int nbytes = walk->nbytes; unsigned int nbytes = walk->nbytes;
struct {
u8 iv[AES_BLOCK_SIZE];
u8 key[AES_MAX_KEY_SIZE];
} param;
if (!nbytes) if (!nbytes)
goto out; goto out;
memcpy(param, walk->iv, AES_BLOCK_SIZE); memcpy(param.iv, walk->iv, AES_BLOCK_SIZE);
memcpy(param.key, sctx->key, sctx->key_len);
do { do {
/* only use complete blocks */ /* only use complete blocks */
unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
u8 *out = walk->dst.virt.addr; u8 *out = walk->dst.virt.addr;
u8 *in = walk->src.virt.addr; u8 *in = walk->src.virt.addr;
ret = crypt_s390_kmc(func, param, out, in, n); ret = crypt_s390_kmc(func, &param, out, in, n);
if (ret < 0 || ret != n) if (ret < 0 || ret != n)
return -EIO; return -EIO;
nbytes &= AES_BLOCK_SIZE - 1; nbytes &= AES_BLOCK_SIZE - 1;
ret = blkcipher_walk_done(desc, walk, nbytes); ret = blkcipher_walk_done(desc, walk, nbytes);
} while ((nbytes = walk->nbytes)); } while ((nbytes = walk->nbytes));
memcpy(walk->iv, param, AES_BLOCK_SIZE); memcpy(walk->iv, param.iv, AES_BLOCK_SIZE);
out: out:
return ret; return ret;
...@@ -481,7 +486,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc, ...@@ -481,7 +486,7 @@ static int cbc_aes_encrypt(struct blkcipher_desc *desc,
return fallback_blk_enc(desc, dst, src, nbytes); return fallback_blk_enc(desc, dst, src, nbytes);
blkcipher_walk_init(&walk, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes);
return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk); return cbc_aes_crypt(desc, sctx->enc, &walk);
} }
static int cbc_aes_decrypt(struct blkcipher_desc *desc, static int cbc_aes_decrypt(struct blkcipher_desc *desc,
...@@ -495,7 +500,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc, ...@@ -495,7 +500,7 @@ static int cbc_aes_decrypt(struct blkcipher_desc *desc,
return fallback_blk_dec(desc, dst, src, nbytes); return fallback_blk_dec(desc, dst, src, nbytes);
blkcipher_walk_init(&walk, dst, src, nbytes); blkcipher_walk_init(&walk, dst, src, nbytes);
return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk); return cbc_aes_crypt(desc, sctx->dec, &walk);
} }
static struct crypto_alg cbc_aes_alg = { static struct crypto_alg cbc_aes_alg = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment