OP-TEE OS · source analysis

optee_msg_arg command dispatch

OP-TEE 4.10.0의 standard command switch를 읽고, session·shared memory·notification 분기와 두 결과 채널을 구분합니다.

OP-TEE OS 4.10.0의 동작 분석 기준입니다. 제품 보안 유지 보수와 플랫폼 설정은 별도로 확인하세요.

Series
07 / 12
Baseline
4.10.0
Commit
753afbbee168
Source
core/tee/entry_std.c:665-753 (발췌 범위)

명령마다 매개변수를 처리하는 방법이 왜 다른가?

__tee_entry_std(arg, num_params)는 먼저 foreign interrupt를 허용한 뒤 arg->cmd를 분기한다. OPEN/INVOKE는 copy_in_params()를 사용하지만 CLOSE/CANCEL, notification, SHM 등록은 같은 변환 경로를 거치지 않는다. REGISTER_SHM은 CFG_CORE_DYN_SHM && !CFG_CORE_FFA일 때만 switch에 존재한다.

GET_PROTMEM_CONFIG도 copy_in_params()를 호출하지만 TA를 실행하는 명령은 아니다. 이 명령은 보호 메모리 설정을 조회한다. 따라서 매개변수 변환과 TA 호출을 같은 단계로 취급하면 안 된다.

결과를 확인할 곳도 두 군데다. 명령 처리 함수는 보통 공유 메시지의 arg->ret에 작업 결과를 쓴다. 세션 명령은 ret_origin도 기록하지만 모든 명령이 이 필드를 쓰는 것은 아니다. 반면 __tee_entry_std()의 반환값은 지원하지 않는 명령인지 등을 나타낸다. 이 함수가 TEE_SUCCESS를 반환했다고 해서 TA 작업까지 성공한 것은 아니다.

dispatcher 689–751 · session handlers 364–459 · SHM handlers 486–525.

하나의 switch에서 명령별 처리로 나뉜다

그림 1. __tee_entry_std()는 직선형 pipeline이 아니라 cmd별 분기점이다
tee_entry_std(arg, num_params) → foreign interrupt 허용 → arg->cmd switchplatform이 weak wrapper를 override해도 보통 __tee_entry_std()로 돌아온다.

Session 명령

OPEN / INVOKEmeta 또는 TA params 검사·변환, TA manager 호출, output/cleanup.
CLOSE / CANCEL0 params 요구·session 처리. copy_in_params() 없음.

설정에 따라 포함되는 명령

REGISTER / UNREGISTER_SHMCFG_CORE_DYN_SHM && !CFG_CORE_FFA에서만 포함.
비동기 알림 / 보호 메모리ASYNC_NOTIF 또는 DYN_PROTMEM 설정에 따라 처리한다. GET_PROTMEM_CONFIG는 매개변수도 변환한다.

그 외 명령과 disabled notification은 err로 가서 dispatcher의 TEE_ERROR_NOT_IMPLEMENTED를 반환한다. 호출에 참여하는 객체도 분기마다 다르다.

entry_std.c 679–751.

Session 명령 네 개의 실제 차이

그림 2. OPEN/INVOKE와 CLOSE/CANCEL의 parameter·session 경계

OPEN_SESSION

앞 2개 META|VALUE_INPUTUUID와 클라이언트 식별 정보. 검사 실패 시 변환·출력 복사를 건너뛴다.
나머지만 copy_in_params최대 4개 TA 매개변수. 변환 실패 시 참조 정리로 이동한다.
tee_ta_open_session호출 뒤 출력 복사와 참조 정리. 마지막에 session/ret/origin을 기록한다.

INVOKE_COMMAND

전체 매개변수 변환META bit는 허용하지 않는다.
세션 조회 → TA 호출변환 또는 세션 조회 실패 시 TA 호출·출력 복사를 건너뛴다.
출력 복사 → 참조 정리 → ret/originTA 호출 뒤 세션 참조를 놓고, 출력 값 또는 memref 크기를 복사한다.

CLOSE / CANCEL

num_params == 0둘 다 parameter conversion이 없다.
session close 또는 cancelCANCEL은 session get/put, CLOSE는 TA close.
ret/origin 기록OPEN/INVOKE의 copy-out 경로를 밟지 않는다.

OPEN/INVOKE/CLOSE 327–459 · CANCEL 461–484.

