CVE-2023-41325 (published 2023-09-15T20:15Z)

OP-TEE is a Trusted Execution Environment (TEE) designed as companion to a non-secure Linux kernel running on Arm; Cortex-A cores using the TrustZone technology. Starting in version 3.20 and prior to version 3.22, `shdr_verify_signature` can make a double free. `shdr_verify_signature` used to verify a TA binary before it is loaded. To verify a signature of it, allocate a memory for RSA key. RSA key allocate function (`sw_crypto_acipher_alloc_rsa_public_key`) will try to allocate a memory (which is optee’s heap memory). RSA key is consist of exponent and modulus (represent as variable `e`, `n`) and it allocation is not atomic way, so it may succeed in `e` but fail in `n`. In this case sw_crypto_acipher_alloc_rsa_public_key` will free on `e` and return as it is failed but variable ‘e’ is remained as already freed memory address . `shdr_verify_signature` will free again that memory (which is `e`) even it is freed when it failed allocate RSA key. A patch is available in version 3.22. No known workarounds are available.

CVSS v3 base score: 6.7, MEDIUM (CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-415
cwe_name: Double Free
description: The product calls free() twice on the same memory address, potentially leading to modification of unexpected memory locations.
extended_description: When a program calls free() twice with the same argument, the program's memory management data structures become corrupted. This corruption can cause the program to crash or, in some circumstances, cause two later calls to malloc() to return the same pointer. If malloc() returns the same value twice and the program later gives the attacker control over the data that is written into this doubly-allocated memory, the program becomes vulnerable to a buffer overflow attack.
         

Fix information:
repo_url: https://github.com/OP-TEE/optee_os
commit_details: repo_url: https://github.com/OP-TEE/optee_os
author: Jihwan Park
author_date: 2023-07-03 08:51:47+02:00
msg: core: crypto_bignum_free(): add indirection and set pointer to NULL

To prevent human mistake, crypto_bignum_free() sets the location of the
bignum pointer to NULL after freeing it.

Signed-off-by: Jihwan Park <jihwp@amazon.com>
Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Reviewed-by: Jerome Forissier <jerome.forissier@linaro.org>
Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
Reviewed-by: Etienne Carriere <etienne.carriere@foss.st.com>
repository: repo_url: https://github.com/OP-TEE/optee_os
repo_name: OP-TEE/optee_os
description: Trusted side of the TEE
repo_language: C
owner: OP-TEE
file_changes: filename: crypto.c
change_type: ModificationType.MODIFY
diff: @@ -528,9 +528,9 @@ void crypto_bignum_copy(struct bignum *to __unused,
 	bignum_cant_happen();
 }
 
-void crypto_bignum_free(struct bignum *a)
+void crypto_bignum_free(struct bignum **a)
 {
-	if (a)
+	if (a && *a)
 		panic();
 }
 

programming_language: C
filename: caam_dh.c
change_type: ModificationType.MODIFY
diff: @@ -195,10 +195,10 @@ static TEE_Result do_allocate_keypair(struct dh_keypair *key, size_t size_bits)
 err:
 	DH_TRACE("Allocation error");
 
-	crypto_bignum_free(key->g);
-	crypto_bignum_free(key->p);
-	crypto_bignum_free(key->x);
-	crypto_bignum_free(key->y);
+	crypto_bignum_free(&key->g);
+	crypto_bignum_free(&key->p);
+	crypto_bignum_free(&key->x);
+	crypto_bignum_free(&key->y);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }

programming_language: C
filename: caam_dsa.c
change_type: ModificationType.MODIFY
diff: @@ -309,10 +309,10 @@ static TEE_Result do_allocate_keypair(struct dsa_keypair *key, size_t l_bits,
 err:
 	DSA_TRACE("Allocation error");
 
-	crypto_bignum_free(key->g);
-	crypto_bignum_free(key->p);
-	crypto_bignum_free(key->q);
-	crypto_bignum_free(key->x);
+	crypto_bignum_free(&key->g);
+	crypto_bignum_free(&key->p);
+	crypto_bignum_free(&key->q);
+	crypto_bignum_free(&key->x);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
@@ -358,9 +358,9 @@ static TEE_Result do_allocate_publickey(struct dsa_public_key *key,
 err:
 	DSA_TRACE("Allocation error");
 
-	crypto_bignum_free(key->g);
-	crypto_bignum_free(key->p);
-	crypto_bignum_free(key->q);
+	crypto_bignum_free(&key->g);
+	crypto_bignum_free(&key->p);
+	crypto_bignum_free(&key->q);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }

programming_language: C
filename: caam_ecc.c
change_type: ModificationType.MODIFY
diff: @@ -171,8 +171,8 @@ static TEE_Result do_allocate_keypair(struct ecc_keypair *key,
 err:
 	ECC_TRACE("Allocation error");
 
-	crypto_bignum_free(key->d);
-	crypto_bignum_free(key->x);
+	crypto_bignum_free(&key->d);
+	crypto_bignum_free(&key->x);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
@@ -207,7 +207,7 @@ static TEE_Result do_allocate_publickey(struct ecc_public_key *key,
 err:
 	ECC_TRACE("Allocation error");
 
-	crypto_bignum_free(key->x);
+	crypto_bignum_free(&key->x);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
@@ -219,8 +219,8 @@ err:
  */
 static void do_free_publickey(struct ecc_public_key *key)
 {
-	crypto_bignum_free(key->x);
-	crypto_bignum_free(key->y);
+	crypto_bignum_free(&key->x);
+	crypto_bignum_free(&key->y);
 }
 
 /*

programming_language: C
filename: caam_rsa.c
change_type: ModificationType.MODIFY
diff: @@ -86,14 +86,14 @@ static uint8_t caam_era;
  */
 static void do_free_keypair(struct rsa_keypair *key)
 {
-	crypto_bignum_free(key->e);
-	crypto_bignum_free(key->d);
-	crypto_bignum_free(key->n);
-	crypto_bignum_free(key->p);
-	crypto_bignum_free(key->q);
-	crypto_bignum_free(key->qp);
-	crypto_bignum_free(key->dp);
-	crypto_bignum_free(key->dq);
+	crypto_bignum_free(&key->e);
+	crypto_bignum_free(&key->d);
+	crypto_bignum_free(&key->n);
+	crypto_bignum_free(&key->p);
+	crypto_bignum_free(&key->q);
+	crypto_bignum_free(&key->qp);
+	crypto_bignum_free(&key->dp);
+	crypto_bignum_free(&key->dq);
 }
 
 /*
@@ -435,8 +435,8 @@ static TEE_Result do_allocate_publickey(struct rsa_public_key *key,
 err_alloc_publickey:
 	RSA_TRACE("Allocation error");
 
-	crypto_bignum_free(key->e);
-	crypto_bignum_free(key->n);
+	crypto_bignum_free(&key->e);
+	crypto_bignum_free(&key->n);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
@@ -448,8 +448,8 @@ err_alloc_publickey:
  */
 static void do_free_publickey(struct rsa_public_key *key)
 {
-	crypto_bignum_free(key->e);
-	crypto_bignum_free(key->n);
+	crypto_bignum_free(&key->e);
+	crypto_bignum_free(&key->n);
 }
 
 /*

programming_language: C
filename: ecc.c
change_type: ModificationType.MODIFY
diff: @@ -743,9 +743,9 @@ static TEE_Result do_alloc_keypair(struct ecc_keypair *s, uint32_t type,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->d);
-	crypto_bignum_free(s->x);
-	crypto_bignum_free(s->y);
+	crypto_bignum_free(&s->d);
+	crypto_bignum_free(&s->x);
+	crypto_bignum_free(&s->y);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 
@@ -764,8 +764,8 @@ static TEE_Result do_alloc_publickey(struct ecc_public_key *s, uint32_t type,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->x);
-	crypto_bignum_free(s->y);
+	crypto_bignum_free(&s->x);
+	crypto_bignum_free(&s->y);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 
@@ -774,8 +774,8 @@ static void do_free_publickey(struct ecc_public_key *s)
 	if (!s)
 		return;
 
-	crypto_bignum_free(s->x);
-	crypto_bignum_free(s->y);
+	crypto_bignum_free(&s->x);
+	crypto_bignum_free(&s->y);
 }
 
 static struct drvcrypt_ecc driver_ecc = {

programming_language: C
filename: rsa.c
change_type: ModificationType.MODIFY
diff: @@ -537,14 +537,14 @@ static TEE_Result do_alloc_keypair(struct rsa_keypair *s,
 
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->e);
-	crypto_bignum_free(s->d);
-	crypto_bignum_free(s->n);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->q);
-	crypto_bignum_free(s->qp);
-	crypto_bignum_free(s->dp);
-	crypto_bignum_free(s->dq);
+	crypto_bignum_free(&s->e);
+	crypto_bignum_free(&s->d);
+	crypto_bignum_free(&s->n);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->q);
+	crypto_bignum_free(&s->qp);
+	crypto_bignum_free(&s->dp);
+	crypto_bignum_free(&s->dq);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
@@ -556,7 +556,7 @@ static TEE_Result do_alloc_publickey(struct rsa_public_key *s,
 	if (!bn_alloc_max(&s->e))
 		return TEE_ERROR_OUT_OF_MEMORY;
 	if (!bn_alloc_max(&s->n)) {
-		crypto_bignum_free(s->e);
+		crypto_bignum_free(&s->e);
 		return TEE_ERROR_OUT_OF_MEMORY;
 	}
 
@@ -566,8 +566,8 @@ static TEE_Result do_alloc_publickey(struct rsa_public_key *s,
 static void do_free_publickey(struct rsa_public_key *s)
 {
 	if (s) {
-		crypto_bignum_free(s->n);
-		crypto_bignum_free(s->e);
+		crypto_bignum_free(&s->n);
+		crypto_bignum_free(&s->e);
 	}
 }
 
@@ -587,14 +587,14 @@ static void do_free_keypair(struct rsa_keypair *s)
 			sss_se05x_key_store_erase_key(se050_kstore, &k_object);
 	}
 
-	crypto_bignum_free(s->e);
-	crypto_bignum_free(s->d);
-	crypto_bignum_free(s->n);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->q);
-	crypto_bignum_free(s->qp);
-	crypto_bignum_free(s->dp);
-	crypto_bignum_free(s->dq);
+	crypto_bignum_free(&s->e);
+	crypto_bignum_free(&s->d);
+	crypto_bignum_free(&s->n);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->q);
+	crypto_bignum_free(&s->qp);
+	crypto_bignum_free(&s->dp);
+	crypto_bignum_free(&s->dq);
 }
 
 static TEE_Result do_gen_keypair(struct rsa_keypair *key, size_t kb)

programming_language: C
filename: ecc.c
change_type: ModificationType.MODIFY
diff: @@ -271,9 +271,9 @@ static TEE_Result sign(uint32_t algo, struct ecc_keypair *key,
 
 	versal_mbox_alloc(bytes, NULL, &k);
 	crypto_bignum_bn2bin_eswap(key->curve, ephemeral.d, k.buf);
-	crypto_bignum_free(ephemeral.d);
-	crypto_bignum_free(ephemeral.x);
-	crypto_bignum_free(ephemeral.y);
+	crypto_bignum_free(&ephemeral.d);
+	crypto_bignum_free(&ephemeral.x);
+	crypto_bignum_free(&ephemeral.y);
 
 	/* Private key*/
 	versal_mbox_alloc(bytes, NULL, &d);

programming_language: C
filename: crypto.h
change_type: ModificationType.MODIFY
diff: @@ -98,7 +98,7 @@ size_t crypto_bignum_num_bytes(struct bignum *a);
 size_t crypto_bignum_num_bits(struct bignum *a);
 void crypto_bignum_bn2bin(const struct bignum *from, uint8_t *to);
 void crypto_bignum_copy(struct bignum *to, const struct bignum *from);
-void crypto_bignum_free(struct bignum *a);
+void crypto_bignum_free(struct bignum **a);
 void crypto_bignum_clear(struct bignum *a);
 
 /* return -1 if a<b, 0 if a==b, +1 if a>b */

programming_language: C
filename: dh.c
change_type: ModificationType.MODIFY
diff: @@ -28,10 +28,10 @@ TEE_Result crypto_acipher_alloc_dh_keypair(struct dh_keypair *s,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->g);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->y);
-	crypto_bignum_free(s->x);
+	crypto_bignum_free(&s->g);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->y);
+	crypto_bignum_free(&s->x);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 

programming_language: C
filename: dsa.c
change_type: ModificationType.MODIFY
diff: @@ -30,10 +30,10 @@ TEE_Result crypto_acipher_alloc_dsa_keypair(struct dsa_keypair *s,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->g);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->q);
-	crypto_bignum_free(s->y);
+	crypto_bignum_free(&s->g);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->q);
+	crypto_bignum_free(&s->y);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 
@@ -52,9 +52,9 @@ TEE_Result crypto_acipher_alloc_dsa_public_key(struct dsa_public_key *s,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->g);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->q);
+	crypto_bignum_free(&s->g);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->q);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 

programming_language: C
filename: ecc.c
change_type: ModificationType.MODIFY
diff: @@ -18,8 +18,8 @@ static void _ltc_ecc_free_public_key(struct ecc_public_key *s)
 	if (!s)
 		return;
 
-	crypto_bignum_free(s->x);
-	crypto_bignum_free(s->y);
+	crypto_bignum_free(&s->x);
+	crypto_bignum_free(&s->y);
 }
 
 /*
@@ -460,8 +460,8 @@ TEE_Result crypto_asym_alloc_ecc_keypair(struct ecc_keypair *s,
 err:
 	s->ops = NULL;
 
-	crypto_bignum_free(s->d);
-	crypto_bignum_free(s->x);
+	crypto_bignum_free(&s->d);
+	crypto_bignum_free(&s->x);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
@@ -536,7 +536,7 @@ TEE_Result crypto_asym_alloc_ecc_public_key(struct ecc_public_key *s,
 err:
 	s->ops = NULL;
 
-	crypto_bignum_free(s->x);
+	crypto_bignum_free(&s->x);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }

programming_language: C
filename: mpi_desc.c
change_type: ModificationType.MODIFY
diff: @@ -763,10 +763,13 @@ struct bignum *crypto_bignum_allocate(size_t size_bits)
 	return (struct bignum *)bn;
 }
 
-void crypto_bignum_free(struct bignum *s)
+void crypto_bignum_free(struct bignum **s)
 {
-	mbedtls_mpi_free((mbedtls_mpi *)s);
-	free(s);
+	assert(s);
+
+	mbedtls_mpi_free((mbedtls_mpi *)*s);
+	free(*s);
+	*s = NULL;
 }
 
 void crypto_bignum_clear(struct bignum *s)

programming_language: C
filename: rsa.c
change_type: ModificationType.MODIFY
diff: @@ -133,7 +133,7 @@ TEE_Result sw_crypto_acipher_alloc_rsa_public_key(struct rsa_public_key *s,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->e);
+	crypto_bignum_free(&s->e);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 
@@ -145,8 +145,8 @@ void sw_crypto_acipher_free_rsa_public_key(struct rsa_public_key *s)
 {
 	if (!s)
 		return;
-	crypto_bignum_free(s->n);
-	crypto_bignum_free(s->e);
+	crypto_bignum_free(&s->n);
+	crypto_bignum_free(&s->e);
 }
 
 
@@ -157,14 +157,14 @@ void sw_crypto_acipher_free_rsa_keypair(struct rsa_keypair *s)
 {
 	if (!s)
 		return;
-	crypto_bignum_free(s->e);
-	crypto_bignum_free(s->d);
-	crypto_bignum_free(s->n);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->q);
-	crypto_bignum_free(s->qp);
-	crypto_bignum_free(s->dp);
-	crypto_bignum_free(s->dq);
+	crypto_bignum_free(&s->e);
+	crypto_bignum_free(&s->d);
+	crypto_bignum_free(&s->n);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->q);
+	crypto_bignum_free(&s->qp);
+	crypto_bignum_free(&s->dp);
+	crypto_bignum_free(&s->dq);
 }
 
 TEE_Result crypto_acipher_gen_rsa_key(struct rsa_keypair *key,

programming_language: C
filename: tee_svc_cryp.c
change_type: ModificationType.MODIFY
diff: @@ -899,8 +899,7 @@ static void op_attr_bignum_free(void *attr)
 {
 	struct bignum **bn = attr;
 
-	crypto_bignum_free(*bn);
-	*bn = NULL;
+	crypto_bignum_free(bn);
 }
 
 static TEE_Result op_attr_value_from_user(void *attr, const void *buffer,
@@ -3557,8 +3556,8 @@ TEE_Result syscall_cryp_derive_key(unsigned long state,
 		} else {
 			res = TEE_ERROR_OUT_OF_MEMORY;
 		}
-		crypto_bignum_free(pub);
-		crypto_bignum_free(ss);
+		crypto_bignum_free(&pub);
+		crypto_bignum_free(&ss);
 	} else if (cs->algo == TEE_ALG_ECDH_DERIVE_SHARED_SECRET) {
 		uint32_t curve = ((struct ecc_keypair *)ko->attr)->curve;
 		struct ecc_public_key key_public = { };

programming_language: C
filename: bignum.c
change_type: ModificationType.MODIFY
diff: @@ -87,10 +87,13 @@ struct bignum *crypto_bignum_allocate(size_t size_bits)
 	return (struct bignum *)bn;
 }
 
-void crypto_bignum_free(struct bignum *s)
+void crypto_bignum_free(struct bignum **s)
 {
-	mbedtls_mpi_free((mbedtls_mpi *)s);
-	free(s);
+	assert(s);
+
+	mbedtls_mpi_free((mbedtls_mpi *)*s);
+	free(*s);
+	*s = NULL;
 }
 
 void crypto_bignum_clear(struct bignum *s)

programming_language: C
filename: dh.c
change_type: ModificationType.MODIFY
diff: @@ -35,10 +35,10 @@ TEE_Result crypto_acipher_alloc_dh_keypair(struct dh_keypair *s,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->g);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->y);
-	crypto_bignum_free(s->x);
+	crypto_bignum_free(&s->g);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->y);
+	crypto_bignum_free(&s->x);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 

programming_language: C
filename: ecc.c
change_type: ModificationType.MODIFY
diff: @@ -40,8 +40,8 @@ static void ecc_free_public_key(struct ecc_public_key *s)
 	if (!s)
 		return;
 
-	crypto_bignum_free(s->x);
-	crypto_bignum_free(s->y);
+	crypto_bignum_free(&s->x);
+	crypto_bignum_free(&s->y);
 }
 
 static TEE_Result ecc_get_keysize(uint32_t curve, uint32_t algo,
@@ -461,8 +461,8 @@ TEE_Result crypto_asym_alloc_ecc_keypair(struct ecc_keypair *s,
 	return TEE_SUCCESS;
 
 err:
-	crypto_bignum_free(s->d);
-	crypto_bignum_free(s->x);
+	crypto_bignum_free(&s->d);
+	crypto_bignum_free(&s->x);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
@@ -558,7 +558,7 @@ TEE_Result crypto_asym_alloc_ecc_public_key(struct ecc_public_key *s,
 	return TEE_SUCCESS;
 
 err:
-	crypto_bignum_free(s->x);
+	crypto_bignum_free(&s->x);
 
 	return TEE_ERROR_OUT_OF_MEMORY;
 }

programming_language: C
filename: rsa.c
change_type: ModificationType.MODIFY
diff: @@ -185,7 +185,7 @@ TEE_Result sw_crypto_acipher_alloc_rsa_public_key(struct rsa_public_key *s,
 		goto err;
 	return TEE_SUCCESS;
 err:
-	crypto_bignum_free(s->e);
+	crypto_bignum_free(&s->e);
 	return TEE_ERROR_OUT_OF_MEMORY;
 }
 
@@ -196,8 +196,8 @@ void sw_crypto_acipher_free_rsa_public_key(struct rsa_public_key *s)
 {
 	if (!s)
 		return;
-	crypto_bignum_free(s->n);
-	crypto_bignum_free(s->e);
+	crypto_bignum_free(&s->n);
+	crypto_bignum_free(&s->e);
 }
 
 void crypto_acipher_free_rsa_keypair(struct rsa_keypair *s)
@@ -207,14 +207,14 @@ void sw_crypto_acipher_free_rsa_keypair(struct rsa_keypair *s)
 {
 	if (!s)
 		return;
-	crypto_bignum_free(s->e);
-	crypto_bignum_free(s->d);
-	crypto_bignum_free(s->n);
-	crypto_bignum_free(s->p);
-	crypto_bignum_free(s->q);
-	crypto_bignum_free(s->qp);
-	crypto_bignum_free(s->dp);
-	crypto_bignum_free(s->dq);
+	crypto_bignum_free(&s->e);
+	crypto_bignum_free(&s->d);
+	crypto_bignum_free(&s->n);
+	crypto_bignum_free(&s->p);
+	crypto_bignum_free(&s->q);
+	crypto_bignum_free(&s->qp);
+	crypto_bignum_free(&s->dp);
+	crypto_bignum_free(&s->dq);
 }
 
 TEE_Result crypto_acipher_gen_rsa_key(struct rsa_keypair *key,

programming_language: C