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

Commit b698a9f4 authored by Gary R Hook's avatar Gary R Hook Committed by Herbert Xu
Browse files

crypto: ccp - Validate buffer lengths for copy operations



The CCP driver copies data between scatter/gather lists and DMA buffers.
The length of the requested copy operation must be checked against
the available destination buffer length.

Reported-by: default avatarMaciej S. Szmigiero <mail@maciej.szmigiero.name>
Signed-off-by: default avatarGary R Hook <gary.hook@amd.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 3d053d53
Loading
Loading
Loading
Loading
+78 −30
Original line number Original line Diff line number Diff line
@@ -178,14 +178,18 @@ static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa,
	return 0;
	return 0;
}
}


static void ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
static int ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
			   struct scatterlist *sg, unsigned int sg_offset,
			   struct scatterlist *sg, unsigned int sg_offset,
			   unsigned int len)
			   unsigned int len)
{
{
	WARN_ON(!wa->address);
	WARN_ON(!wa->address);


	if (len > (wa->length - wa_offset))
		return -EINVAL;

	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
	scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len,
				 0);
				 0);
	return 0;
}
}


static void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
static void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset,
@@ -205,8 +209,11 @@ static int ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa,
				   unsigned int len)
				   unsigned int len)
{
{
	u8 *p, *q;
	u8 *p, *q;
	int	rc;


	ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
	rc = ccp_set_dm_area(wa, wa_offset, sg, sg_offset, len);
	if (rc)
		return rc;


	p = wa->address + wa_offset;
	p = wa->address + wa_offset;
	q = p + len - 1;
	q = p + len - 1;
@@ -509,7 +516,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
		return ret;
		return ret;


	dm_offset = CCP_SB_BYTES - aes->key_len;
	dm_offset = CCP_SB_BYTES - aes->key_len;
	ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
	if (ret)
		goto e_key;
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
			     CCP_PASSTHRU_BYTESWAP_256BIT);
			     CCP_PASSTHRU_BYTESWAP_256BIT);
	if (ret) {
	if (ret) {
@@ -528,7 +537,9 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
		goto e_key;
		goto e_key;


	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
	dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
	ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
	if (ret)
		goto e_ctx;
	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
			     CCP_PASSTHRU_BYTESWAP_256BIT);
			     CCP_PASSTHRU_BYTESWAP_256BIT);
	if (ret) {
	if (ret) {
@@ -556,8 +567,10 @@ static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q,
				goto e_src;
				goto e_src;
			}
			}


			ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
			ret = ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0,
					      aes->cmac_key_len);
					      aes->cmac_key_len);
			if (ret)
				goto e_src;
			ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
			ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
					     CCP_PASSTHRU_BYTESWAP_256BIT);
					     CCP_PASSTHRU_BYTESWAP_256BIT);
			if (ret) {
			if (ret) {
@@ -666,7 +679,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
		return ret;
		return ret;


	dm_offset = CCP_SB_BYTES - aes->key_len;
	dm_offset = CCP_SB_BYTES - aes->key_len;
	ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
	if (ret)
		goto e_key;
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
			     CCP_PASSTHRU_BYTESWAP_256BIT);
			     CCP_PASSTHRU_BYTESWAP_256BIT);
	if (ret) {
	if (ret) {
@@ -685,7 +700,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
		goto e_key;
		goto e_key;


	dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len;
	dm_offset = CCP_AES_CTX_SB_COUNT * CCP_SB_BYTES - aes->iv_len;
	ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
	if (ret)
		goto e_ctx;


	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
			     CCP_PASSTHRU_BYTESWAP_256BIT);
			     CCP_PASSTHRU_BYTESWAP_256BIT);
@@ -777,7 +794,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
		goto e_dst;
		goto e_dst;
	}
	}


	ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
	ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
	if (ret)
		goto e_dst;


	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
			     CCP_PASSTHRU_BYTESWAP_256BIT);
			     CCP_PASSTHRU_BYTESWAP_256BIT);
@@ -820,7 +839,9 @@ static int ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q,
					   DMA_BIDIRECTIONAL);
					   DMA_BIDIRECTIONAL);
		if (ret)
		if (ret)
			goto e_tag;
			goto e_tag;
		ccp_set_dm_area(&tag, 0, p_tag, 0, AES_BLOCK_SIZE);
		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, AES_BLOCK_SIZE);
		if (ret)
			goto e_tag;


		ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE);
		ret = memcmp(tag.address, final_wa.address, AES_BLOCK_SIZE);
		ccp_dm_free(&tag);
		ccp_dm_free(&tag);
