1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #define _GNU_SOURCE
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <fcntl.h>
18 #include <dlfcn.h>
19 #include <sys/mman.h>
20 #include <priorities.h>
21 #include <fileio.h>
22 #include <unistd.h>
23 #include <ipclib.h>
24 #include <securec.h>
25 #include <tee_log.h>
26 #include <ta_framework.h>
27 #include <tee_task.h>
28 #include <tee_drv_internal.h>
29 #include <spawn_init.h>
30 #include <target_type.h>
31 #include <tee_drv_entry.h>
32 #include "get_spawn_env.h"
33 #include "load_init.h"
34 #include "ta_mt.h"
35 #include <ipclib_hal.h>
36 #include <mem_ops.h>
37 #include <unistd.h>
38
39 #define RTLD_TA 0x100000
40 #define IPC_CHANNEL_NUM 2
41
42 #ifdef __aarch64__
43 static const char *g_tarunner_path = "/tarunner.elf";
44 static const char *g_drv_so_path = "libdrv_shared.so";
45 #else
46 static const char *g_tarunner_path = "/tarunner_a32.elf";
47 static const char *g_drv_so_path = "libdrv_shared_a32.so";
48 #endif
49
param_check(int32_t argc,const char * const * argv)50 static int32_t param_check(int32_t argc, const char * const * argv)
51 {
52 size_t length;
53
54 if (argc < (ARGV_TERMINATE_INDEX - 1)) {
55 tloge("invalid argc %d\n", argc);
56 return -1;
57 }
58
59 length = strnlen(argv[ARGV_TASK_NAME_INDEX], ARGV0_SIZE);
60 if (length == 0 || length >= ARGV0_SIZE) {
61 tloge("invalid service name\n");
62 return -1;
63 }
64
65 if (strncmp(argv[ARGV_TASK_NAME_INDEX], g_tarunner_path, (strlen(g_tarunner_path) + 1)) == 0) {
66 tloge("load TA in buffer not implemented\n");
67 return -1;
68 }
69
70 length = strnlen(argv[ARGV_TASK_PATH_INDEX], ARGV_SIZE);
71 if (length == 0 || length >= ARGV_SIZE) {
72 tloge("invalid path name\n");
73 return -1;
74 }
75
76 return 0;
77 }
78
79 /*
80 * they work for many TAs
81 * which helps TA to extend utilities
82 */
is_agent(const char * task_name)83 static bool is_agent(const char *task_name)
84 {
85 if (strncmp(task_name, "task_ssa", strlen("task_ssa") + 1) == 0)
86 return true;
87 return false;
88 }
89
extend_one_more_utable(const char * task_name)90 static bool extend_one_more_utable(const char *task_name)
91 {
92 return is_agent(task_name);
93 }
94
get_target_type_name(const struct env_param * param)95 static const char *get_target_type_name(const struct env_param *param)
96 {
97 const char *name = NULL;
98
99 if (param->target_type == DRV_TARGET_TYPE)
100 name = "DRV";
101 else
102 name = "TA";
103
104 return name;
105 }
106
load_info_print(const char * task_name,const struct env_param * param)107 static void load_info_print(const char *task_name, const struct env_param *param)
108 {
109 const char *type = get_target_type_name(param);
110
111 /* Always print, but not an error */
112 #ifdef __aarch64__
113 tlogi("Start dynlink 64bit %s %s: pid=%d\n", type, task_name, getpid());
114 #else
115 tlogi("Start dynlink %s %s: pid=%d\n", type, task_name, getpid());
116 #endif
117 }
118
create_task_channel(const char * task_name,const struct env_param * param,cref_t * drv_channel)119 static int32_t create_task_channel(const char *task_name, const struct env_param *param, cref_t *drv_channel)
120 {
121 int32_t ret;
122 struct reg_items_st reg_items = { true, false, false };
123
124 if (param->target_type == DRV_TARGET_TYPE) {
125 /* used for cs_server_loop */
126 ret = ipc_create_channel_native(task_name, drv_channel);
127 if (ret != 0) {
128 tloge("create drv:%s channel failed\n", task_name);
129 return -1;
130 }
131
132 tlogd("create drv:%s channel:0x%llx\n", task_name, (unsigned long long)(*drv_channel));
133 } else {
134 /* Create 2 IPC channels */
135 ret = ipc_create_channel(task_name, IPC_CHANNEL_NUM, NULL, reg_items);
136 if (ret != 0) {
137 tloge("create multi ipc channel failed: %d\n", ret);
138 return -1;
139 }
140 }
141
142 return 0;
143 }
144
init(const char * task_name,const struct env_param * param,cref_t * drv_channel)145 static int32_t init(const char *task_name, const struct env_param *param, cref_t *drv_channel)
146 {
147 int32_t ret;
148
149 load_info_print(task_name, param);
150
151 /* modify g_debug_prefix */
152 g_debug_prefix = task_name;
153
154 /* Extend utable for drv or agent, such as SSA */
155 if ((param->target_type == DRV_TARGET_TYPE) || extend_one_more_utable(task_name)) {
156 ret = extend_utables();
157 if (ret != 0) {
158 tloge("extend utable for \"%s\" failed: %d\n", task_name, ret);
159 return -1;
160 }
161 }
162
163 ret = create_task_channel(task_name, param, drv_channel);
164 if (ret != 0)
165 return -1;
166
167 ret = fileio_init();
168 if (ret != 0) {
169 tloge("file io init failed: %d\n", ret);
170 return -1;
171 }
172
173 return 0;
174 }
175
send_fail_msg_to_drvmgr(void)176 static void send_fail_msg_to_drvmgr(void)
177 {
178 cref_t ch = 0;
179 int32_t ret = ipc_get_ch_from_path(DRV_SPAWN_SYNC_NAME, &ch);
180 if (ret != 0) {
181 tloge("something wrong, spawn fail get drvmgr sync channel fail\n");
182 return;
183 }
184
185 struct spawn_sync_msg msg = { 0 };
186 msg.msg_id = PROCESS_INIT_FAIL;
187
188 ret = ipc_msg_notification(ch, &msg, sizeof(msg));
189 if (ret != 0) {
190 tloge("spawn fail notify to drvmgr fail\n");
191 return;
192 }
193
194 if (ipc_release_from_path(DRV_SPAWN_SYNC_NAME, ch) != 0)
195 tloge("release drvmgr sync channel fail\n");
196 }
197
send_load_fail_msg(uint32_t target_type)198 static void send_load_fail_msg(uint32_t target_type)
199 {
200 if (target_type == DRV_TARGET_TYPE) {
201 send_fail_msg_to_drvmgr();
202 } else {
203 /*
204 * TA load failed, send error to global task
205 * uwMsgHandle is 0 mean we don't need handle msg in msg function
206 * uwMsgID is 0 means we don't care about the context
207 * ucDstID is 1 means the recevier's channel ID is 1
208 */
209 if (ipc_msg_qsend(CREATE_THREAD_FAIL, GLOBAL_HANDLE, SECOND_CHANNEL) != 0)
210 tloge("failed to reply GTASK for MT ta\n");
211 }
212 }
213
load_fail(uint32_t target_type)214 static void load_fail(uint32_t target_type)
215 {
216 clear_libtee();
217
218 send_load_fail_msg(target_type);
219 }
220
get_routine_info(void * handle,uint32_t size,struct ta_routine_info * routine)221 static int32_t get_routine_info(void *handle, uint32_t size, struct ta_routine_info *routine)
222 {
223 /* no need to check function entry since TA may not define it */
224 routine->info[CREATE_ENTRY_INDEX] = dlsym(handle, "TA_CreateEntryPoint");
225 routine->info[OPEN_SESSION_INDEX] = dlsym(handle, "TA_OpenSessionEntryPoint");
226 routine->info[INVOKE_COMMAND_INDEX] = dlsym(handle, "TA_InvokeCommandEntryPoint");
227 routine->info[CLOSE_SESSION_INDEX] = dlsym(handle, "TA_CloseSessionEntryPoint");
228 routine->info[DESTROY_ENTRY_INDEX] = dlsym(handle, "TA_DestroyEntryPoint");
229
230 /* should check caller info when open session */
231 routine->addcaller_flag = true;
232
233 if (mprotect(routine, size, PROT_READ) != 0) {
234 tloge("change routine attribute failed\n");
235 return -1;
236 }
237
238 return 0;
239 }
240
lib_tee_task_entry(void * handle,int32_t priority,const char * task_name,void * libtee)241 static void lib_tee_task_entry(void *handle, int32_t priority, const char *task_name, void *libtee)
242 {
243 struct ta_routine_info *routine = NULL;
244 ta_entry_type ta_entry = { 0 };
245 uint32_t size;
246
247 ta_entry.ta_entry = dlsym(libtee, "tee_task_entry");
248 if (ta_entry.ta_entry == NULL) {
249 tloge("get task entry failed: %s\n", dlerror());
250 return;
251 }
252
253 /* cannot be overflow */
254 size = PAGE_ALIGN_UP(sizeof(*routine));
255 /* first param set as 0 means no specific address, set fd as -1 means no specific fd */
256 routine = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
257 if (routine == MAP_FAILED) {
258 tloge("map for routine failed\n");
259 return;
260 }
261
262 if (memset_s(routine, size, 0, size) != EOK) {
263 tloge("clear routine failed\n");
264 goto err_out;
265 }
266
267 if (get_routine_info(handle, size, routine) != 0)
268 goto err_out;
269
270 tee_task_entry_mt(ta_entry, priority, task_name, routine);
271
272 /* tee_task_entry should never return */
273 tee_abort("tee task entry returns\n");
274
275 err_out:
276 if (munmap(routine, size) != 0)
277 tloge("free routine failed\n");
278 }
279
ta_tee_task_entry(ta_entry_type ta_entry,int32_t priority,const char * task_name)280 static void ta_tee_task_entry(ta_entry_type ta_entry, int32_t priority, const char *task_name)
281 {
282 tlogi("ta link elf_main_entry\n");
283
284 tee_task_entry_mt(ta_entry, priority, task_name, NULL);
285
286 /* tee_task_entry should never return */
287 tee_abort("tee task entry returns\n");
288 }
289
load_dyn_client(char * client)290 static void load_dyn_client(char *client)
291 {
292 uint32_t size = CLIENT_NAME_SIZE * MAX_DYN_CLIENT_NUM;
293 if (strnlen(client, size - 1) != size - 1)
294 return;
295
296 for (uint32_t i = 0; i < size; i++) {
297 if (client[i] == '#')
298 client[i] = 0;
299 }
300
301 char per_client_name[CLIENT_NAME_SIZE + 1] = {0};
302 for (uint32_t i = 0; i < MAX_DYN_CLIENT_NUM; i++) {
303 if (memcpy_s(per_client_name, sizeof(per_client_name),
304 client + i * CLIENT_NAME_SIZE, CLIENT_NAME_SIZE) != 0)
305 continue;
306
307 if (strlen(per_client_name) == 0)
308 continue;
309
310 tlogi("load_dyn_client client_name:%s\n", per_client_name);
311 (void)dlopen(per_client_name, RTLD_NOW | RTLD_GLOBAL | RTLD_TA);
312 (void)memset_s(per_client_name, sizeof(per_client_name), 0, sizeof(per_client_name));
313 }
314 }
315
tee_task_handle(const char * const * argv,const struct env_param * param,void * libtee)316 static void tee_task_handle(const char * const *argv, const struct env_param *param, void *libtee)
317 {
318 ta_entry_type ta_entry = { 0 };
319
320 load_dyn_client((char *)argv[ARGV_CLIENT_NAME_INDEX]);
321
322 /* Load TA in dlopen, will call init_array func */
323 void *handle = dlopen(argv[ARGV_TASK_PATH_INDEX], RTLD_NOW | RTLD_GLOBAL | RTLD_TA);
324 if (handle == NULL) {
325 tloge("dlopen %s failed: %s\n", argv[ARGV_TASK_PATH_INDEX], dlerror());
326 return;
327 }
328
329 /* elf symbol reloc */
330 ta_entry.ta_entry_orig = dlsym(handle, "tee_task_entry");
331 /* TA has tee_task_entry */
332 if (ta_entry.ta_entry_orig != NULL)
333 ta_tee_task_entry(ta_entry, param->priority, argv[ARGV_TASK_NAME_INDEX]);
334 else
335 lib_tee_task_entry(handle, param->priority, argv[ARGV_TASK_NAME_INDEX], libtee);
336
337 dlclose(handle);
338 }
339
340 #define DRV_FUNC_SYMBOL_APPEND 9U /* reserved mem for "g_driver_" string */
dlsym_drv_func(void * drv_handle,const char * drv_name)341 static struct tee_driver_module *dlsym_drv_func(void *drv_handle, const char *drv_name)
342 {
343 char symbol_name[DRV_NAME_MAX_LEN + DRV_FUNC_SYMBOL_APPEND] = {0};
344 if (snprintf_s(symbol_name, sizeof(symbol_name), sizeof(symbol_name) - 1, "%s%s", "g_driver_", drv_name) <= 0) {
345 tloge("get symbol_name failed\n");
346 return NULL;
347 }
348
349 struct tee_driver_module *drv_func = dlsym(drv_handle, symbol_name);
350 if (drv_func == NULL) {
351 tloge("cannot get drv func:%s\n", symbol_name);
352 return NULL;
353 }
354
355 return drv_func;
356 }
357
drv_task_handle(const char * const * argv,const struct env_param * param,void * libtee,cref_t drv_channel)358 static void drv_task_handle(const char * const * argv, const struct env_param *param, void *libtee, cref_t drv_channel)
359 {
360 void *drv_so_handle = NULL;
361 void *drv_handle = NULL;
362 void (*use_tid_flag)(void) = NULL;
363
364 use_tid_flag = dlsym(libtee, "set_log_use_tid_flag");
365 if (use_tid_flag != NULL) {
366 use_tid_flag();
367 } else {
368 tloge("cannot set use tid log flag\n");
369 goto drv_err;
370 }
371
372 tlogd("target_type is %u elf_path:%s task_name:%s\n", param->target_type, argv[ARGV_TASK_PATH_INDEX],
373 argv[ARGV_TASK_NAME_INDEX]);
374
375 drv_so_handle = dlopen(g_drv_so_path, RTLD_NOW | RTLD_GLOBAL);
376 if (drv_so_handle == NULL) {
377 tloge("load %s failed %s\n", g_drv_so_path, dlerror());
378 goto drv_err;
379 }
380
381 drv_entry_func drv_entry = dlsym(drv_so_handle, "tee_drv_entry");
382 if (drv_entry == NULL) {
383 tloge("cannot get tee drv entry\n");
384 goto drv_err;
385 }
386
387 drv_handle = dlopen(argv[ARGV_TASK_PATH_INDEX], RTLD_NOW | RTLD_GLOBAL | RTLD_TA);
388 if (drv_handle == NULL) {
389 tloge("dlopen drv:%s failed %s\n", argv[ARGV_TASK_PATH_INDEX], dlerror());
390 goto drv_err;
391 }
392
393 /* check in drv_entry */
394 struct tee_driver_module *drv_func = dlsym_drv_func(drv_handle, argv[ARGV_TASK_NAME_INDEX]);
395 if (drv_func == NULL)
396 goto drv_err;
397
398 drv_entry(drv_func, argv[ARGV_TASK_NAME_INDEX], drv_channel, param);
399
400 tee_abort("drv entry return, something wrong\n");
401
402 drv_err:
403 if (drv_so_handle != NULL)
404 dlclose(drv_so_handle);
405
406 if (drv_handle != NULL)
407 dlclose(drv_handle);
408 }
409
main(int32_t argc,const char * const * argv)410 __attribute__((visibility("default"))) int32_t main(int32_t argc, const char * const * argv)
411 {
412 struct env_param param = { 0 };
413 void *libtee = NULL;
414 cref_t drv_channel = 0;
415
416 mem_ops_init();
417
418 if (param_check(argc, argv) != 0) {
419 tloge("param check failed\n");
420 goto err_out;
421 }
422
423 if (get_env_param(¶m) != 0)
424 goto err_out;
425
426 /* task context initialization */
427 if (init(argv[ARGV_TASK_NAME_INDEX], ¶m, &drv_channel) != 0)
428 goto err_out;
429
430 if (param.target_type == DRV_TARGET_TYPE) {
431 drv_task_handle(argv, ¶m, libtee, drv_channel);
432 } else {
433 /* A parameter is added for transferring the client name during dynamic service loading */
434 if (argc < ARGV_MAX - 1) {
435 tloge("invalid argc %d", argc);
436 goto err_out;
437 }
438
439 tee_task_handle(argv, ¶m, libtee);
440 }
441
442 err_out:
443 load_fail(param.target_type);
444 return -1;
445 }
446