aboutsummaryrefslogtreecommitdiff
path: root/core/kernel/tee_ta_manager.c
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 /core/kernel/tee_ta_manager.c
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>
Diffstat (limited to 'core/kernel/tee_ta_manager.c')
-rw-r--r--core/kernel/tee_ta_manager.c121
1 files changed, 101 insertions, 20 deletions
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);