OP-TEE OS · source analysis

TA context와 session 수명

session을 먼저 만들고 목록에 연결한 다음 TA context를 찾거나 load하는 경로와 close의 참조 정리를 읽습니다.

OP-TEE OS 4.10.0의 tee_ta_manager.c를 분석 기준으로 삼는다. 세션 목록 연결, 외부 ID 반환, close 정리는 서로 다른 시점이다. 이 버전 표시는 최신 보안 버전 권고가 아니다.

Series
09 / 12
Baseline
4.10.0
Commit
753afbbee168
Source
core/kernel/tee_ta_manager.c:682-770 (발췌 범위)

session은 context를 찾기 전부터 존재하는가?

tee_ta_init_session()은 calloc()으로 세션을 만들고 condvar·초기 refcount·ID를 설정한 뒤 TAILQ_INSERT_TAIL(open_sessions, s, link)로 client 목록에 연결한다. 그 다음에 기존 TA context, secure partition, pseudo TA, user TA 순서로 찾는다.

목록 연결은 곧바로 성공 ID를 caller에게 내보내는 단계가 아니다. context 연결 또는 TA open entry가 실패하면 세션을 목록에서 제거·해제하며, tee_ta_open_session()은 성공 끝에 *sess_id를 쓴다.

close 경계

정상 context는 TA enter_close_session()을 먼저 실행하고 destroy_session()으로 들어간다. 그 안에서 unlink 표시, 남은 참조 대기, 목록 제거, 세션 해제가 진행된다.

session 목록과 TA context는 다른 수명

그림 1. 세션 객체와 context 연결의 소유권
client 목록TA 연결close
01open_sessions와 세션 ID
02tee_ta_session·refcount
03ts_sess.ctx·TA flags
04unlink·ref 대기·free
시점

client 목록에는 context 탐색 전에 삽입한다. 외부 session ID는 성공한 open이 끝날 때 반환한다.

고정 tee_ta_manager.c의 소유권 관계다. tee_ta_mutex 아래 연결하므로 이 삽입을 동시 caller에게 즉시 보이는 성공 세션으로 읽지 않는다.

초기화, context 연결, open entry, close

그림 2. tee_ta_open_session()의 실제 순서
session calloc()·초기 ref
ID 부여·목록 삽입
context 재사용 또는 TA load
검사·TA open entry
성공 ID 반환 / 실패 close

새 ID를 만들 수 없으면 삽입 전 세션만 해제한다. 삽입 뒤 초기화 실패는 목록에서 제거하고 해제한다. 초기화 뒤 parameter·TA open entry 실패는 close_session()으로 정리한다.

세션 생성과 context 연결 시점

목록 연결, context 초기화, 성공 ID 반환을 각각 구분한다.

순서고정 코드세션 상태context 상태실패 시 정리
01calloc()·condvar·ref_count = 1미연결 세션 객체아직 탐색 전할당 실패 즉시 반환
02new_session_id()·TAILQ_INSERT_TAIL()client 목록 연결·현재 thread가 잠금 보유아직 탐색 전ID 실패는 삽입 없이 free
03기존 context → secure partition → pseudo TA → user TA같은 세션 객체에 ts_sess.ctx 연결 시도재사용 또는 새 context 초기화실패하면 목록 제거·free
04check_params()·enter_open_session()성공 전까지 외부 ID 미반환busy/panic 정책 적용close_session()
05*sess_id = s->id·tee_ta_put_session()성공 ID 반환; open이 잡은 초기 ref 해제세션이 context 참조 유지close까지 client 목록에 남음
06정상 close entry → destroy/unlinkunlink=true, ref_count == 1 대기, 목록 제거세션 정리 후 context ref 감소·조건부 destroypanic/ctx 없음은 close entry 생략

close가 기다리는 ref_count == 1은 close caller가 가진 참조 하나가 남은 상태다. “0까지 기다린 뒤 CloseSession”이 아니다.

목록 삽입과 close entry의 앞뒤

그림 3은 세션 초기화, 그림 4는 정상 context의 close 경로다. 실패·panic 분기는 그림 아래에 분리했다.

그림 3. context 탐색 전에 session이 목록에 들어간다