@@ -914,7 +935,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
		return ret;
		return ret;


	dm_offset = CCP_SB_BYTES - aes->key_len;
	dm_offset = CCP_SB_BYTES - aes->key_len;
	ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
	ret = ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len);
	if (ret)
		goto e_key;
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
			     CCP_PASSTHRU_BYTESWAP_256BIT);
			     CCP_PASSTHRU_BYTESWAP_256BIT);
	if (ret) {
	if (ret) {
@@ -935,7 +958,9 @@ static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
	if (aes->mode != CCP_AES_MODE_ECB) {
	if (aes->mode != CCP_AES_MODE_ECB) {
		/* Load the AES context - convert to LE */
		/* Load the AES context - convert to LE */
		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
		dm_offset = CCP_SB_BYTES - AES_BLOCK_SIZE;
		ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
		ret = ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len);
		if (ret)
			goto e_ctx;
		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
		ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
				     CCP_PASSTHRU_BYTESWAP_256BIT);
				     CCP_PASSTHRU_BYTESWAP_256BIT);
		if (ret) {
		if (ret) {
@@ -1113,8 +1138,12 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
		 * big endian to little endian.
		 * big endian to little endian.
		 */
		 */
		dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
		dm_offset = CCP_SB_BYTES - AES_KEYSIZE_128;
		ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
		ret = ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len);
		ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
		if (ret)
			goto e_key;
		ret = ccp_set_dm_area(&key, 0, xts->key, xts->key_len, xts->key_len);
		if (ret)
			goto e_key;
	} else {
	} else {
		/* Version 5 CCPs use a 512-bit space for the key: each portion
		/* Version 5 CCPs use a 512-bit space for the key: each portion
		 * occupies 256 bits, or one entire slot, and is zero-padded.
		 * occupies 256 bits, or one entire slot, and is zero-padded.
@@ -1123,9 +1152,13 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,


		dm_offset = CCP_SB_BYTES;
		dm_offset = CCP_SB_BYTES;
		pad = dm_offset - xts->key_len;
		pad = dm_offset - xts->key_len;
		ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
		ret = ccp_set_dm_area(&key, pad, xts->key, 0, xts->key_len);
		ccp_set_dm_area(&key, dm_offset + pad, xts->key, xts->key_len,
		if (ret)
				xts->key_len);
			goto e_key;
		ret = ccp_set_dm_area(&key, dm_offset + pad, xts->key,
				      xts->key_len, xts->key_len);
		if (ret)
			goto e_key;
	}
	}
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
			     CCP_PASSTHRU_BYTESWAP_256BIT);
			     CCP_PASSTHRU_BYTESWAP_256BIT);
@@ -1144,7 +1177,9 @@ static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q,
	if (ret)
	if (ret)
		goto e_key;
		goto e_key;


	ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
	ret = ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len);
	if (ret)
		goto e_ctx;
	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
			     CCP_PASSTHRU_BYTESWAP_NOOP);
			     CCP_PASSTHRU_BYTESWAP_NOOP);
	if (ret) {
	if (ret) {
@@ -1287,12 +1322,18 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
	dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */
	dm_offset = CCP_SB_BYTES - des3->key_len; /* Basic offset */


	len_singlekey = des3->key_len / 3;
	len_singlekey = des3->key_len / 3;
	ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
	ret = ccp_set_dm_area(&key, dm_offset + 2 * len_singlekey,
			      des3->key, 0, len_singlekey);
			      des3->key, 0, len_singlekey);
	ccp_set_dm_area(&key, dm_offset + len_singlekey,
	if (ret)
		goto e_key;
	ret = ccp_set_dm_area(&key, dm_offset + len_singlekey,
			      des3->key, len_singlekey, len_singlekey);
			      des3->key, len_singlekey, len_singlekey);
	ccp_set_dm_area(&key, dm_offset,
	if (ret)
		goto e_key;
	ret = ccp_set_dm_area(&key, dm_offset,
			      des3->key, 2 * len_singlekey, len_singlekey);
			      des3->key, 2 * len_singlekey, len_singlekey);
	if (ret)
		goto e_key;


	/* Copy the key to the SB */
	/* Copy the key to the SB */
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
	ret = ccp_copy_to_sb(cmd_q, &key, op.jobid, op.sb_key,
@@ -1320,7 +1361,10 @@ static int ccp_run_des3_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)


		/* Load the context into the LSB */
		/* Load the context into the LSB */
		dm_offset = CCP_SB_BYTES - des3->iv_len;
		dm_offset = CCP_SB_BYTES - des3->iv_len;
		ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0, des3->iv_len);
		ret = ccp_set_dm_area(&ctx, dm_offset, des3->iv, 0,
				      des3->iv_len);
		if (ret)
			goto e_ctx;


		if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
		if (cmd_q->ccp->vdata->version == CCP_VERSION(3, 0))
			load_mode = CCP_PASSTHRU_BYTESWAP_NOOP;
			load_mode = CCP_PASSTHRU_BYTESWAP_NOOP;
@@ -1604,8 +1648,10 @@ static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
		}
		}
	} else {
	} else {
		/* Restore the context */
		/* Restore the context */
		ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
		ret = ccp_set_dm_area(&ctx, 0, sha->ctx, 0,
				      sb_count * CCP_SB_BYTES);
				      sb_count * CCP_SB_BYTES);
		if (ret)
			goto e_ctx;
	}
	}


	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
	ret = ccp_copy_to_sb(cmd_q, &ctx, op.jobid, op.sb_ctx,
@@ -1927,7 +1973,9 @@ static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q,
		if (ret)
		if (ret)
			return ret;
			return ret;


		ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
		ret = ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len);
		if (ret)
			goto e_mask;
		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
		ret = ccp_copy_to_sb(cmd_q, &mask, op.jobid, op.sb_key,
				     CCP_PASSTHRU_BYTESWAP_NOOP);
				     CCP_PASSTHRU_BYTESWAP_NOOP);
		if (ret) {
		if (ret) {