명령별로 필요한 상태와 반환 위치

OP-TEE standard command 분기
명령선행 검사·변환핵심 작업결과 기록
OPEN_SESSION2 meta params 검사; 나머지 ≤4개 변환TA session 열기arg->session/ret/ret_origin
INVOKE_COMMAND모든 params ≤4개 변환; session lookupTA command 실행arg->ret/ret_origin
CLOSE_SESSION / CANCELnum_params==0close / cancelarg->ret/ret_origin
REGISTER / UNREGISTER_SHMDYN_SHM && !FFA; 각각 전용 param 계약registered mobj 생성 / cookie로 해제주로 arg->ret
GET_PROTMEM_CONFIGDYN_PROTMEM; 매개변수 2개 변환 및 타입 검사보호 메모리 설정 조회; TA 호출 아님arg->ret/ret_origin, 조회 결과
DO_BOTTOM_HALF / STOP_ASYNC_NOTIFASYNC_NOTIF enablednotification 전달switch 반환; disabled면 NOT_IMPLEMENTED
기타 / 비활성 명령case 없음Unknown cmd 로그dispatcher TEE_ERROR_NOT_IMPLEMENTED

메시지의 매개변수 배치와 두 종류의 결과

그림 3. OPEN의 meta 2개와 일반 TA parameter는 복사 경계가 다르다
arg.params[0], [1]정확히 META|VALUE_INPUT: UUID, login/client identity
arg.params[2..]copy_in_params: META 거부, 최대 4개
tee_ta_paramvalue 복사 또는 mobj 획득, TA session 호출
허용된 output → cleanupVALUE a/b 또는 memref size. 참조 정리는 속성 값과 빌드 설정에 따른다.
copy_in_params()의 빌드별 wire type
wire type설정secure 표현·경계
VALUE / NONE공통value a/b 복사 또는 NONE; META bit 거부
TMEM!CFG_CORE_FFAnoncontig/기본 SHM/SDP/protected memory에 따른 mobj
RMEMCFG_CORE_DYN_SHM && !CFG_CORE_FFAcookie lookup, offset+size bounds 검사
FMEMCFG_CORE_FFAFF-A global ID/cookie, offset+size bounds 검사

FMEM 타입 값은 RMEM과 같다. 따라서 FMEM의 출력 크기도 RMEM case에서 복사하며, CFG_CORE_DYN_SHM으로 포함된 RMEM 정리 case는 FMEM 타입에도 해당한다. 추가 속성 비트와 빌드 설정을 확인해야 하며, REGISTER_SHM의 등록 객체 수명과 혼동하지 않는다. copy/cleanup 184–318.

그림 4. handler의 arg->ret와 dispatcher TEE_Result는 별도 결과다

알려진 명령

case → handlerTA 실패나 BAD_PARAMETERS도 handler가 arg->ret에 기록 가능.
dispatcher resswitch 뒤 기본값 TEE_SUCCESS 반환.

알 수 없거나 비활성

default/errUnknown cmd 로그, res=TEE_ERROR_NOT_IMPLEMENTED.
함수 반환이 분기에서 arg->ret 기록을 가정하지 않는다.

SHM handler는 arg->ret_origin을 항상 쓰지 않는다. Normal World에서 결과를 해석할 때 함수 반환과 message header 필드를 혼동하지 않는다.

dispatcher 689–751 · SHM 488–524.

원본 코드

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

