Vulnerability: Linaro/OP-TEE OP-TEE Prior to version v3.4.0 is affected by: Boundary checks. The impact is: This could lead to corruption of any memory which the TA can access. The component is: optee_os. The fixed version is: v3.4.0.
Vulnerability ID: CVE-2019-1010292
CWE: CWE-787
Severity score: 6.4
Project: https://github.com/OP-TEE/optee_os
Published: 2019-07-16
File: core/arch/arm/tee/entry_std.c
Commit message: core: ensure that supplied range matches MOBJ

In set_rmem_param() if the MOBJ is found by the cookie it's verified to
represent non-secure shared memory. Prior to this patch the supplied
sub-range to be used of the MOBJ was not checked here and relied on
later checks further down the chain. Those checks seems to be enough
for user TAs, but not for pseudo TAs where the size isn't checked.

This patch adds a check for offset and size to see that they remain
inside the memory covered by the MOBJ.

Fixes: OP-TEE-2018-0004: "Unchecked parameters are passed through from
REE".

Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
Tested-by: Joakim Bech <joakim.bech@linaro.org> (QEMU v7, v8)
Reviewed-by: Joakim Bech <joakim.bech@linaro.org>
Reported-by: Riscure <inforequest@riscure.com>
Reported-by: Alyssa Milburn <a.a.milburn@vu.nl>
Acked-by: Etienne Carriere <etienne.carriere@linaro.org>
Commit author: Jens Wiklander

Vulnerable version (before fix):
 static TEE_Result set_tmem_param(const struct optee_msg_param_tmem *tmem, static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem, 				 struct param_mem *mem) { 	uint64_t shm_ref = READ_ONCE(rmem->shm_ref);  	mem->mobj = mobj_reg_shm_get_by_cookie(shm_ref); static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem, 	mem->offs = READ_ONCE(rmem->offs); 	mem->size = READ_ONCE(rmem->size);  	return TEE_SUCCESS; } 

Fixed version (after fix):
 static TEE_Result set_tmem_param(const struct optee_msg_param_tmem *tmem, static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem, 				 struct param_mem *mem) { 	size_t req_size = 0; 	uint64_t shm_ref = READ_ONCE(rmem->shm_ref);  	mem->mobj = mobj_reg_shm_get_by_cookie(shm_ref); static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem, 	mem->offs = READ_ONCE(rmem->offs); 	mem->size = READ_ONCE(rmem->size);  	/* 	 * Check that the supplied offset and size is covered by the 	 * previously verified MOBJ. 	 */ 	if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) || 	    mem->mobj->size < req_size) 		return TEE_ERROR_SECURITY;  	return TEE_SUCCESS; } 

Patch:
patch: @@ -101,6 +101,7 @@ static TEE_Result set_tmem_param(const struct optee_msg_param_tmem *tmem,
 static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem,
 				 struct param_mem *mem)
 {
+	size_t req_size = 0;
 	uint64_t shm_ref = READ_ONCE(rmem->shm_ref);
 
 	mem->mobj = mobj_reg_shm_get_by_cookie(shm_ref);
@@ -110,6 +111,14 @@ static TEE_Result set_rmem_param(const struct optee_msg_param_rmem *rmem,
 	mem->offs = READ_ONCE(rmem->offs);
 	mem->size = READ_ONCE(rmem->size);
 
+	/*
+	 * Check that the supplied offset and size is covered by the
+	 * previously verified MOBJ.
+	 */
+	if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) ||
+	    mem->mobj->size < req_size)
+		return TEE_ERROR_SECURITY;
+
 	return TEE_SUCCESS;
 }
path: core/arch/arm/tee/entry_std.c