xref: /optee_os/lib/libutee/user_ta_entry.c (revision 9f2dc7a17efdd58b8afa6c45edcc5bb99c766bfa)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2014, STMicroelectronics International N.V.
4  * Copyright (c) 2022, Linaro Limited.
5  */
6 #include <asan.h>
7 #include <compiler.h>
8 #include <link.h>
9 #include <malloc.h>
10 #include <memtag.h>
11 #include <stdbool.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/queue.h>
15 #include <tee_api.h>
16 #include <tee_arith_internal.h>
17 #include <tee_internal_api_extensions.h>
18 #include <tee_ta_api.h>
19 #include <user_ta_header.h>
20 #include <utee_syscalls.h>
21 #include "tee_api_private.h"
22 
23 struct ta_session {
24 	uint32_t session_id;
25 	void *session_ctx;
26 	TAILQ_ENTRY(ta_session) link;
27 };
28 
29 static TAILQ_HEAD(ta_sessions, ta_session) ta_sessions =
30 		TAILQ_HEAD_INITIALIZER(ta_sessions);
31 
32 /* From user_ta_header.c, built within TA */
33 extern uint8_t ta_heap[];
34 extern const size_t ta_heap_size;
35 extern struct ta_head ta_head;
36 
37 uint32_t ta_param_types;
38 TEE_Param ta_params[TEE_NUM_PARAMS];
39 
40 struct malloc_ctx *__ta_no_share_malloc_ctx;
41 
42 struct __elf_phdr_info __elf_phdr_info;
43 
44 struct phdr_info {
45 	struct dl_phdr_info info;
46 	TAILQ_ENTRY(phdr_info) link;
47 };
48 
49 static TAILQ_HEAD(phdr_info_head, phdr_info) __phdr_info_head =
50 		TAILQ_HEAD_INITIALIZER(__phdr_info_head);
51 /*
52  * Keep track of how many modules have been initialized so that subsequent
53  * dlopen() calls will not run the same initializers again
54  */
55 static size_t _num_mod_init;
56 
_init_iterate_phdr_cb(struct dl_phdr_info * info,size_t size __unused,void * data)57 static int _init_iterate_phdr_cb(struct dl_phdr_info *info,
58 				 size_t size __unused, void *data)
59 {
60 	struct phdr_info *qe = NULL;
61 	size_t *count = data;
62 
63 	qe = malloc(sizeof(*qe));
64 	if (!qe) {
65 		EMSG("init/fini: out of memory");
66 		abort();
67 	}
68 	qe->info = *info;
69 	TAILQ_INSERT_TAIL(&__phdr_info_head, qe, link);
70 	(*count)++;
71 	return 0;
72 }
73 
_get_fn_array(struct dl_phdr_info * info,Elf_Sword tag_a,Elf_Sword tag_s,void (*** fn)(void),size_t * num_fn)74 static void _get_fn_array(struct dl_phdr_info *info, Elf_Sword tag_a,
75 			  Elf_Sword tag_s, void (***fn)(void), size_t *num_fn)
76 {
77 	const Elf_Phdr *phdr = NULL;
78 	Elf_Dyn *dyn = NULL;
79 	size_t num_dyn = 0;
80 	size_t i = 0;
81 	size_t j = 0;
82 
83 	for (i = 0; i < info->dlpi_phnum; i++) {
84 		phdr = info->dlpi_phdr + i;
85 		if (phdr->p_type != PT_DYNAMIC)
86 			continue;
87 		num_dyn = phdr->p_memsz / sizeof(Elf_Dyn);
88 		dyn = (Elf_Dyn *)(phdr->p_vaddr + info->dlpi_addr);
89 		for (j = 0; j < num_dyn; j++) {
90 			if (*fn && *num_fn)
91 				break;
92 			if (dyn->d_tag == DT_NULL) {
93 				break;
94 			} else if (dyn->d_tag == tag_a) {
95 				*fn = (void (**)(void))(dyn->d_un.d_ptr +
96 							info->dlpi_addr);
97 			} else if (dyn->d_tag == tag_s) {
98 				*num_fn = dyn->d_un.d_val / sizeof(Elf_Addr);
99 			}
100 			dyn++;
101 		}
102 	}
103 }
104 
__utee_call_elf_init_fn(void)105 void __utee_call_elf_init_fn(void)
106 {
107 	void (**fn)(void) = NULL;
108 	size_t num_mod = 0;
109 	size_t num_fn = 0;
110 	size_t mod = 0;
111 	size_t i = 0;
112 	struct phdr_info *qe = NULL;
113 	struct phdr_info *qe2 = NULL;
114 
115 	dl_iterate_phdr(_init_iterate_phdr_cb, &num_mod);
116 
117 	/* Reverse order: dependencies first */
118 	TAILQ_FOREACH_REVERSE(qe, &__phdr_info_head, phdr_info_head, link) {
119 		if (mod == num_mod - _num_mod_init)
120 			break;
121 		_get_fn_array(&qe->info, DT_INIT_ARRAY, DT_INIT_ARRAYSZ, &fn,
122 			      &num_fn);
123 		for (i = 0; i < num_fn; i++)
124 			fn[i]();
125 		fn = NULL;
126 		num_fn = 0;
127 		mod++;
128 	}
129 	_num_mod_init += mod;
130 
131 	TAILQ_FOREACH_SAFE(qe, &__phdr_info_head, link, qe2) {
132 		TAILQ_REMOVE(&__phdr_info_head, qe, link);
133 		free(qe);
134 	}
135 }
136 
_fini_iterate_phdr_cb(struct dl_phdr_info * info,size_t size __unused,void * data __unused)137 static int _fini_iterate_phdr_cb(struct dl_phdr_info *info,
138 				 size_t size __unused, void *data __unused)
139 {
140 	void (**fn)(void) = NULL;
141 	size_t num_fn = 0;
142 	size_t i = 0;
143 
144 	_get_fn_array(info, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, &fn, &num_fn);
145 
146 	for (i = 1; i <= num_fn; i++)
147 		fn[num_fn - i]();
148 
149 	return 0;
150 }
151 
__utee_call_elf_fini_fn(void)152 void __utee_call_elf_fini_fn(void)
153 {
154 	dl_iterate_phdr(_fini_iterate_phdr_cb, NULL);
155 }
156 
get_memtag_implementation(void)157 static unsigned int get_memtag_implementation(void)
158 {
159 	const char *s = "org.trustedfirmware.optee.cpu.feat_memtag_implemented";
160 	uint32_t v = 0;
161 
162 	if (TEE_GetPropertyAsU32(TEE_PROPSET_TEE_IMPLEMENTATION, s, &v))
163 		return 0;
164 	return v;
165 }
166 
init_instance(void)167 static TEE_Result init_instance(void)
168 {
169 	static bool internal_init_done;
170 	static bool init_done;
171 	TEE_Result res;
172 
173 	if (init_done)
174 		return TEE_SUCCESS;
175 
176 	if (internal_init_done)
177 		goto create_entrypoint;
178 
179 	trace_set_level(tahead_get_trace_level());
180 	__utee_gprof_init();
181 	malloc_add_pool(ta_heap, ta_heap_size);
182 	if (__ta_no_share_heap_size) {
183 		__ta_no_share_malloc_ctx = malloc(raw_malloc_get_ctx_size());
184 		if (__ta_no_share_malloc_ctx) {
185 			raw_malloc_init_ctx(__ta_no_share_malloc_ctx);
186 			raw_malloc_add_pool(__ta_no_share_malloc_ctx,
187 					    __ta_no_share_heap,
188 					    __ta_no_share_heap_size);
189 		}
190 	}
191 	memtag_init_ops(get_memtag_implementation());
192 	_TEE_MathAPI_Init();
193 	__utee_tcb_init();
194 	__utee_call_elf_init_fn();
195 	asan_start();
196 
197 	internal_init_done = true;
198 
199 create_entrypoint:
200 	res = TA_CreateEntryPoint();
201 	if (!res)
202 		init_done = true;
203 
204 	return res;
205 }
206 
uninit_instance(void)207 static void uninit_instance(void)
208 {
209 	__utee_gprof_fini();
210 	TA_DestroyEntryPoint();
211 	__utee_call_elf_fini_fn();
212 }
213 
ta_header_save_params(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS])214 static void ta_header_save_params(uint32_t param_types,
215 				  TEE_Param params[TEE_NUM_PARAMS])
216 {
217 	ta_param_types = param_types;
218 
219 	if (params)
220 		memcpy(ta_params, params, sizeof(ta_params));
221 	else
222 		memset(ta_params, 0, sizeof(ta_params));
223 }
224 
ta_header_get_session(uint32_t session_id)225 static struct ta_session *ta_header_get_session(uint32_t session_id)
226 {
227 	struct ta_session *itr;
228 
229 	TAILQ_FOREACH(itr, &ta_sessions, link) {
230 		if (itr->session_id == session_id)
231 			return itr;
232 	}
233 	return NULL;
234 }
235 
ta_header_add_session(uint32_t session_id)236 static TEE_Result ta_header_add_session(uint32_t session_id)
237 {
238 	struct ta_session *itr = ta_header_get_session(session_id);
239 	TEE_Result res;
240 
241 	if (itr)
242 		return TEE_SUCCESS;
243 
244 	res = init_instance();
245 	if (res)
246 		return res;
247 
248 	itr = TEE_Malloc(sizeof(struct ta_session),
249 			TEE_USER_MEM_HINT_NO_FILL_ZERO);
250 	if (!itr)
251 		return TEE_ERROR_OUT_OF_MEMORY;
252 	itr->session_id = session_id;
253 	itr->session_ctx = 0;
254 	TAILQ_INSERT_TAIL(&ta_sessions, itr, link);
255 
256 	return TEE_SUCCESS;
257 }
258 
ta_header_remove_session(uint32_t session_id)259 static void ta_header_remove_session(uint32_t session_id)
260 {
261 	struct ta_session *itr;
262 	bool keep_alive;
263 
264 	TAILQ_FOREACH(itr, &ta_sessions, link) {
265 		if (itr->session_id == session_id) {
266 			TAILQ_REMOVE(&ta_sessions, itr, link);
267 			TEE_Free(itr);
268 
269 			keep_alive =
270 				(ta_head.flags & TA_FLAG_SINGLE_INSTANCE) &&
271 				(ta_head.flags & TA_FLAG_INSTANCE_KEEP_ALIVE);
272 			if (TAILQ_EMPTY(&ta_sessions) && !keep_alive)
273 				uninit_instance();
274 
275 			return;
276 		}
277 	}
278 }
279 
to_utee_params(struct utee_params * up,uint32_t param_types,const TEE_Param params[TEE_NUM_PARAMS])280 static void to_utee_params(struct utee_params *up, uint32_t param_types,
281 			   const TEE_Param params[TEE_NUM_PARAMS])
282 {
283 	size_t n = 0;
284 
285 	up->types = param_types;
286 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
287 		switch (TEE_PARAM_TYPE_GET(param_types, n)) {
288 		case TEE_PARAM_TYPE_VALUE_INPUT:
289 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
290 		case TEE_PARAM_TYPE_VALUE_INOUT:
291 			up->vals[n * 2] = params[n].value.a;
292 			up->vals[n * 2 + 1] = params[n].value.b;
293 			break;
294 		case TEE_PARAM_TYPE_MEMREF_INPUT:
295 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
296 		case TEE_PARAM_TYPE_MEMREF_INOUT:
297 			up->vals[n * 2] = (uintptr_t)params[n].memref.buffer;
298 			up->vals[n * 2 + 1] = params[n].memref.size;
299 			break;
300 		default:
301 			up->vals[n * 2] = 0;
302 			up->vals[n * 2 + 1] = 0;
303 			break;
304 		}
305 	}
306 }
307 
from_utee_params(TEE_Param params[TEE_NUM_PARAMS],uint32_t * param_types,const struct utee_params * up)308 static void from_utee_params(TEE_Param params[TEE_NUM_PARAMS],
309 			     uint32_t *param_types,
310 			     const struct utee_params *up)
311 {
312 	size_t n;
313 	uint32_t types = up->types;
314 
315 	for (n = 0; n < TEE_NUM_PARAMS; n++) {
316 		uintptr_t a = up->vals[n * 2];
317 		uintptr_t b = up->vals[n * 2 + 1];
318 
319 		switch (TEE_PARAM_TYPE_GET(types, n)) {
320 		case TEE_PARAM_TYPE_VALUE_INPUT:
321 		case TEE_PARAM_TYPE_VALUE_OUTPUT:
322 		case TEE_PARAM_TYPE_VALUE_INOUT:
323 			params[n].value.a = a;
324 			params[n].value.b = b;
325 			break;
326 		case TEE_PARAM_TYPE_MEMREF_INPUT:
327 		case TEE_PARAM_TYPE_MEMREF_OUTPUT:
328 		case TEE_PARAM_TYPE_MEMREF_INOUT:
329 			params[n].memref.buffer = (void *)a;
330 			params[n].memref.size = b;
331 			break;
332 		default:
333 			break;
334 		}
335 	}
336 
337 	if (param_types)
338 		*param_types = types;
339 }
340 
entry_open_session(unsigned long session_id,struct utee_params * up)341 static TEE_Result entry_open_session(unsigned long session_id,
342 			struct utee_params *up)
343 {
344 	TEE_Result res;
345 	struct ta_session *session;
346 	uint32_t param_types;
347 	TEE_Param params[TEE_NUM_PARAMS];
348 
349 	res = ta_header_add_session(session_id);
350 	if (res != TEE_SUCCESS)
351 		return res;
352 
353 	session = ta_header_get_session(session_id);
354 	if (!session)
355 		return TEE_ERROR_BAD_STATE;
356 
357 	from_utee_params(params, &param_types, up);
358 	ta_header_save_params(param_types, params);
359 
360 	res = TA_OpenSessionEntryPoint(param_types, params,
361 				       &session->session_ctx);
362 
363 	to_utee_params(up, param_types, params);
364 
365 	if (res != TEE_SUCCESS)
366 		ta_header_remove_session(session_id);
367 	return res;
368 }
369 
entry_close_session(unsigned long session_id)370 static TEE_Result entry_close_session(unsigned long session_id)
371 {
372 	struct ta_session *session = ta_header_get_session(session_id);
373 
374 	if (!session)
375 		return TEE_ERROR_BAD_STATE;
376 
377 	TA_CloseSessionEntryPoint(session->session_ctx);
378 
379 	ta_header_remove_session(session_id);
380 	return TEE_SUCCESS;
381 }
382 
entry_invoke_command(unsigned long session_id,struct utee_params * up,unsigned long cmd_id)383 static TEE_Result entry_invoke_command(unsigned long session_id,
384 			struct utee_params *up, unsigned long cmd_id)
385 {
386 	TEE_Result res;
387 	uint32_t param_types;
388 	TEE_Param params[TEE_NUM_PARAMS];
389 	struct ta_session *session = ta_header_get_session(session_id);
390 
391 	if (!session)
392 		return TEE_ERROR_BAD_STATE;
393 
394 	from_utee_params(params, &param_types, up);
395 	ta_header_save_params(param_types, params);
396 
397 	res = TA_InvokeCommandEntryPoint(session->session_ctx, cmd_id,
398 					 param_types, params);
399 
400 	to_utee_params(up, param_types, params);
401 	return res;
402 }
403 
404 #if defined(CFG_TA_STATS)
entry_dump_memstats(unsigned long session_id __unused,struct utee_params * up)405 static TEE_Result entry_dump_memstats(unsigned long session_id __unused,
406 				      struct utee_params *up)
407 {
408 	uint32_t param_types = 0;
409 	TEE_Param params[TEE_NUM_PARAMS] = { };
410 	struct pta_stats_alloc stats = { };
411 
412 	from_utee_params(params, &param_types, up);
413 	ta_header_save_params(param_types, params);
414 
415 	if (TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_OUTPUT,
416 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
417 			    TEE_PARAM_TYPE_VALUE_OUTPUT,
418 			    TEE_PARAM_TYPE_NONE) != param_types)
419 		return TEE_ERROR_BAD_PARAMETERS;
420 
421 	malloc_get_stats(&stats);
422 	params[0].value.a = stats.allocated;
423 	params[0].value.b = stats.max_allocated;
424 	params[1].value.a = stats.size;
425 	params[1].value.b = stats.num_alloc_fail;
426 	params[2].value.a = stats.biggest_alloc_fail;
427 	params[2].value.b = stats.biggest_alloc_fail_used;
428 	to_utee_params(up, param_types, params);
429 
430 	return TEE_SUCCESS;
431 }
432 #endif
433 
__utee_entry(unsigned long func,unsigned long session_id,struct utee_params * up,unsigned long cmd_id)434 TEE_Result __utee_entry(unsigned long func, unsigned long session_id,
435 			struct utee_params *up, unsigned long cmd_id)
436 {
437 	TEE_Result res;
438 
439 	switch (func) {
440 	case UTEE_ENTRY_FUNC_OPEN_SESSION:
441 		res = entry_open_session(session_id, up);
442 		break;
443 	case UTEE_ENTRY_FUNC_CLOSE_SESSION:
444 		res = entry_close_session(session_id);
445 		break;
446 	case UTEE_ENTRY_FUNC_INVOKE_COMMAND:
447 		res = entry_invoke_command(session_id, up, cmd_id);
448 		break;
449 #if defined(CFG_TA_STATS)
450 	case UTEE_ENTRY_FUNC_DUMP_MEMSTATS:
451 		res = entry_dump_memstats(session_id, up);
452 		break;
453 #endif
454 	default:
455 		res = TEE_ERROR_NOT_SUPPORTED;
456 		break;
457 	}
458 	ta_header_save_params(0, NULL);
459 
460 	return res;
461 }
462