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 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 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 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 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 152 void __utee_call_elf_fini_fn(void) 153 { 154 dl_iterate_phdr(_fini_iterate_phdr_cb, NULL); 155 } 156 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 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 207 static void uninit_instance(void) 208 { 209 __utee_gprof_fini(); 210 TA_DestroyEntryPoint(); 211 __utee_call_elf_fini_fn(); 212 } 213 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 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 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 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 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 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 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, ¶m_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 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 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, ¶m_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) 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, ¶m_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 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