tee_ta_init_session()의 생성·연결·탐색 순서.

01session calloc()
02condvar·refcount 초기화
03session ID 생성
04open_sessions 삽입
05기존 context 탐색
06SP·pseudo·user TA 시도
그림 4. 정상 close entry 뒤에 unlink와 참조 대기

close_session() → destroy_session() → tee_ta_unlink_session().

01exclusive session ref 획득
02client 검사·context busy
03TA enter_close_session()
04destroy_session()
05unlink=true·ref 대기
06목록 제거·session free
07context ref 감소·조건부 destroy

원본 코드

아래 코드는 OP-TEE OS 4.10.0의 core/kernel/tee_ta_manager.c에서 682-770줄을 그대로 가져온 것이다. 설명을 위해 실제 코드를 가짜 의사 코드로 바꾸지 않았다.

commit753afbbee1682f5d16fd30e87b31058a4fd4f4b8anchor · L706TEE_Result tee_ta_open_session(TEE_ErrorOrigin *err
682		keep_alive = ctx->flags & TA_FLAG_INSTANCE_KEEP_ALIVE;
683	if (keep_alive)
684		keep_crashed = ctx->flags & TA_FLAG_INSTANCE_KEEP_CRASHED;
685
686	/*
687	 * Keep panicked TAs with SINGLE_INSTANCE, KEEP_ALIVE, and KEEP_CRASHED
688	 * flags in the context list to maintain their panicked status and
689	 * prevent respawning.
690	 */
691	if (!keep_crashed) {
692		mutex_lock(&tee_ta_mutex);
693		was_releasing = ctx->is_releasing;
694		ctx->is_releasing = true;
695		if (!was_releasing) {
696			DMSG("Releasing panicked TA ctx");
697			TAILQ_REMOVE(&tee_ctxes, ctx, link);
698		}
699		mutex_unlock(&tee_ta_mutex);
700
701		if (!was_releasing)
702			ctx->ts_ctx.ops->release_state(&ctx->ts_ctx);
703	}
704}
705
706TEE_Result tee_ta_open_session(TEE_ErrorOrigin *err, uint32_t *sess_id,
707			       struct tee_ta_session_head *open_sessions,
708			       const TEE_UUID *uuid,
709			       const TEE_Identity *clnt_id,
710			       uint32_t cancel_req_to,
711			       struct tee_ta_param *param)
712{
713	TEE_Result res = TEE_SUCCESS;
714	struct tee_ta_session *s = NULL;
715	struct tee_ta_ctx *ctx = NULL;
716	struct ts_ctx *ts_ctx = NULL;
717	bool panicked = false;
718	bool was_busy = false;
719
720	res = tee_ta_init_session(err, open_sessions, uuid, &s);
721	if (res != TEE_SUCCESS) {
722		DMSG("init session failed 0x%x", res);
723		return res;
724	}
725
726	if (!check_params(s, param)) {
727		close_session(s, open_sessions);
728		return TEE_ERROR_BAD_PARAMETERS;
729	}
730
731	ts_ctx = s->ts_sess.ctx;
732	ctx = ts_to_ta_ctx(ts_ctx);
733
734	if (tee_ta_try_set_busy(ctx)) {
735		if (!ctx->panicked) {
736			/* Save identity of the owner of the session */
737			s->clnt_id = *clnt_id;
738			s->param = param;
739			set_invoke_timeout(s, cancel_req_to);
740			res = ts_ctx->ops->enter_open_session(&s->ts_sess);
741			s->param = NULL;
742		}
743
744		panicked = ctx->panicked;
745		if (panicked) {
746			maybe_release_ta_ctx(ctx);
747			res = TEE_ERROR_TARGET_DEAD;
748		} else {
749			if (IS_ENABLED(CFG_FTRACE_DUMP_EVERY_ENTRY))
750				dump_ftrace(s);
751		}
752
753		tee_ta_clear_busy(ctx);
754	} else {
755		/* Deadlock avoided */
756		res = TEE_ERROR_BUSY;
757		was_busy = true;
758	}
759
760	/*
761	 * Origin error equal to TEE_ORIGIN_TRUSTED_APP for "regular" error,
762	 * apart from panicking.
763	 */
764	if (panicked || was_busy)
765		*err = TEE_ORIGIN_TEE;
766	else
767		*err = s->err_origin;
768
769	if (res) {
770		close_session(s, open_sessions);

발췌 앞뒤의 호출 순서

원본 발췌는 tee_ta_open_session() 주변을 보여 준다. 세션이 먼저 할당·삽입되는 근거는 tee_ta_init_session()이다. 종료 순서는 close_session()과 tee_ta_unlink_session()·destroy_session()을 함께 대조한다.

발췌 안의 *sess_id 기록은 외부 성공 결과이며, 더 이른 TAILQ_INSERT_TAIL()과 구분한다.

함께 읽어야 하는 원본 코드

첫 코드 조각만으로 동작이 완성되지 않는 경우 호출 매크로, 객체 정의와 실제 실행 목록을 같은 페이지에 묶었다. 각 조각은 같은 기준 commit에서 가져왔다.

01. 열린 session에서 TA command를 호출

core/kernel/tee_ta_manager.c 768-858줄이다.

filecore/kernel/tee_ta_manager.canchor · L780TEE_Result tee_ta_invoke_command
768
769	if (res) {
770		close_session(s, open_sessions);
771		EMSG("Failed for TA %pUl. Return error %#"PRIx32, uuid, res);
772	} else {
773		*sess_id = s->id;
774		tee_ta_put_session(s);
775	}
776
777	return res;
778}
779
780TEE_Result tee_ta_invoke_command(TEE_ErrorOrigin *err,
781				 struct tee_ta_session *sess,
782				 const TEE_Identity *clnt_id,
783				 uint32_t cancel_req_to, uint32_t cmd,
784				 struct tee_ta_param *param)
785{
786	struct tee_ta_ctx *ta_ctx = NULL;
787	struct ts_ctx *ts_ctx = NULL;
788	TEE_Result res = TEE_SUCCESS;
789	bool panicked = false;
790
791	if (check_client(sess, clnt_id) != TEE_SUCCESS)
792		return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
793
794	if (!check_params(sess, param))
795		return TEE_ERROR_BAD_PARAMETERS;
796
797	ts_ctx = sess->ts_sess.ctx;
798	ta_ctx = ts_to_ta_ctx(ts_ctx);
799
800	tee_ta_set_busy(ta_ctx);
801
802	if (!ta_ctx->panicked) {
803		sess->param = param;
804		set_invoke_timeout(sess, cancel_req_to);
805		res = ts_ctx->ops->enter_invoke_cmd(&sess->ts_sess, cmd);
806		sess->param = NULL;
807	}
808
809	panicked = ta_ctx->panicked;
810	if (panicked) {
811		maybe_release_ta_ctx(ta_ctx);
812		res = TEE_ERROR_TARGET_DEAD;
813	} else {
814		if (IS_ENABLED(CFG_FTRACE_DUMP_EVERY_ENTRY))
815			dump_ftrace(sess);
816	}
817
818	tee_ta_clear_busy(ta_ctx);
819
820	/*
821	 * Origin error equal to TEE_ORIGIN_TRUSTED_APP for "regular" error,
822	 * apart from panicking.
823	 */
824	if (panicked)
825		*err = TEE_ORIGIN_TEE;
826	else
827		*err = sess->err_origin;
828
829	/* Short buffer is not an effective error case */
830	if (res != TEE_SUCCESS && res != TEE_ERROR_SHORT_BUFFER)
831		DMSG("Error: %x of %d", res, *err);
832
833	return res;
834}
835
836#if defined(CFG_TA_STATS)
837static TEE_Result dump_ta_memstats(struct tee_ta_session *s,
838				   struct tee_ta_param *param)
839{
840	TEE_Result res = TEE_SUCCESS;
841	struct tee_ta_ctx *ctx = NULL;
842	struct ts_ctx *ts_ctx = NULL;
843	bool panicked = false;
844
845	ts_ctx = s->ts_sess.ctx;
846	if (!ts_ctx)
847		return TEE_ERROR_ITEM_NOT_FOUND;
848
849	ctx = ts_to_ta_ctx(ts_ctx);
850
851	if (ctx->is_initializing)
852		return TEE_ERROR_BAD_STATE;
853
854	if (tee_ta_try_set_busy(ctx)) {
855		if (!ctx->panicked) {
856			s->param = param;
857			set_invoke_timeout(s, TEE_TIMEOUT_INFINITE);
858			res = ts_ctx->ops->dump_mem_stats(&s->ts_sess);

02. TA close entry를 실행한 뒤 세션을 정리하는 함수

core/kernel/tee_ta_manager.c 495-585줄이다.

filecore/kernel/tee_ta_manager.canchor · L507TEE_Result tee_ta_close_session(uint32_t id
495			ctx->is_releasing = true;
496		}
497		mutex_unlock(&tee_ta_mutex);
498
499		destroy_context(ctx);
500	} else
501		mutex_unlock(&tee_ta_mutex);
502}
503
504/*
505 * Close a Trusted Application and free available resources
506 */
507TEE_Result tee_ta_close_session(uint32_t id,
508				struct tee_ta_session_head *open_sessions,
509				const TEE_Identity *clnt_id)
510{
511	struct tee_ta_session *sess = NULL;
512
513	DMSG("id %"PRIu32, id);
514
515	sess = tee_ta_get_session(id, true, open_sessions);
516
517	if (!sess) {
518		EMSG("session id %"PRIu32" to be removed is not found", id);
519		return TEE_ERROR_ITEM_NOT_FOUND;
520	}
521
522	if (check_client(sess, clnt_id) != TEE_SUCCESS) {
523		tee_ta_put_session(sess);
524		return TEE_ERROR_BAD_PARAMETERS; /* intentional generic error */
525	}
526
527	DMSG("Destroy session");
528	close_session(sess, open_sessions);
529
530	return TEE_SUCCESS;
531}
532
533static TEE_Result tee_ta_init_session_with_context(struct tee_ta_session *s,
534						   const TEE_UUID *uuid)
535{
536	struct tee_ta_ctx *ctx = NULL;
537
538	while (true) {
539		ctx = tee_ta_context_find(uuid);
540		if (!ctx)
541			return TEE_ERROR_ITEM_NOT_FOUND;
542
543		if (!ctx->is_initializing)
544			break;
545		/*
546		 * Context is still initializing, wait here until it's
547		 * fully initialized. Note that we're searching for the
548		 * context again since it may have been removed while we
549		 * where sleeping.
550		 */
551		condvar_wait(&tee_ta_init_cv, &tee_ta_mutex);
552	}
553
554	/*
555	 * If the trusted service is not a single instance service (e.g. is
556	 * a multi-instance TA) it should be loaded as a new instance instead
557	 * of doing anything with this instance. So tell the caller that we
558	 * didn't find the TA it the caller will load a new instance.
559	 */
560	if ((ctx->flags & TA_FLAG_SINGLE_INSTANCE) == 0)
561		return TEE_ERROR_ITEM_NOT_FOUND;
562
563	/*
564	 * The trusted service is single instance, if it isn't multi session we
565	 * can't create another session unless its reference is zero
566	 */
567	if (!(ctx->flags & TA_FLAG_MULTI_SESSION) && ctx->ref_count)
568		return TEE_ERROR_BUSY;
569
570	DMSG("Re-open trusted service %pUl", (void *)&ctx->ts_ctx.uuid);
571
572	ctx->ref_count++;
573	s->ts_sess.ctx = &ctx->ts_ctx;
574	s->ts_sess.handle_scall = s->ts_sess.ctx->ops->handle_scall;
575	return TEE_SUCCESS;
576}
577
578static uint32_t new_session_id(struct tee_ta_session_head *open_sessions)
579{
580	struct tee_ta_session *last = NULL;
581	uint32_t saved = 0;
582	uint32_t id = 1;
583
584	last = TAILQ_LAST(open_sessions, tee_ta_session_head);
585	if (last) {

고정 manager의 open과 close

01

세션을 먼저 만든다

tee_ta_init_session()은 calloc() 뒤 cancellation flag, condvar, lock_thread, ref_count = 1을 초기화한다. tee_ta_mutex 아래 새 ID를 고른 뒤 open_sessions에 삽입한다.

02

context 후보를 세션에 연결한다

목록 삽입 다음에 기존 context를 시도하고, 없으면 secure partition, pseudo TA, user TA 순서로 탐색·초기화한다. 다음 후보는 TEE_ERROR_ITEM_NOT_FOUND일 때만 시도한다. 기존 single-instance context가 multi-session을 허용하지 않고 참조가 남아 있으면 TEE_ERROR_BUSY를 반환한다.

03

초기화 실패는 목록에서 되돌린다

ID 생성 실패는 아직 삽입되지 않은 세션을 바로 해제한다. 그 뒤 context 경로 실패는 TAILQ_REMOVE(open_sessions, s, link)와 free(s)로 정리한다. 부분 context 정리는 해당 loader의 경로도 확인한다.

04

TA open entry 성공 뒤 ID를 돌려준다

tee_ta_open_session()은 parameter를 검사하고 context busy 상태에서 enter_open_session()을 호출한다. 실패 시 close_session()을 거치고, 성공 시 *sess_id = s->id를 기록한 뒤 tee_ta_put_session()으로 open caller의 초기 ref를 해제한다.

05

정상 close entry가 먼저다

tee_ta_close_session()은 exclusive session ref와 client 검사를 거친다. 정상 context라면 tee_ta_set_busy(), enter_close_session(), destroy_session(), tee_ta_clear_busy() 순서다. 다만 TA_FLAG_CONCURRENT가 있으면 busy 설정·해제 함수는 그 상태를 변경하지 않고 반환한다. context가 없거나 panicked이면 close entry 없이 destroy로 간다.

unlink가 차단하는 새 접근과 마지막 context

01

목록 연결과 성공 공개는 다르다

삽입은 tee_ta_mutex를 잡은 초기화 함수 안에서 context 탐색 전에 일어난다. 그러나 caller에게 돌려주는 성공 ID는 TA open entry가 성공한 뒤에야 기록된다. 실패한 임시 세션을 성공한 client handle로 세지 않는다.

02

unlink는 다른 참조가 빠진 뒤 제거한다

tee_ta_unlink_session()은 unlink=true와 condvar broadcast로 새 get을 막고, ref_count == 1을 기다린 뒤 목록에서 제거한다. 남은 하나는 close caller가 가진 참조다. 이후 세션 객체를 해제한다.

03

context는 별도 참조·flag로 정리한다

세션 destroy 뒤 ctx->ref_count를 감소시킨다. 0이면 panicked, single-instance keep-alive, keep-crashed flag 조합에 따라 context 목록 제거와 destroy_context() 여부를 결정한다. 세션 제거와 context 해제를 같은 사건으로 묶지 않는다.

레지스터에서 오류 판정까지 상세 분석

TA context와 session은 같은 객체가 아니다. tee_ta_ctx는 TA binary, address space와 global instance state를 나타내고 여러 session이 공유할 수 있으며, tee_ta_session은 한 client의 open 관계, cancellation과 invoke state를 보유한다.

single-instance, multi-session, keep-alive flag에 따라 context 재사용과 destruction 시점이 달라진다. session list lock, context busy state, ref_count와 condvar가 어떤 순서로 사용되는지 보지 않으면 close와 concurrent invoke 사이 use-after-free를 놓치게 된다.

그림 5. 세션 요청에서 확인할 다섯 가지 입력 조건
01TA UUID

load 가능한 signed TA 또는 등록된 pseudo TA를 정확히 지칭해야 한다.

02client identity

login method와 client UUID가 policy대로 정규화돼야 한다.

03open_sessions list

해당 client가 소유한 session namespace여야 한다.

04TA flags

single-instance, multi-session, keep-alive 조합이 유효해야 한다.

05tee_ta_param

open/invoke 동안 secure object와 mobj ref를 유지해야 한다.

이 다섯 항목은 함수 호출 순서가 아니라 서로 다른 입력 조건이다. session 목록, client identity, TA flag, parameter의 유효성을 각각 확인한다.

진입 레지스터와 메모리 계약

함수 첫 줄에 도달했을 때 이미 참이라고 가정하는 값과, 그 값이 틀렸을 때 영향을 받는 범위를 함께 적었다.

#입력 상태생산자정상 조건확인 이유
01TA UUIDopen-session meta parameterload 가능한 signed TA 또는 등록된 pseudo TA를 정확히 지칭해야 한다.context lookup/creation key다.
02client identityNormal World/session metadatalogin method와 client UUID가 policy대로 정규화돼야 한다.TA access control과 session identity를 결정한다.
03open_sessions listcaller/client context해당 client가 소유한 session namespace여야 한다.session ID lookup과 close 범위를 한정한다.
04TA flagssigned header/pseudo TA descriptorsingle-instance, multi-session, keep-alive 조합이 유효해야 한다.context 공유와 lifetime policy를 정한다.
05tee_ta_parammessage conversionopen/invoke 동안 secure object와 mobj ref를 유지해야 한다.TA entry parameter와 cleanup의 입력이다.

핵심 구조체 필드의 생산자, 소비자와 수명

구조체 이름만 나열하지 않고 어떤 코드가 값을 쓰고, 어느 코드가 처음 읽으며, 언제까지 주소와 내용이 유지되어야 하는지 구분했다.

#객체 또는 필드생산자소비자수명과 불변 조건
01tee_ta_ctxTA load/createsession open/invokeref_count와 flags에 따라 마지막 session 뒤 destroy 또는 keep-alive된다.
02user_ta_ctx/ts_ctxuser TA loaderMMU/EL0 entryTA address space, code/data, loader state를 소유한다.
03tee_ta_sessionopen sessioninvoke/close/cancelclient open_sessions list에 연결되고 close가 남은 ref 1개를 확인한 뒤 해제한다.
04session ref_count/refc_cvget/put sessionclose와 concurrent invokeunlink 뒤 다른 ref가 빠져 close caller의 1개만 남을 때까지 기다린다.
05tee_ctxes global listcontext creationUUID lookup/reusecontext lock 아래 공개·제거되며 half-initialized object를 노출하면 안 된다.
06TA private session contextTA OpenSession entryInvoke/CloseSessionTA가 반환한 pointer를 session이 소유하고 close까지 유지한다.

함수 내부 실행 순서

소스의 큰 분기와 side effect를 실행 순서대로 다시 펼쳤다. breakpoint는 이 목록의 경계에 두고, 다음 번호로 넘어갈 때 새로 유효해진 객체를 기록한다.

  1. 01

    open request의 UUID, client identity와 parameter가 tee_ta_open_session()에 들어온다.

  2. 02

    tee_ta_init_session()이 새 tee_ta_session을 calloc()하고 condvar·초기 refcount 1·현재 lock_thread를 설정한다.

  3. 03

    tee_ta_mutex 아래 ID를 고르고 TAILQ_INSERT_TAIL(open_sessions, s, link)로 세션을 먼저 연결한다.

  4. 04

    같은 세션에 기존 context를 연결하거나 secure partition → pseudo TA → user TA 순서로 초기화한다. 실패하면 삽입된 세션을 제거·해제한다.

  5. 05

    check_params()와 busy 규칙을 거쳐 TA enter_open_session()을 호출한다. 성공 후에야 *sess_id를 기록하고 초기 ref를 내려놓는다.

  6. 06

    invoke는 client와 parameter를 확인하고 TA context의 busy 규칙 아래 enter_invoke_cmd()를 호출한다.

  7. 07

    close는 exclusive ref와 client identity를 확인한다. 정상 context면 TA enter_close_session()을 먼저 호출한다.

  8. 08

    이어 destroy_session()이 unlink=true로 새 접근을 막고 다른 ref가 빠져 ref_count == 1이 되길 기다린 후 목록에서 제거·free한다.

  9. 09

    그 뒤 context ref를 줄이고 single-instance·keep-alive·panic flag에 따라 context를 유지하거나 파괴한다.

빌드 설정이 바꾸는 실제 코드 경로

동일한 함수 이름이라도 아래 설정에 따라 포함되는 source, 구조체 크기, 인자 의미와 failure path가 달라진다.

#설정바뀌는 동작확인 방법
01CFG_WITH_USER_TAsigned user TA load와 EL0 context를 지원한다.pseudo TA와 user TA 생성/destruction 경로를 구분한다.
02CFG_REE_FS_TA/CFG_EARLY_TATA binary source와 load 시점이 달라진다.동일 UUID source 우선순위와 signature 검증을 확인한다.
03TA_FLAG_SINGLE_INSTANCE/MULTI_SESSION/KEEP_ALIVEcontext 공유와 session 동시성 정책을 바꾼다.TA header flag와 manager branch를 기록한다.
04CFG_TA_ASLRuser TA mapping base가 session/context 생성 때 달라진다.panic 주소 decode에 TA load base를 남긴다.

증상에서 최초 불일치 지점까지 추적하기

마지막 panic 메시지가 아니라 어디에서 멈추고 무엇을 읽어 어떤 결론을 내릴지 정리했다. 정상값과 실패값은 같은 build와 같은 위치에서 비교한다.

#관찰 증상중단 위치기록할 값판정
01close와 invoke 동시 실행에서 crashtee_ta_get/put_session과 closesession refcount, list membership, exclusive flagsession을 너무 일찍 unlink/free하는지 확인한다.
02single-instance TA가 두 context로 loadglobal context lookupUUID, flags, tee_ctxes locklookup/insert race 또는 flag parse 문제를 찾는다.
03마지막 close 뒤 secure memory 누수context destroysession count, ctx ref_count, mapping/fobjkeep-alive 정책과 cleanup 누락을 구분한다.
04다른 client가 session ID를 사용session lookupopen_sessions owner, client/guest identitysession ID namespace와 list 선택 오류를 판정한다.

session과 context의 별도 수명

대상생성·연결성공 뒤 수명정리 조건
tee_ta_sessioncontext 탐색 전 calloc()·client 목록 삽입성공한 open 뒤 목록에 남음close의 unlink·ref 대기·free
session ID삽입 전 new_session_id()TA open 성공 뒤 *sess_id 반환실패하면 외부 성공 ID 없음
ts_sess.ctx기존 context 재사용 또는 TA 초기화 중 연결session이 TA context를 참조close 뒤 context ref 감소
ref_count·unlink초기 ref 1, get/put으로 변동invoke/close의 동시 접근 관리unlink 뒤 close ref 1만 남으면 제거
tee_ta_ctx재사용 또는 새 TA loadflag에 따라 여러 세션 공유 가능마지막 ref와 keep-alive/panic 정책

삽입 전후와 close 분기

지점고정 코드의 동작관찰할 상태
할당 또는 ID 실패목록 삽입 없이 반환·freeclient 목록에 새 ID 없음
context/SP/PTA/user TA 초기화 실패이미 삽입된 세션을 TAILQ_REMOVE()·free임시 session 누수 없음
parameter 또는 TA open entry 실패close_session()으로 정리외부 *sess_id 미반환
context 없음·panicked 상태의 closeTA close entry 없이 destroy_session()unlink/ref 대기는 계속 수행
정상 close와 다른 활성 참조TA close entry 후 unlink=true, ref_count == 1 대기목록 제거 전 새 get 거부

빌드와 런타임에서 대조할 자료

소스 순서와 실제 빌드의 manager 동작을 동일 UUID·동일 client 조건에서 비교한다.

목적읽기 전용 자료·계측판정 기준
고정 소스tee_ta_init_session(), close_session(), tee_ta_unlink_session()삽입과 context 탐색, close entry와 unlink의 순서
동일 UUID 동시 open세션 ID, open_sessions 목록, context flags·refcountsingle-instance/multi-session 분기와 실패 unwind
close와 invoke 경합unlink, ref_count, lock_thread, condvar새 get 차단과 남은 close ref 1 확인
마지막 contextctx->ref_count, keep-alive·panicked flags세션 free와 context destroy를 분리해 확인

복구 가능한 시험 환경에서 재현

  1. 01
    초기화 실패 주입

    ID 실패와 context 탐색·load 실패를 나눠 목록 삽입 여부와 TAILQ_REMOVE() 실행을 기록한다.

  2. 02
    open entry 실패

    *sess_id 미반환과 close_session() 정리 순서를 같은 세션 주소로 추적한다.

  3. 03
    invoke와 close 경합

    exclusive close ref, TA close entry, unlink=true, ref_count == 1, 목록 제거 시점을 차례로 기록한다.

원문과 다음 글