Vulnerability: A memory leak flaw was found in the Linux kernel in the ccp_run_aes_gcm_cmd() function in drivers/crypto/ccp/ccp-ops.c, which allows attackers to cause a denial of service (memory consumption). This vulnerability is similar with the older CVE-2019-18808.
Vulnerability ID: CVE-2021-3744
CWE: CWE-401
Severity score: 2.9
Project: https://github.com/torvalds/linux
Published: 2022-03-04
File: drivers/crypto/ccp/ccp-ops.c
Commit message: crypto: ccp - fix resource leaks in ccp_run_aes_gcm_cmd()

There are three bugs in this code:

1) If we ccp_init_data() fails for &src then we need to free aad.
   Use goto e_aad instead of goto e_ctx.
2) The label to free the &final_wa was named incorrectly as "e_tag" but
   it should have been "e_final_wa".  One error path leaked &final_wa.
3) The &tag was leaked on one error path.  In that case, I added a free
   before the goto because the resource was local to that block.

Fixes: 36cf515b9bbe ("crypto: ccp - Enable support for AES GCM on v5 CCPs")
Reported-by: "minihanshen(沈明航)" <minihanshen@tencent.com>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: John Allen <john.allen@amd.com>
Tested-by: John Allen <john.allen@amd.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Commit author: Dan Carpenter

Vulnerable version (before fix):
 ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) 				    in_place ? DMA_BIDIRECTIONAL 					     : DMA_TO_DEVICE); 		if (ret) 			goto e_ctx;  		if (in_place) { 			dst = src; ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) 	op.u.aes.size = 0; 	ret = cmd_q->ccp->vdata->perform->aes(&op); 	if (ret) 		goto e_dst;  	if (aes->action == CCP_AES_ACTION_ENCRYPT) { 		/* Put the ciphered tag after the ciphertext. */ ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) 		ret = ccp_init_dm_workarea(&tag, cmd_q, authsize, 					   DMA_BIDIRECTIONAL); 		if (ret) 			goto e_tag; 		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, authsize); 		if (ret) 			goto e_tag;  		ret = crypto_memneq(tag.address, final_wa.address, 				    authsize) ? -EBADMSG : 0; 		ccp_dm_free(&tag); 	}  e_tag: 	ccp_dm_free(&final_wa);  e_dst:

Fixed version (after fix):
 ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) 				    in_place ? DMA_BIDIRECTIONAL 					     : DMA_TO_DEVICE); 		if (ret) 			goto e_aad;  		if (in_place) { 			dst = src; ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) 	op.u.aes.size = 0; 	ret = cmd_q->ccp->vdata->perform->aes(&op); 	if (ret) 		goto e_final_wa;  	if (aes->action == CCP_AES_ACTION_ENCRYPT) { 		/* Put the ciphered tag after the ciphertext. */ ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) 		ret = ccp_init_dm_workarea(&tag, cmd_q, authsize, 					   DMA_BIDIRECTIONAL); 		if (ret) 			goto e_final_wa; 		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, authsize); 		if (ret) { 			ccp_dm_free(&tag); 			goto e_final_wa; 		}  		ret = crypto_memneq(tag.address, final_wa.address, 				    authsize) ? -EBADMSG : 0; 		ccp_dm_free(&tag); 	}  e_final_wa: 	ccp_dm_free(&final_wa);  e_dst:

Patch:
patch: @@ -778,7 +778,7 @@ ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
 				    in_place ? DMA_BIDIRECTIONAL
 					     : DMA_TO_DEVICE);
 		if (ret)
-			goto e_ctx;
+			goto e_aad;
 
 		if (in_place) {
 			dst = src;
@@ -863,7 +863,7 @@ ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
 	op.u.aes.size = 0;
 	ret = cmd_q->ccp->vdata->perform->aes(&op);
 	if (ret)
-		goto e_dst;
+		goto e_final_wa;
 
 	if (aes->action == CCP_AES_ACTION_ENCRYPT) {
 		/* Put the ciphered tag after the ciphertext. */
@@ -873,17 +873,19 @@ ccp_run_aes_gcm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd)
 		ret = ccp_init_dm_workarea(&tag, cmd_q, authsize,
 					   DMA_BIDIRECTIONAL);
 		if (ret)
-			goto e_tag;
+			goto e_final_wa;
 		ret = ccp_set_dm_area(&tag, 0, p_tag, 0, authsize);
-		if (ret)
-			goto e_tag;
+		if (ret) {
+			ccp_dm_free(&tag);
+			goto e_final_wa;
+		}
 
 		ret = crypto_memneq(tag.address, final_wa.address,
 				    authsize) ? -EBADMSG : 0;
 		ccp_dm_free(&tag);
 	}
 
-e_tag:
+e_final_wa:
 	ccp_dm_free(&final_wa);
 
 e_dst:
path: drivers/crypto/ccp/ccp-ops.c