diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/arch/arm/include/tee/entry_std.h | 3 | ||||
-rw-r--r-- | core/arch/arm/tee/entry_std.c | 5 | ||||
-rw-r--r-- | core/kernel/tee_ta_manager.c | 121 | ||||
-rw-r--r-- | core/tee/tee_svc.c | 2 |
4 files changed, 111 insertions, 20 deletions
diff --git a/core/arch/arm/include/tee/entry_std.h b/core/arch/arm/include/tee/entry_std.h index 109c3eed..4a5147bc 100644 --- a/core/arch/arm/include/tee/entry_std.h +++ b/core/arch/arm/include/tee/entry_std.h @@ -12,4 +12,7 @@ /* Standard call entry */ void tee_entry_std(struct thread_smc_args *args); +/* Get list head for sessions opened from non-secure */ +void nsec_sessions_list_head(struct tee_ta_session_head **open_sessions); + #endif /* TEE_ENTRY_STD_H */ diff --git a/core/arch/arm/tee/entry_std.c b/core/arch/arm/tee/entry_std.c index 24f174bf..876f97ea 100644 --- a/core/arch/arm/tee/entry_std.c +++ b/core/arch/arm/tee/entry_std.c @@ -529,6 +529,11 @@ static struct mobj *get_cmd_buffer(paddr_t parg, uint32_t *num_params) return mobj_shm_alloc(parg, args_size, 0); } +void nsec_sessions_list_head(struct tee_ta_session_head **open_sessions) +{ + *open_sessions = &tee_open_sessions; +} + /* * Note: this function is weak just to make it possible to exclude it from * the unpaged area. diff --git a/core/kernel/tee_ta_manager.c b/core/kernel/tee_ta_manager.c index ce6a93de..bbd76659 100644 --- a/core/kernel/tee_ta_manager.c +++ b/core/kernel/tee_ta_manager.c @@ -23,6 +23,7 @@ #include <mm/core_memprot.h> #include <mm/mobj.h> #include <mm/tee_mmu.h> +#include <tee/entry_std.h> #include <tee/tee_svc_cryp.h> #include <tee/tee_obj.h> #include <tee/tee_svc_storage.h> @@ -261,6 +262,84 @@ static void tee_ta_unlink_session(struct tee_ta_session *s, mutex_unlock(&tee_ta_mutex); } +static void destroy_session(struct tee_ta_session *s, + struct tee_ta_session_head *open_sessions) +{ + tee_ta_unlink_session(s, open_sessions); +#if defined(CFG_TA_GPROF_SUPPORT) + free(s->sbuf); +#endif + free(s); +} + +static void destroy_context(struct tee_ta_ctx *ctx) +{ + DMSG("Destroy TA ctx (0x%" PRIxVA ")", (vaddr_t)ctx); + + condvar_destroy(&ctx->busy_cv); + pgt_flush_ctx(ctx); + ctx->ops->destroy(ctx); +} + +static void destroy_ta_ctx_from_session(struct tee_ta_session *s) +{ + struct tee_ta_session *sess = NULL; + struct tee_ta_session_head *open_sessions = NULL; + struct tee_ta_ctx *ctx = NULL; + struct user_ta_ctx *utc = NULL; + size_t count = 1; /* start counting the references to the context */ + + DMSG("Remove references to context (0x%" PRIxVA ")", (vaddr_t)s->ctx); + + mutex_lock(&tee_ta_mutex); + nsec_sessions_list_head(&open_sessions); + + /* + * Next two loops will remove all references to the context which is + * about to be destroyed, but avoiding such operation to the current + * session. That will be done later in this function, only after + * the context will be properly destroyed. + */ + + /* + * Scan the entire list of opened sessions by the clients from + * non-secure world. + */ + TAILQ_FOREACH(sess, open_sessions, link) { + if (sess->ctx == s->ctx && sess != s) { + sess->ctx = NULL; + count++; + } + } + + /* + * Scan all sessions opened from secure side by searching through + * all available TA instances and for each context, scan all opened + * sessions. + */ + TAILQ_FOREACH(ctx, &tee_ctxes, link) { + if (is_user_ta_ctx(ctx)) { + utc = to_user_ta_ctx(ctx); + + TAILQ_FOREACH(sess, &utc->open_sessions, link) { + if (sess->ctx == s->ctx && sess != s) { + sess->ctx = NULL; + count++; + } + } + } + } + + assert(count == s->ctx->ref_count); + + TAILQ_REMOVE(&tee_ctxes, s->ctx, link); + mutex_unlock(&tee_ta_mutex); + + destroy_context(s->ctx); + + s->ctx = NULL; +} + /* * tee_ta_context_find - Find TA in session list based on a UUID (input) * Returns a pointer to the session @@ -416,18 +495,19 @@ TEE_Result tee_ta_close_session(struct tee_ta_session *csess, ctx = sess->ctx; DMSG("Destroy session"); + if (!ctx) { + destroy_session(sess, open_sessions); + return TEE_SUCCESS; + } + + assert(!ctx->panicked); + tee_ta_set_busy(ctx); - if (!ctx->panicked) { - set_invoke_timeout(sess, TEE_TIMEOUT_INFINITE); - ctx->ops->enter_close_session(sess); - } + set_invoke_timeout(sess, TEE_TIMEOUT_INFINITE); + ctx->ops->enter_close_session(sess); - tee_ta_unlink_session(sess, open_sessions); -#if defined(CFG_TA_GPROF_SUPPORT) - free(sess->sbuf); -#endif - free(sess); + destroy_session(sess, open_sessions); tee_ta_clear_busy(ctx); @@ -440,15 +520,10 @@ TEE_Result tee_ta_close_session(struct tee_ta_session *csess, keep_alive = (ctx->flags & TA_FLAG_INSTANCE_KEEP_ALIVE) && (ctx->flags & TA_FLAG_SINGLE_INSTANCE); if (!ctx->ref_count && !keep_alive) { - DMSG("Destroy TA ctx"); - TAILQ_REMOVE(&tee_ctxes, ctx, link); mutex_unlock(&tee_ta_mutex); - condvar_destroy(&ctx->busy_cv); - - pgt_flush_ctx(ctx); - ctx->ops->destroy(ctx); + destroy_context(ctx); } else mutex_unlock(&tee_ta_mutex); @@ -594,7 +669,7 @@ TEE_Result tee_ta_open_session(TEE_ErrorOrigin *err, ctx = s->ctx; - if (ctx->panicked) { + if (!ctx || ctx->panicked) { DMSG("panicked, call tee_ta_close_session()"); tee_ta_close_session(s, open_sessions, KERN_IDENTITY); *err = TEE_ORIGIN_TEE; @@ -650,8 +725,13 @@ TEE_Result tee_ta_invoke_command(TEE_ErrorOrigin *err, if (!check_params(sess, param)) return TEE_ERROR_BAD_PARAMETERS; - if (sess->ctx->panicked) { + if (!sess->ctx) { + /* The context has been already destroyed */ + *err = TEE_ORIGIN_TEE; + return TEE_ERROR_TARGET_DEAD; + } else if (sess->ctx->panicked) { DMSG("Panicked !"); + destroy_ta_ctx_from_session(sess); *err = TEE_ORIGIN_TEE; return TEE_ERROR_TARGET_DEAD; } @@ -661,13 +741,14 @@ TEE_Result tee_ta_invoke_command(TEE_ErrorOrigin *err, set_invoke_timeout(sess, cancel_req_to); res = sess->ctx->ops->enter_invoke_cmd(sess, cmd, param, err); + tee_ta_clear_busy(sess->ctx); + if (sess->ctx->panicked) { + destroy_ta_ctx_from_session(sess); *err = TEE_ORIGIN_TEE; - res = TEE_ERROR_TARGET_DEAD; + return TEE_ERROR_TARGET_DEAD; } - tee_ta_clear_busy(sess->ctx); - /* Short buffer is not an effective error case */ if (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER) DMSG("Error: %x of %d", res, *err); diff --git a/core/tee/tee_svc.c b/core/tee/tee_svc.c index 0f01e22a..a7d4be3d 100644 --- a/core/tee/tee_svc.c +++ b/core/tee/tee_svc.c @@ -854,6 +854,8 @@ TEE_Result syscall_invoke_ta_command(unsigned long ta_sess, res = tee_ta_invoke_command(&ret_o, called_sess, &clnt_id, cancel_req_to, cmd_id, ¶m); + if (res == TEE_ERROR_TARGET_DEAD) + goto function_exit; res2 = tee_svc_update_out_param(¶m, tmp_buf_va, usr_param); if (res2 != TEE_SUCCESS) { |