aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/arch/arm/include/tee/entry_std.h3
-rw-r--r--core/arch/arm/tee/entry_std.c5
-rw-r--r--core/kernel/tee_ta_manager.c121
-rw-r--r--core/tee/tee_svc.c2
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, &param);
+ if (res == TEE_ERROR_TARGET_DEAD)
+ goto function_exit;
res2 = tee_svc_update_out_param(&param, tmp_buf_va, usr_param);
if (res2 != TEE_SUCCESS) {