static TEE_Result gprof_send_rpc(TEE_UUID *uuid, void *buf, size_t len, uint32_t *id) { struct mobj *mobj; TEE_Result res = TEE_ERROR_GENERIC; char *va; mobj = thread_rpc_alloc_payload(sizeof(*uuid) + len); if (!mobj) return TEE_ERROR_OUT_OF_MEMORY; va = mobj_get_va(mobj, 0); if (!va) goto exit; memcpy(va, uuid, sizeof(*uuid)); memcpy(va + sizeof(*uuid), buf, len); struct thread_param params[3] = { [0] = THREAD_PARAM_VALUE(INOUT, *id, 0, 0), [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, sizeof(*uuid)), [2] = THREAD_PARAM_MEMREF(IN, mobj, sizeof(*uuid), len), }; res = thread_rpc_cmd(OPTEE_RPC_CMD_GPROF, 3, params); if (res != TEE_SUCCESS) goto exit; *id = (uint32_t)params[0].u.value.a; exit: thread_rpc_free_payload(mobj); return res; }
void tee_fs_rpc_cache_clear(struct thread_specific_data *tsd) { if (tsd->rpc_fs_payload) { thread_rpc_free_payload(tsd->rpc_fs_payload_cookie, tsd->rpc_fs_payload_mobj); tsd->rpc_fs_payload = NULL; tsd->rpc_fs_payload_cookie = 0; tsd->rpc_fs_payload_size = 0; tsd->rpc_fs_payload_mobj = NULL; } }
static void ree_fs_ta_close(struct user_ta_store_handle *h) { struct ree_fs_ta_handle *handle = (struct ree_fs_ta_handle *)h; if (!handle) return; thread_rpc_free_payload(handle->mobj); crypto_hash_free_ctx(handle->hash_ctx, handle->hash_algo); free(handle->shdr); free(handle); }
void *tee_fs_rpc_cache_alloc(size_t size, struct mobj **mobj, uint64_t *cookie) { struct thread_specific_data *tsd = thread_get_tsd(); size_t sz = size; uint64_t c = 0; paddr_t p; void *va; if (!size) return NULL; /* * Always allocate in page chunks as normal world allocates payload * memory as complete pages. */ sz = ROUNDUP(size, SMALL_PAGE_SIZE); if (sz > tsd->rpc_fs_payload_size) { tee_fs_rpc_cache_clear(tsd); *mobj = thread_rpc_alloc_payload(sz, &c); if (!*mobj) return NULL; if (mobj_get_pa(*mobj, 0, 0, &p)) goto err; if (!ALIGNMENT_IS_OK(p, uint64_t)) goto err; va = mobj_get_va(*mobj, 0); if (!va) goto err; tsd->rpc_fs_payload = va; tsd->rpc_fs_payload_mobj = *mobj; tsd->rpc_fs_payload_cookie = c; tsd->rpc_fs_payload_size = sz; } else *mobj = tsd->rpc_fs_payload_mobj; *cookie = tsd->rpc_fs_payload_cookie; return tsd->rpc_fs_payload; err: thread_rpc_free_payload(c, *mobj); return NULL; }
/* * Load a TA via RPC with UUID defined by input param @uuid. The virtual * address of the raw TA binary is received in out parameter @ta. */ static TEE_Result rpc_load(const TEE_UUID *uuid, struct shdr **ta, size_t *ta_size, struct mobj **mobj) { TEE_Result res; struct thread_param params[2]; if (!uuid || !ta || !mobj || !ta_size) return TEE_ERROR_BAD_PARAMETERS; memset(params, 0, sizeof(params)); params[0].attr = THREAD_PARAM_ATTR_VALUE_IN; tee_uuid_to_octets((void *)¶ms[0].u.value, uuid); params[1].attr = THREAD_PARAM_ATTR_MEMREF_OUT; res = thread_rpc_cmd(OPTEE_RPC_CMD_LOAD_TA, 2, params); if (res != TEE_SUCCESS) return res; *mobj = thread_rpc_alloc_payload(params[1].u.memref.size); if (!*mobj) return TEE_ERROR_OUT_OF_MEMORY; if ((*mobj)->size < params[1].u.memref.size) { res = TEE_ERROR_SHORT_BUFFER; goto exit; } *ta = mobj_get_va(*mobj, 0); /* We don't expect NULL as thread_rpc_alloc_payload() was successful */ assert(*ta); *ta_size = params[1].u.memref.size; params[0].attr = THREAD_PARAM_ATTR_VALUE_IN; tee_uuid_to_octets((void *)¶ms[0].u.value, uuid); params[1].attr = THREAD_PARAM_ATTR_MEMREF_OUT; params[1].u.memref.offs = 0; params[1].u.memref.mobj = *mobj; res = thread_rpc_cmd(OPTEE_RPC_CMD_LOAD_TA, 2, params); exit: if (res != TEE_SUCCESS) thread_rpc_free_payload(*mobj); return res; }
static TEE_Result gprof_send_rpc(TEE_UUID *uuid, void *buf, size_t len, uint32_t *id) { struct optee_msg_param params[3]; TEE_Result res = TEE_ERROR_GENERIC; uint64_t c = 0; paddr_t pa; char *va; thread_rpc_alloc_payload(sizeof(*uuid) + len, &pa, &c); if (!pa) return TEE_ERROR_OUT_OF_MEMORY; va = phys_to_virt(pa, MEM_AREA_NSEC_SHM); if (!va) goto exit; memcpy(va, uuid, sizeof(*uuid)); memcpy(va + sizeof(*uuid), buf, len); memset(params, 0, sizeof(params)); params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INOUT; params[0].u.value.a = *id; params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; params[1].u.tmem.buf_ptr = pa; params[1].u.tmem.size = sizeof(*uuid); params[1].u.tmem.shm_ref = c; params[2].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; params[2].u.tmem.buf_ptr = pa + sizeof(*uuid); params[2].u.tmem.size = len; params[2].u.tmem.shm_ref = c; res = thread_rpc_cmd(OPTEE_MSG_RPC_CMD_GPROF, 3, params); if (res != TEE_SUCCESS) goto exit; *id = (uint32_t)params[0].u.value.a; exit: thread_rpc_free_payload(c); return res; }
static TEE_Result ree_fs_ta_open(const TEE_UUID *uuid, struct user_ta_store_handle **h) { struct ree_fs_ta_handle *handle; struct shdr *shdr = NULL; struct mobj *mobj = NULL; void *hash_ctx = NULL; uint32_t hash_algo = 0; struct shdr *ta = NULL; size_t ta_size = 0; TEE_Result res; size_t offs; handle = calloc(1, sizeof(*handle)); if (!handle) return TEE_ERROR_OUT_OF_MEMORY; /* Request TA from tee-supplicant */ res = rpc_load(uuid, &ta, &ta_size, &mobj); if (res != TEE_SUCCESS) goto error; /* Make secure copy of signed header */ shdr = shdr_alloc_and_copy(ta, ta_size); if (!shdr) { res = TEE_ERROR_SECURITY; goto error_free_payload; } /* Validate header signature */ res = shdr_verify_signature(shdr); if (res != TEE_SUCCESS) goto error_free_payload; if (shdr->img_type != SHDR_TA && shdr->img_type != SHDR_BOOTSTRAP_TA) { res = TEE_ERROR_SECURITY; goto error_free_payload; } /* * Initialize a hash context and run the algorithm over the signed * header (less the final file hash and its signature of course) */ hash_algo = TEE_DIGEST_HASH_TO_ALGO(shdr->algo); res = crypto_hash_alloc_ctx(&hash_ctx, hash_algo); if (res != TEE_SUCCESS) goto error_free_payload; res = crypto_hash_init(hash_ctx, hash_algo); if (res != TEE_SUCCESS) goto error_free_hash; res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)shdr, sizeof(*shdr)); if (res != TEE_SUCCESS) goto error_free_hash; offs = SHDR_GET_SIZE(shdr); if (shdr->img_type == SHDR_BOOTSTRAP_TA) { TEE_UUID bs_uuid; struct shdr_bootstrap_ta bs_hdr; if (ta_size < SHDR_GET_SIZE(shdr) + sizeof(bs_hdr)) { res = TEE_ERROR_SECURITY; goto error_free_hash; } memcpy(&bs_hdr, ((uint8_t *)ta + offs), sizeof(bs_hdr)); /* * There's a check later that the UUID embedded inside the * ELF is matching, but since we now have easy access to * the expected uuid of the TA we check it a bit earlier * here. */ tee_uuid_from_octets(&bs_uuid, bs_hdr.uuid); if (memcmp(&bs_uuid, uuid, sizeof(TEE_UUID))) { res = TEE_ERROR_SECURITY; goto error_free_hash; } res = crypto_hash_update(hash_ctx, hash_algo, (uint8_t *)&bs_hdr, sizeof(bs_hdr)); if (res != TEE_SUCCESS) goto error_free_hash; offs += sizeof(bs_hdr); } if (ta_size != offs + shdr->img_size) { res = TEE_ERROR_SECURITY; goto error_free_hash; } handle->nw_ta = ta; handle->nw_ta_size = ta_size; handle->offs = offs; handle->hash_algo = hash_algo; handle->hash_ctx = hash_ctx; handle->shdr = shdr; handle->mobj = mobj; *h = (struct user_ta_store_handle *)handle; return TEE_SUCCESS; error_free_hash: crypto_hash_free_ctx(hash_ctx, hash_algo); error_free_payload: thread_rpc_free_payload(mobj); error: shdr_free(shdr); free(handle); return res; }