commit753afbbee1682f5d16fd30e87b31058a4fd4f4b8anchor · L689TEE_Result __tee_entry_std(struct optee_msg_arg *arg
665
666out_dec_map:
667	mobj_dec_map(param.u[1].mem.mobj);
668out_cleanup:
669	cleanup_shm_refs(saved_attr, &param, num_params);
670out:
671	arg->ret = res;
672}
673
674void nsec_sessions_list_head(struct tee_ta_session_head **open_sessions)
675{
676	*open_sessions = &tee_open_sessions;
677}
678
679/* Note: this function is weak to let platforms add special handling */
680TEE_Result __weak tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params)
681{
682	return __tee_entry_std(arg, num_params);
683}
684
685/*
686 * If tee_entry_std() is overridden, it's still supposed to call this
687 * function.
688 */
689TEE_Result __tee_entry_std(struct optee_msg_arg *arg, uint32_t num_params)
690{
691	TEE_Result res = TEE_SUCCESS;
692
693	/* Enable foreign interrupts for STD calls */
694	thread_set_foreign_intr(true);
695	switch (arg->cmd) {
696	case OPTEE_MSG_CMD_OPEN_SESSION:
697		entry_open_session(arg, num_params);
698		break;
699	case OPTEE_MSG_CMD_CLOSE_SESSION:
700		entry_close_session(arg, num_params);
701		break;
702	case OPTEE_MSG_CMD_INVOKE_COMMAND:
703		entry_invoke_command(arg, num_params);
704		break;
705	case OPTEE_MSG_CMD_CANCEL:
706		entry_cancel(arg, num_params);
707		break;
708#if defined(CFG_CORE_DYN_SHM) && !defined(CFG_CORE_FFA)
709	case OPTEE_MSG_CMD_REGISTER_SHM:
710		register_shm(arg, num_params);
711		break;
712	case OPTEE_MSG_CMD_UNREGISTER_SHM:
713		unregister_shm(arg, num_params);
714		break;
715#endif
716	case OPTEE_MSG_CMD_DO_BOTTOM_HALF:
717		if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF))
718			notif_deliver_event(NOTIF_EVENT_DO_BOTTOM_HALF);
719		else
720			goto err;
721		break;
722	case OPTEE_MSG_CMD_STOP_ASYNC_NOTIF:
723		if (IS_ENABLED(CFG_CORE_ASYNC_NOTIF))
724			notif_deliver_event(NOTIF_EVENT_STOPPED);
725		else
726			goto err;
727		break;
728#ifdef CFG_CORE_DYN_PROTMEM
729	case OPTEE_MSG_CMD_GET_PROTMEM_CONFIG:
730		get_protmem_config(arg, num_params);
731		break;
732#ifdef CFG_CORE_FFA
733	case OPTEE_MSG_CMD_ASSIGN_PROTMEM:
734		assign_protmem(arg, num_params);
735		break;
736#else
737	case OPTEE_MSG_CMD_LEND_PROTMEM:
738		lend_protmem(arg, num_params);
739		break;
740	case OPTEE_MSG_CMD_RECLAIM_PROTMEM:
741		reclaim_protmem(arg, num_params);
742		break;
743#endif /*!CFG_CORE_FFA*/
744#endif /*CFG_CORE_DYN_PROTMEM*/
745	default:
746err:
747		EMSG("Unknown cmd 0x%x", arg->cmd);
748		res = TEE_ERROR_NOT_IMPLEMENTED;
749	}
750
751	return res;
752}
753

발췌 범위와 읽기 기준

위 메인 발췌는 entry_std.c:665–753이며 __tee_entry_std() 본문은 689행부터다. 앞부분은 다른 함수의 끝과 weak wrapper를 포함한다. 관련 원본 두 조각은 OPEN handler 354–434와 copy_in_params() 주변 174–276이다.

원본 발췌만으로 보이지 않는 CLOSE/CANCEL, REGISTER_SHM, copy-out, cleanup 전체를 264–318, 410–525와 함께 읽는다. 모든 case가 TA manager를 호출하거나 동일한 결과 필드를 기록한다는 가정은 두지 않는다.

함께 읽어야 하는 원본 코드

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

01. OPEN_SESSION parameter와 TA session 생성

core/tee/entry_std.c 354-434줄이다.

