Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit adc3fcf1 authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Herbert Xu
Browse files

crypto: s390 - fix des and des3_ede cbc concurrency issue



In s390 des and des3_ede cbc mode the iv value is not protected
against concurrency access and modifications from another running
en/decrypt operation which is using the very same tfm struct
instance. This fix copies the iv to the local stack before
the crypto operation and stores the value back when done.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarHarald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 0519e9ad
Loading
Loading
Loading
Loading
+14 −12
Original line number Original line Diff line number Diff line
@@ -105,29 +105,35 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func,
}
}


static int cbc_desall_crypt(struct blkcipher_desc *desc, long func,
static int cbc_desall_crypt(struct blkcipher_desc *desc, long func,
			    u8 *iv, struct blkcipher_walk *walk)
			    struct blkcipher_walk *walk)
{
{
	struct s390_des_ctx *ctx = 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[DES_BLOCK_SIZE];
		u8 key[DES3_KEY_SIZE];
	} param;


	if (!nbytes)
	if (!nbytes)
		goto out;
		goto out;


	memcpy(iv, walk->iv, DES_BLOCK_SIZE);
	memcpy(param.iv, walk->iv, DES_BLOCK_SIZE);
	memcpy(param.key, ctx->key, DES3_KEY_SIZE);
	do {
	do {
		/* only use complete blocks */
		/* only use complete blocks */
		unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
		unsigned int n = nbytes & ~(DES_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, iv, 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 &= DES_BLOCK_SIZE - 1;
		nbytes &= DES_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, iv, DES_BLOCK_SIZE);
	memcpy(walk->iv, param.iv, DES_BLOCK_SIZE);


out:
out:
	return ret;
	return ret;
@@ -179,22 +185,20 @@ static int cbc_des_encrypt(struct blkcipher_desc *desc,
			   struct scatterlist *dst, struct scatterlist *src,
			   struct scatterlist *dst, struct scatterlist *src,
			   unsigned int nbytes)
			   unsigned int nbytes)
{
{
	struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
	struct blkcipher_walk walk;
	struct blkcipher_walk walk;


	blkcipher_walk_init(&walk, dst, src, nbytes);
	blkcipher_walk_init(&walk, dst, src, nbytes);
	return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, ctx->iv, &walk);
	return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, &walk);
}
}


static int cbc_des_decrypt(struct blkcipher_desc *desc,
static int cbc_des_decrypt(struct blkcipher_desc *desc,
			   struct scatterlist *dst, struct scatterlist *src,
			   struct scatterlist *dst, struct scatterlist *src,
			   unsigned int nbytes)
			   unsigned int nbytes)
{
{
	struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
	struct blkcipher_walk walk;
	struct blkcipher_walk walk;


	blkcipher_walk_init(&walk, dst, src, nbytes);
	blkcipher_walk_init(&walk, dst, src, nbytes);
	return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, ctx->iv, &walk);
	return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, &walk);
}
}


static struct crypto_alg cbc_des_alg = {
static struct crypto_alg cbc_des_alg = {
@@ -327,22 +331,20 @@ static int cbc_des3_encrypt(struct blkcipher_desc *desc,
			    struct scatterlist *dst, struct scatterlist *src,
			    struct scatterlist *dst, struct scatterlist *src,
			    unsigned int nbytes)
			    unsigned int nbytes)
{
{
	struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
	struct blkcipher_walk walk;
	struct blkcipher_walk walk;


	blkcipher_walk_init(&walk, dst, src, nbytes);
	blkcipher_walk_init(&walk, dst, src, nbytes);
	return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, ctx->iv, &walk);
	return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, &walk);
}
}


static int cbc_des3_decrypt(struct blkcipher_desc *desc,
static int cbc_des3_decrypt(struct blkcipher_desc *desc,
			    struct scatterlist *dst, struct scatterlist *src,
			    struct scatterlist *dst, struct scatterlist *src,
			    unsigned int nbytes)
			    unsigned int nbytes)
{
{
	struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
	struct blkcipher_walk walk;
	struct blkcipher_walk walk;


	blkcipher_walk_init(&walk, dst, src, nbytes);
	blkcipher_walk_init(&walk, dst, src, nbytes);
	return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, ctx->iv, &walk);
	return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, &walk);
}
}


static struct crypto_alg cbc_des3_alg = {
static struct crypto_alg cbc_des3_alg = {