aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOvidiu Mihalachi <ovidiu_mihalachi@mentor.com>2019-01-28 13:01:24 +0200
committerJérôme Forissier <jerome.forissier@linaro.org>2019-05-07 16:16:24 +0200
commitfd10f62b821033f20d6fdc73cfd804d18806b46d (patch)
treeae1db8f1a4d93728c0442f47eaed99dcb5e4ea09
parent6e59bb1e95f0b3334d2f06a1312e9e395bb1232c (diff)
core: keep alive TA context can be created after TA has panickedHEADmaster
When a keep alive TA instance panics, it continues to exist and blocks all further use of the TA until the next reboot of the system. Moreover, when a new session is trying to be created for the panicked TA (while another session to that TA is still opened), the system hangs. This change releases panicked TA context and clears all references to the released context when the TA panics regardless the TA properties. This allows keep alive TA instances to be created back after they have panicked without needing to reboot OP-TEE core. Sessions on panicked TAs have to be closed by the client by calling the proper API when session client is scheduled back. Signed-off-by: Ovidiu Mihalachi <ovidiu_mihalachi@mentor.com> Reviewed-by: Etienne Carriere <etienne.carriere@linaro.org> Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
-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) {