filecore/tee/entry_std.canchor · L364static void entry_open_session
354				     (void *)&params[1].u.value);
355		break;
356	default:
357		return TEE_ERROR_BAD_PARAMETERS;
358	}
359
360	*num_meta = 2;
361	return TEE_SUCCESS;
362}
363
364static void entry_open_session(struct optee_msg_arg *arg, uint32_t num_params)
365{
366	TEE_Result res = TEE_ERROR_GENERIC;
367	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
368	uint32_t sess_id = 0;
369	TEE_Identity clnt_id = { };
370	TEE_UUID uuid = { };
371	struct tee_ta_param param = { };
372	size_t num_meta = 0;
373	uint64_t saved_attr[TEE_NUM_PARAMS] = { 0 };
374
375	res = get_open_session_meta(num_params, arg->params, &num_meta, &uuid,
376				    &clnt_id);
377	if (res != TEE_SUCCESS)
378		goto out;
379
380	res = copy_in_params(arg->params + num_meta, num_params - num_meta,
381			     &param, saved_attr);
382	if (res != TEE_SUCCESS)
383		goto cleanup_shm_refs;
384
385	res = tee_ta_open_session(&err_orig, &sess_id, &tee_open_sessions,
386				  &uuid, &clnt_id, TEE_TIMEOUT_INFINITE,
387				  &param);
388	if (res)
389		sess_id = 0;
390	copy_out_param(&param, num_params - num_meta, arg->params + num_meta,
391		       saved_attr);
392
393	/*
394	 * The occurrence of open/close session command is usually
395	 * un-predictable, using this property to increase randomness
396	 * of prng
397	 */
398	plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
399				     &session_pnum);
400
401cleanup_shm_refs:
402	cleanup_shm_refs(saved_attr, &param, num_params - num_meta);
403
404out:
405	arg->session = sess_id;
406	arg->ret = res;
407	arg->ret_origin = err_orig;
408}
409
410static void entry_close_session(struct optee_msg_arg *arg, uint32_t num_params)
411{
412	TEE_Result res = TEE_SUCCESS;
413
414	if (num_params) {
415		res = TEE_ERROR_BAD_PARAMETERS;
416		goto out;
417	}
418
419	plat_prng_add_jitter_entropy(CRYPTO_RNG_SRC_JITTER_SESSION,
420				     &session_pnum);
421
422	res = tee_ta_close_session(arg->session, &tee_open_sessions,
423				   NSAPP_IDENTITY);
424out:
425	arg->ret = res;
426	arg->ret_origin = TEE_ORIGIN_TEE;
427}
428
429static void entry_invoke_command(struct optee_msg_arg *arg, uint32_t num_params)
430{
431	TEE_Result res;
432	TEE_ErrorOrigin err_orig = TEE_ORIGIN_TEE;
433	struct tee_ta_session *s;
434	struct tee_ta_param param = { 0 };

02. wire parameter를 secure tee_ta_param으로 복사

core/tee/entry_std.c 174-276줄이다.

filecore/tee/entry_std.canchor · L184static TEE_Result copy_in_params
174	 */
175	if (ADD_OVERFLOW(mem->offs, mem->size, &req_size) ||
176	    mem->mobj->size < req_size)
177		return TEE_ERROR_SECURITY;
178
179	return TEE_SUCCESS;
180}
181#endif /*CFG_CORE_DYN_SHM*/
182#endif /*!CFG_CORE_FFA*/
183
184static TEE_Result copy_in_params(const struct optee_msg_param *params,
185				 uint32_t num_params,
186				 struct tee_ta_param *ta_param,
187				 uint64_t *saved_attr)
188{
189	TEE_Result res;
190	size_t n;
191	uint8_t pt[TEE_NUM_PARAMS] = { 0 };
192
193	if (num_params > TEE_NUM_PARAMS)
194		return TEE_ERROR_BAD_PARAMETERS;
195
196	memset(ta_param, 0, sizeof(*ta_param));
197
198	for (n = 0; n < num_params; n++) {
199		uint32_t attr;
200
201		saved_attr[n] = READ_ONCE(params[n].attr);
202
203		if (saved_attr[n] & OPTEE_MSG_ATTR_META)
204			return TEE_ERROR_BAD_PARAMETERS;
205
206		attr = saved_attr[n] & OPTEE_MSG_ATTR_TYPE_MASK;
207		switch (attr) {
208		case OPTEE_MSG_ATTR_TYPE_NONE:
209			pt[n] = TEE_PARAM_TYPE_NONE;
210			break;
211		case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
212		case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
213		case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
214			pt[n] = TEE_PARAM_TYPE_VALUE_INPUT + attr -
215				OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
216			ta_param->u[n].val.a = READ_ONCE(params[n].u.value.a);
217			ta_param->u[n].val.b = READ_ONCE(params[n].u.value.b);
218			break;
219#ifdef CFG_CORE_FFA
220		case OPTEE_MSG_ATTR_TYPE_FMEM_INPUT:
221		case OPTEE_MSG_ATTR_TYPE_FMEM_OUTPUT:
222		case OPTEE_MSG_ATTR_TYPE_FMEM_INOUT:
223			res = set_fmem_param(&params[n].u.fmem,
224					     &ta_param->u[n].mem);
225			if (res)
226				return res;
227			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
228				OPTEE_MSG_ATTR_TYPE_FMEM_INPUT;
229			break;
230#else /*!CFG_CORE_FFA*/
231		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
232		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
233		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
234			res = set_tmem_param(&params[n].u.tmem, saved_attr[n],
235					     &ta_param->u[n].mem);
236			if (res)
237				return res;
238			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
239				OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
240			break;
241#ifdef CFG_CORE_DYN_SHM
242		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
243		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
244		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
245			res = set_rmem_param(&params[n].u.rmem,
246					     &ta_param->u[n].mem);
247			if (res)
248				return res;
249			pt[n] = TEE_PARAM_TYPE_MEMREF_INPUT + attr -
250				OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
251			break;
252#endif /*CFG_CORE_DYN_SHM*/
253#endif /*!CFG_CORE_FFA*/
254		default:
255			return TEE_ERROR_BAD_PARAMETERS;
256		}
257	}
258
259	ta_param->types = TEE_PARAM_TYPES(pt[0], pt[1], pt[2], pt[3]);
260
261	return TEE_SUCCESS;
262}
263
264static void cleanup_shm_refs(const uint64_t *saved_attr,
265			     struct tee_ta_param *param, uint32_t num_params)
266{
267	size_t n;
268
269	for (n = 0; n < MIN((unsigned int)TEE_NUM_PARAMS, num_params); n++) {
270		switch (saved_attr[n]) {
271		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
272		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
273		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
274#ifdef CFG_CORE_DYN_SHM
275		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
276		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:

분기마다 다른 검증·자원 경계

01

OPEN의 두 meta 값

get_open_session_meta()는 최소 두 개와 각 attr의 정확한 META|VALUE_INPUT 조합을 검사한다. UUID와 login/identity를 읽고 나서 남은 parameter만 copy_in_params()에 준다.

02

INVOKE의 session 참조

변환 성공 뒤 tee_ta_get_session()으로 현재 open-session 목록에서 ID를 찾는다. 실패 시 BAD_PARAMETERS, 성공 시 TA invoke 후 tee_ta_put_session()을 거쳐 output 복사와 mobj cleanup을 한다.

03

SHM 등록은 별도 ABI

REGISTER_SHM은 한 개의 TMEM_OUTPUT|NONCONTIG와 noncontiguous list를 검사한다. UNREGISTER_SHM은 cookie로 registered mobj를 해제한다. 두 case는 CFG_CORE_DYN_SHM && !CFG_CORE_FFA에서만 컴파일된다.

entry_std.c 327–525.

parameter 변환을 모든 명령에 대입하지 않기

01

최대 네 개의 TA parameter

copy_in_params()는 받은 num_params > TEE_NUM_PARAMS를 먼저 거절한다. OPEN에서는 두 meta를 제외한 개수이고 INVOKE에서는 전체 개수다. saved_attr를 저장하고 META bit를 거절한다.

02

빌드별 memory type

일반 경로는 TMEM 및 조건부 RMEM을, FF-A 경로는 FMEM을 처리한다. RMEM/FMEM은 cookie나 global ID로 mobj를 얻고 offset+size overflow 또는 객체 범위를 확인한다. TMEM의 noncontiguous와 기본 shared-memory 경로는 별도다.

03

FMEM도 타입 값과 구조체 배치를 함께 확인한다

OPTEE_MSG_ATTR_TYPE_FMEM_*는 RMEM 타입의 별칭이다. copy_out_param()의 RMEM 분기는 FMEM 출력에도 해당하며, 두 구조체의 size는 같은 위치에 있다. cleanup_shm_refs()의 RMEM case는 CFG_CORE_DYN_SHM일 때 포함되므로, 이 설정에서 FMEM 타입 값도 같은 case에 대응한다. 이름만 보고 FMEM이 별도 정리 경로를 거친다고 판단하면 안 된다.

입력 변환과 출력 복사는 타입 마스크를 쓰지만 참조 정리는 saved_attr[n] 전체 값으로 분기한다. 따라서 NONCONTIG처럼 추가 비트가 있는 속성까지 전부 같은 정리 case에 들어간다고 일반화하지 않는다. REGISTER_SHM의 등록 객체 수명도 TA 호출 중의 임시 참조와 구분한다.

optee_msg.h의 FMEM/RMEM 별칭과 size 배치 · 참조 정리와 출력 복사.

entry_std.c 101–318.

고정 소스의 결정 표

entry_std.c 4.10.0의 명령별 조건과 두 결과
경계조건결과·주의
copy_in_paramsTA params 4개 초과 또는 META bitTEE_ERROR_BAD_PARAMETERS; OPEN 앞 2 meta는 따로 처리
RMEM/FMEM lookupcookie/global ID 미발견 또는 offset+size overflowBAD_PARAMETERS 또는 SECURITY; 설정별로 하나의 type군 선택
OPEN/INVOKETA manager 결과handler가 arg->ret/ret_origin 기록; dispatcher 반환은 별도
CLOSE/CANCEL0 params 아님BAD_PARAMETERS; parameter copy 없음
REGISTER_SHMDYN_SHM && !FFA; 1개 TMEM_OUTPUT|NONCONTIGregistered mobj를 만들고 arg->ret 기록
notificationASYNC_NOTIF 꺼짐err → 함수 반환 NOT_IMPLEMENTED
unknown cmdswitch case 없음arg->ret 변경을 가정하지 않고 함수 반환 NOT_IMPLEMENTED

parameter conversion · handlers/dispatch.

각 분기가 소유하는 상태

message-dispatch의 객체와 수명
대상만드는/읽는 곳정리·유지
optee_msg_argcaller가 전달; dispatcher/handler가 cmd·params·header 접근Normal World와 공유되는 call message
tee_ta_paramOPEN/INVOKE의 stack localhandler 종료 시 수명 끝
saved_attr[]copy_in에서 각 attr 기록copy_out·cleanup 판단에 사용
mobj 참조TMEM/RMEM/FMEM 변환설정·type에 맞는 함수가 정리
tee_open_sessionsOPEN이 session 추가; INVOKE/CLOSE/CANCEL이 ID 조회단일 call의 임시 배열과 달리 session 수명까지 유지
arg->ret / 함수 반환handler / dispatcher서로 다른 두 결과 채널

어느 분기가 먼저 거절하는가?

소스에 대응한 실패 판정
증상처음 검사할 조건고정 소스
OPEN BAD_PARAMETERSmeta 2개와 정확한 attr; 남은 TA params ≤4327–383
INVOKE BAD_PARAMETERSTA params ≤4, type, session ID lookup184–261, 429–459
memory type 거절FFA면 FMEM, non-FFA면 TMEM/조건부 RMEM; bounds66–179, 219–255
REGISTER_SHM 실패/명령 없음DYN_SHM && !FFA, 한 개 TMEM_OUTPUT|NONCONTIG486–525, 708–715
알 수 없는 명령case/설정 유무; 함수 반환 NOT_IMPLEMENTED716–751

이 표는 실제 반환 조건을 보여 준다. 모든 실패를 ‘cleanup 중복으로 UAF’로 묶는 진단은 이 코드로 뒷받침되지 않는다.

대상 빌드에서 대조할 자료

이 리뷰는 소스와 로컬 페이지를 검증했으며 OP-TEE를 새로 빌드하거나 보드에서 실행하지 않았다.

message-dispatch 확인 자료
자료읽기 예시구분할 값
빌드 설정CFG_CORE_FFA, CFG_CORE_DYN_SHM, CFG_CORE_ASYNC_NOTIF어느 switch case와 memory type이 포함되는지
symbol${CROSS_COMPILE64}nm -n out/arm/core/tee.elf | grep -E ' (__tee_entry_std|entry_open_session|entry_invoke_command)$'소스 선언문이 아닌 symbol 이름
command tracearg.cmd, num_params, arg.ret, dispatcher 반환handler의 결과와 함수 반환 분리
parameter tracemeta attr, saved_attr, secure TA type, mobj/cookieOPEN의 meta 2개와 일반 TA params 분리

분기별 최소 검증

  1. 01
    OPEN과 INVOKE의 차이

    OPEN의 두 meta attr를 바꾸거나 남은 TA params를 5개로 만들어 BAD_PARAMETERS 경계를 확인한다. INVOKE에는 meta를 넣어 별도로 비교한다.

  2. 02
    설정에 따른 SHM case

    DYN_SHM/FFA 빌드 조합에서 REGISTER_SHM case의 존재와 한 개 parameter 계약을 확인한다.

  3. 03
    두 반환값

    알 수 없는 cmd와 알려진 cmd의 handler 오류를 각각 넣어 dispatcher 반환, arg->ret, ret_origin을 독립 기록한다.

원문과 다음 글