TEE_Result syscall_se_session_open_channel(unsigned long session_handle, unsigned long is_logical, const void *aid_buf, size_t aid_buf_len, uint32_t *channel_handle) { TEE_Result ret; struct tee_se_session *s = tee_svc_uref_to_kaddr(session_handle); struct tee_ta_session *sess; struct tee_se_service *service; struct tee_se_aid *se_aid = NULL; struct tee_se_channel *kc = NULL; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; if (!tee_se_service_is_session_valid(service, s)) return TEE_ERROR_BAD_PARAMETERS; if (aid_buf) { ret = tee_se_aid_create_from_buffer((void *)aid_buf, aid_buf_len, &se_aid); if (ret != TEE_SUCCESS) return ret; } if (is_logical) ret = tee_se_session_open_logical_channel(s, se_aid, &kc); else ret = tee_se_session_open_basic_channel(s, se_aid, &kc); if (ret != TEE_SUCCESS) goto error_free_aid; ret = tee_svc_copy_kaddr_to_uref(channel_handle, kc); if (ret != TEE_SUCCESS) goto error_free_aid; return TEE_SUCCESS; error_free_aid: if (se_aid) tee_se_aid_release(se_aid); return TEE_SUCCESS; }
TEE_Result syscall_se_channel_get_select_resp(unsigned long channel_handle, void *resp, uint64_t *resp_len) { TEE_Result ret; struct tee_se_channel *c = tee_svc_uref_to_kaddr(channel_handle); struct tee_ta_session *sess; struct tee_se_service *service; struct resp_apdu *resp_apdu; size_t kresp_len; uint64_t uresp_len; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; if (!tee_se_service_is_channel_valid(service, c)) return TEE_ERROR_BAD_PARAMETERS; ret = tee_svc_copy_from_user(&uresp_len, resp_len, sizeof(size_t)); if (ret != TEE_SUCCESS) return TEE_ERROR_BAD_PARAMETERS; ret = tee_se_channel_get_select_response(c, &resp_apdu); if (ret != TEE_SUCCESS) return ret; kresp_len = apdu_get_length(to_apdu_base(resp_apdu)); if (uresp_len < kresp_len) return TEE_ERROR_SHORT_BUFFER; ret = tee_svc_copy_to_user(resp, apdu_get_data(to_apdu_base(resp_apdu)), kresp_len); if (ret != TEE_SUCCESS) return ret; uresp_len = kresp_len; ret = tee_svc_copy_to_user(resp_len, &uresp_len, sizeof(*resp_len)); if (ret != TEE_SUCCESS) return ret; return TEE_SUCCESS; }
TEE_Result syscall_se_channel_select_next(unsigned long channel_handle) { TEE_Result ret; struct tee_se_channel *c = tee_svc_uref_to_kaddr(channel_handle); struct tee_ta_session *sess; struct tee_se_service *service; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; if (!tee_se_service_is_channel_valid(service, c)) return TEE_ERROR_BAD_PARAMETERS; tee_se_channel_select_next(c); return TEE_SUCCESS; }
TEE_Result syscall_se_session_close(unsigned long session_handle) { TEE_Result ret; struct tee_se_session *s = tee_svc_uref_to_kaddr(session_handle); struct tee_ta_session *sess; struct tee_se_service *service; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; if (!tee_se_service_is_session_valid(service, s)) return TEE_ERROR_BAD_PARAMETERS; tee_se_service_close_session(service, s); return TEE_SUCCESS; }
TEE_Result syscall_se_reader_close_sessions(unsigned long reader_handle) { TEE_Result ret; struct tee_se_reader_proxy *r = tee_svc_uref_to_kaddr(reader_handle); struct tee_se_service *service; struct tee_ta_session *sess; if (!tee_se_manager_is_reader_proxy_valid(r)) return TEE_ERROR_BAD_PARAMETERS; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; tee_se_service_close_sessions_by_reader(service, r); return TEE_SUCCESS; }
TEE_Result syscall_se_session_get_atr(unsigned long session_handle, void *atr, uint64_t *atr_len) { TEE_Result ret; struct tee_se_session *s = tee_svc_uref_to_kaddr(session_handle); struct tee_ta_session *sess; struct tee_se_service *service; size_t katr_len; uint64_t uatr_len; uint8_t *katr; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; if (!tee_se_service_is_session_valid(service, s)) return TEE_ERROR_BAD_PARAMETERS; ret = tee_svc_copy_from_user(&uatr_len, atr_len, sizeof(uatr_len)); if (ret != TEE_SUCCESS) return ret; katr_len = uatr_len; ret = tee_se_session_get_atr(s, &katr, &katr_len); if (ret != TEE_SUCCESS) return ret; if (uatr_len < katr_len) return TEE_ERROR_SHORT_BUFFER; ret = tee_svc_copy_to_user(atr, katr, katr_len); if (ret != TEE_SUCCESS) return ret; uatr_len = katr_len; ret = tee_svc_copy_to_user(atr_len, &uatr_len, sizeof(*atr_len)); if (ret != TEE_SUCCESS) return ret; return TEE_SUCCESS; }
static void get_current_ta_exidx_stack(vaddr_t *exidx, size_t *exidx_sz, vaddr_t *stack, size_t *stack_size) { struct tee_ta_session *s; struct user_ta_ctx *utc; if (tee_ta_get_current_session(&s) != TEE_SUCCESS) panic(); utc = to_user_ta_ctx(s->ctx); /* Only 32-bit TAs use .ARM.exidx/.ARM.extab exception handling */ assert(utc->is_32bit); *exidx = utc->exidx_start; /* NULL if TA has no unwind tables */ if (*exidx) *exidx += utc->load_addr; *exidx_sz = utc->exidx_size; *stack = utc->stack_addr; *stack_size = utc->mobj_stack->size; }
TEE_Result syscall_se_reader_get_name(unsigned long reader_handle, char *name, uint64_t *name_len) { TEE_Result ret; struct tee_se_reader_proxy *r = tee_svc_uref_to_kaddr(reader_handle); struct tee_ta_session *sess; char *kname; size_t kname_len; uint64_t uname_len; if (!tee_se_manager_is_reader_proxy_valid(r)) return TEE_ERROR_BAD_PARAMETERS; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; ret = tee_svc_copy_from_user(&uname_len, name_len, sizeof(uname_len)); if (ret != TEE_SUCCESS) return ret; kname_len = uname_len; tee_se_reader_get_name(r, &kname, &kname_len); if (uname_len < kname_len) return TEE_ERROR_SHORT_BUFFER; ret = tee_svc_copy_to_user(name, kname, kname_len); if (ret != TEE_SUCCESS) return ret; uname_len = kname_len; ret = tee_svc_copy_to_user(name_len, &uname_len, sizeof(*name_len)); if (ret != TEE_SUCCESS) return ret; return TEE_SUCCESS; }
void tee_svc_sys_panic(uint32_t code) { struct tee_ta_session *sess; if (tee_ta_get_current_session(&sess) == TEE_SUCCESS) { EMSG("Set session 0x%x to panicked", sess); sess->ctx->panicked = 1; sess->ctx->panic_code = code; { /* * Force panicking. This memory error will be trapped by * the error exception handler myErrorHandler() */ EMSG("Following 'DTLB exception in bundle'"); EMSG(" is generated with code %d", code); int *p = 0; *p = 1; } } else { DMSG("Panic called from unknown TA"); } }
/* Called when a TA calls an OpenSession on another TA */ TEE_Result tee_svc_open_ta_session(const TEE_UUID *dest, uint32_t cancel_req_to, uint32_t param_types, TEE_Param params[4], TEE_TASessionHandle *ta_sess, uint32_t *ret_orig) { TEE_Result res; uint32_t ret_o = TEE_ORIGIN_TEE; struct tee_ta_session *s = NULL; struct tee_ta_session *sess; tee_mm_entry_t *mm_param = NULL; TEE_UUID *uuid = malloc(sizeof(TEE_UUID)); struct tee_ta_param *param = malloc(sizeof(struct tee_ta_param)); TEE_Identity *clnt_id = malloc(sizeof(TEE_Identity)); tee_paddr_t tmp_buf_pa[TEE_NUM_PARAMS]; if (uuid == NULL || param == NULL || clnt_id == NULL) { res = TEE_ERROR_OUT_OF_MEMORY; goto out_free_only; } memset(param, 0, sizeof(struct tee_ta_param)); res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) goto out_free_only; res = tee_svc_copy_from_user(sess, uuid, dest, sizeof(TEE_UUID)); if (res != TEE_SUCCESS) goto function_exit; clnt_id->login = TEE_LOGIN_TRUSTED_APP; memcpy(&clnt_id->uuid, &sess->ctx->head->uuid, sizeof(TEE_UUID)); res = tee_svc_copy_param(sess, NULL, param_types, params, param, tmp_buf_pa, &mm_param); if (res != TEE_SUCCESS) goto function_exit; /* * Find session of a multi session TA or a static TA * In such a case, there is no need to ask the supplicant for the TA * code */ res = tee_ta_open_session(&ret_o, &s, &sess->ctx->open_sessions, uuid, NULL, clnt_id, cancel_req_to, param); if (ret_o != TEE_ORIGIN_TEE || res != TEE_ERROR_ITEM_NOT_FOUND) goto function_exit; if (ret_o == TEE_ORIGIN_TEE && res == TEE_ERROR_ITEM_NOT_FOUND) { kta_signed_header_t *ta = NULL; struct tee_ta_nwumap lp; tee_mmu_set_ctx(NULL); /* Load TA */ res = tee_ta_rpc_load(uuid, &ta, &lp, &ret_o); if (res != TEE_SUCCESS) { tee_mmu_set_ctx(sess->ctx); goto function_exit; } res = tee_ta_open_session(&ret_o, &s, &sess->ctx->open_sessions, uuid, ta, clnt_id, cancel_req_to, param); tee_mmu_set_ctx(sess->ctx); if (res != TEE_SUCCESS) goto function_exit; s->ctx->nwumap = lp; } res = tee_svc_update_out_param(sess, NULL, param, tmp_buf_pa, params); if (res != TEE_SUCCESS) goto function_exit; function_exit: tee_ta_set_current_session(sess); if (mm_param != NULL) { TEE_Result res2; void *va = 0; res2 = tee_mmu_kmap_pa2va((void *)tee_mm_get_smem(mm_param), &va); if (res2 == TEE_SUCCESS) tee_mmu_kunmap(va, tee_mm_get_bytes(mm_param)); } tee_mm_free(mm_param); tee_svc_copy_to_user(sess, ta_sess, &s, sizeof(s)); tee_svc_copy_to_user(sess, ret_orig, &ret_o, sizeof(ret_o)); out_free_only: free(param); free(uuid); free(clnt_id); return res; }
TEE_Result tee_svc_sys_get_property(uint32_t prop, tee_uaddr_t buf, size_t blen) { static const char api_vers[] = "1.0"; static const char descr[] = "Version N.N"; /* * Value 100 means: * System time based on REE-controlled timers. Can be tampered by the * REE. The implementation must still guarantee that the system time * is monotonous, i.e., successive calls to TEE_GetSystemTime must * return increasing values of the system time. */ static const uint32_t sys_time_prot_lvl = 100; static const uint32_t ta_time_prot_lvl = 100; struct tee_ta_session *sess; TEE_Result res; res = tee_ta_get_current_session(&sess); if (res != TEE_SUCCESS) return res; switch (prop) { case UTEE_PROP_TEE_API_VERSION: if (blen < sizeof(api_vers)) return TEE_ERROR_SHORT_BUFFER; return tee_svc_copy_to_user(sess, (void *)buf, api_vers, sizeof(api_vers)); case UTEE_PROP_TEE_DESCR: if (blen < sizeof(descr)) return TEE_ERROR_SHORT_BUFFER; return tee_svc_copy_to_user(sess, (void *)buf, descr, sizeof(descr)); case UTEE_PROP_TEE_DEV_ID: { TEE_UUID uuid; const size_t nslen = 4; uint8_t data[4 + FVR_DIE_ID_NUM_REGS * sizeof(uint32_t)] = { 'S', 'T', 'E', 'E' }; if (blen < sizeof(uuid)) return TEE_ERROR_SHORT_BUFFER; if (tee_otp_get_die_id (data + nslen, sizeof(data) - nslen)) return TEE_ERROR_BAD_STATE; res = tee_hash_createdigest( TEE_ALG_SHA256, data, sizeof(data), (uint8_t *)&uuid, sizeof(uuid)); if (res != TEE_SUCCESS) return TEE_ERROR_BAD_STATE; /* * Changes the random value into and UUID as specifiec * in RFC 4122. The magic values are from the example * code in the RFC. * * TEE_UUID is defined slightly different from the RFC, * but close enough for our purpose. */ uuid.timeHiAndVersion &= 0x0fff; uuid.timeHiAndVersion |= 5 << 12; /* uuid.clock_seq_hi_and_reserved in the RFC */ uuid.clockSeqAndNode[0] &= 0x3f; uuid.clockSeqAndNode[0] |= 0x80; return tee_svc_copy_to_user(sess, (void *)buf, &uuid, sizeof(TEE_UUID)); } case UTEE_PROP_TEE_SYS_TIME_PROT_LEVEL: if (blen < sizeof(sys_time_prot_lvl)) return TEE_ERROR_SHORT_BUFFER; return tee_svc_copy_to_user(sess, (void *)buf, &sys_time_prot_lvl, sizeof(sys_time_prot_lvl)); case UTEE_PROP_TEE_TA_TIME_PROT_LEVEL: if (blen < sizeof(ta_time_prot_lvl)) return TEE_ERROR_SHORT_BUFFER; return tee_svc_copy_to_user(sess, (void *)buf, &ta_time_prot_lvl, sizeof(ta_time_prot_lvl)); case UTEE_PROP_TEE_ARITH_MAX_BIG_INT_SIZE: { uint32_t v = LTC_MAX_BITS_PER_VARIABLE / 2; if (blen < sizeof(v)) return TEE_ERROR_SHORT_BUFFER; return tee_svc_copy_to_user(sess, (void *)buf, &v, sizeof(v)); } case UTEE_PROP_CLIENT_ID: { if (blen < sizeof(TEE_Identity)) return TEE_ERROR_SHORT_BUFFER; return tee_svc_copy_to_user(sess, (void *)buf, &sess->clnt_id, sizeof(TEE_Identity)); } case UTEE_PROP_TA_APP_ID: { if (blen < sizeof(TEE_UUID)) return TEE_ERROR_SHORT_BUFFER; return tee_svc_copy_to_user(sess, (void *)buf, &sess->ctx->head->uuid, sizeof(TEE_UUID)); } default: break; } return TEE_ERROR_NOT_IMPLEMENTED; }
TEE_Result syscall_se_channel_transmit(unsigned long channel_handle, void *cmd, unsigned long cmd_len, void *resp, uint64_t *resp_len) { TEE_Result ret; struct tee_se_channel *c = tee_svc_uref_to_kaddr(channel_handle); struct tee_ta_session *sess; struct tee_se_service *service; struct cmd_apdu *cmd_apdu; struct resp_apdu *resp_apdu; void *kcmd_buf; uint64_t kresp_len; ret = tee_ta_get_current_session(&sess); if (ret != TEE_SUCCESS) return ret; service = to_user_ta_ctx(sess->ctx)->se_service; if (!tee_se_service_is_channel_valid(service, c)) return TEE_ERROR_BAD_PARAMETERS; ret = tee_svc_copy_from_user(&kresp_len, resp_len, sizeof(kresp_len)); if (ret != TEE_SUCCESS) return ret; kcmd_buf = malloc(cmd_len); if (kcmd_buf == NULL) return TEE_ERROR_OUT_OF_MEMORY; ret = tee_svc_copy_from_user(kcmd_buf, cmd, cmd_len); if (ret != TEE_SUCCESS) goto err_free_cmd_buf; cmd_apdu = alloc_cmd_apdu_from_buf(kcmd_buf, cmd_len); if (cmd_apdu == NULL) goto err_free_cmd_buf; kresp_len -= 2; /* reserve space for SW1 and SW2 */ resp_apdu = alloc_resp_apdu(kresp_len); if (resp_apdu == NULL) goto err_free_cmd_apdu; ret = tee_se_channel_transmit(c, cmd_apdu, resp_apdu); if (ret != TEE_SUCCESS) goto err_free_resp_apdu; kresp_len = apdu_get_length(to_apdu_base(resp_apdu)); ret = tee_svc_copy_to_user(resp_len, &kresp_len, sizeof(*resp_len)); if (ret != TEE_SUCCESS) goto err_free_resp_apdu; ret = tee_svc_copy_to_user(resp, resp_apdu_get_data(resp_apdu), kresp_len); if (ret != TEE_SUCCESS) goto err_free_resp_apdu; apdu_release(to_apdu_base(resp_apdu)); apdu_release(to_apdu_base(cmd_apdu)); free(kcmd_buf); return TEE_SUCCESS; err_free_resp_apdu: apdu_release(to_apdu_base(resp_apdu)); err_free_cmd_apdu: apdu_release(to_apdu_base(cmd_apdu)); err_free_cmd_buf: free(kcmd_buf); return ret; }