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 #include "tee_load_lib.h"
13 #include <stdlib.h>
14 #include <fileio.h>
15 #include "securec.h"
16 #include "tee_inner_uuid.h"
17 #include "gtask_core.h" /* for find_service */
18 #include "tee_time_api.h"
19 #include "service_manager.h"
20 #include "session_manager.h"
21 #include "init.h"
22
23 #define PREFIX_LEN 6 /* prefix: /tafs/ */
24 #define LIB_AGED_TIME_LIMIT 10000U /* unit: millis */
25 #define LIB_LIMIT_COUNT 5U
26
get_lib_count(const struct service_struct * service)27 static uint32_t get_lib_count(const struct service_struct *service)
28 {
29 uint32_t count = 0;
30 struct lib_info *cur = NULL;
31
32 cur = service->lib_list_head.next;
33
34 while ((cur != NULL) && (cur->type != IMG_TYPE_DYNAMIC_DRV) &&
35 (cur->type != IMG_TYPE_CRYPTO_DRV)) {
36 count++;
37 cur = cur->next;
38 }
39
40 return count;
41 }
42
is_aged_lib(const struct lib_info * libinfo)43 static bool is_aged_lib(const struct lib_info *libinfo)
44 {
45 TEE_Time current = { 0, 0 };
46 uint64_t interval;
47
48 if (libinfo == NULL) {
49 tloge("invalid param\n");
50 return false;
51 }
52
53 /* for dynamic_drv, donnot need aged */
54 if (libinfo->type == IMG_TYPE_DYNAMIC_DRV || libinfo->type == IMG_TYPE_CRYPTO_DRV ||
55 libinfo->type == IMG_TYPE_DYNAMIC_CLIENT)
56 return false;
57
58 TEE_GetSystemTime(¤t);
59
60 get_interval(¤t, &libinfo->load_elf_time, &interval);
61
62 if (interval > LIB_AGED_TIME_LIMIT) {
63 tlogi("aged lib: name is %s, and seconds interval =%llu, max interval = %u\n",
64 libinfo->name, (unsigned long long)interval, LIB_AGED_TIME_LIMIT);
65 return true;
66 }
67 return false;
68 }
69
do_age_timeout_lib(struct service_struct * service)70 void do_age_timeout_lib(struct service_struct *service)
71 {
72 struct lib_info *cur = NULL;
73 struct lib_info *pre = NULL;
74 struct lib_info *tmp = NULL;
75
76 if (service == NULL)
77 return;
78
79 pre = &service->lib_list_head;
80 cur = pre->next;
81 while (cur != NULL) {
82 if (is_aged_lib(cur)) {
83 tmp = cur->next;
84 if (unlink(cur->name) != 0)
85 tloge("unlink %s failed\n", cur->name);
86 free(cur);
87 pre->next = tmp;
88 cur = pre->next;
89 } else {
90 pre = cur;
91 cur = cur->next;
92 }
93 }
94 }
95
is_lib_loaded(const struct service_struct * service,const char * name,size_t name_size)96 int is_lib_loaded(const struct service_struct *service, const char *name, size_t name_size)
97 {
98 int ret = LIB_NOT_LOADED;
99 struct lib_info *cur = NULL;
100
101 if (service == NULL || name == NULL || name_size > LIB_NAME_MAX) {
102 tloge("input param is null\n");
103 return CHECK_ERROR;
104 }
105
106 cur = service->lib_list_head.next;
107 while (cur != NULL) {
108 /* compare length add 1 in order to include "\0" */
109 if (strncmp(name, cur->name, (strlen(cur->name) + 1)) == 0) {
110 tlogi("already in the list, file_name = %s\n", name);
111 ret = LIB_LOADED;
112 break;
113 } else {
114 cur = cur->next;
115 }
116 }
117
118 return ret;
119 }
120
tee_add_libinfo(struct service_struct * service,const char * name,size_t name_size,tee_img_type_t type)121 TEE_Result tee_add_libinfo(struct service_struct *service, const char *name, size_t name_size,
122 tee_img_type_t type)
123 {
124 struct lib_info *libinfo = NULL;
125 bool check_value = (service == NULL || name == NULL);
126 if (check_value == true) {
127 tloge("params error\n");
128 return TEE_ERROR_GENERIC;
129 }
130 if (is_lib_loaded(service, name, name_size) != LIB_NOT_LOADED) {
131 tloge("already in the list or param is invalid!\n");
132 return TEE_ERROR_GENERIC;
133 }
134
135 /* dynamic_drv lib should not be limited by IMG_TYPE_DYNAMIC_DRV and CRYPTO_DRV */
136 if ((type != IMG_TYPE_DYNAMIC_DRV) && (get_lib_count(service) > LIB_LIMIT_COUNT) &&
137 (type != IMG_TYPE_CRYPTO_DRV)) {
138 tlogi("already load %u lib, caution!\n", LIB_LIMIT_COUNT);
139 return TEE_ERROR_GENERIC;
140 }
141
142 libinfo = (struct lib_info *)malloc(sizeof(*libinfo));
143 if (libinfo == NULL) {
144 tloge("libinfo malloc failed\n");
145 return TEE_ERROR_GENERIC;
146 }
147
148 if (strcpy_s(libinfo->name, sizeof(libinfo->name), name) != EOK) { /* with /tafs/ prefix */
149 free(libinfo);
150 return TEE_ERROR_GENERIC;
151 }
152
153 TEE_GetSystemTime(&libinfo->load_elf_time);
154 libinfo->type = type;
155 tlogd("libinfo add node: %s at sec: %u is drv: %d\n",
156 libinfo->name, libinfo->load_elf_time.seconds, (int32_t)libinfo->type);
157 libinfo->next = service->lib_list_head.next;
158 service->lib_list_head.next = libinfo;
159
160 return TEE_SUCCESS;
161 }
162
tee_delete_all_libinfo(struct service_struct * service)163 void tee_delete_all_libinfo(struct service_struct *service)
164 {
165 struct lib_info *libinfo = NULL;
166 struct lib_info *next = NULL;
167
168 if (service == NULL) {
169 tloge("params error\n");
170 return;
171 }
172 libinfo = service->lib_list_head.next;
173 while (libinfo != NULL) {
174 next = libinfo->next;
175 if (unlink(libinfo->name) != 0)
176 tloge("unlink %s failed\n", libinfo->name);
177 free(libinfo);
178 libinfo = next;
179 }
180 service->lib_list_head.next = NULL;
181 return;
182 }
183
tee_delete_single_libinfo(struct service_struct * service,const char * lib_name)184 static void tee_delete_single_libinfo(struct service_struct *service, const char *lib_name)
185 {
186 struct lib_info *pre = NULL;
187 struct lib_info *cur = NULL;
188
189 if (service->lib_list_head.next == NULL) {
190 tloge("no node in lib_list and %s won't be deleted!\n", lib_name);
191 return;
192 }
193 if (strnlen(lib_name, LIB_NAME_MAX) == LIB_NAME_MAX) {
194 tloge("lib name is too long\n");
195 return;
196 }
197
198 pre = &service->lib_list_head;
199 cur = service->lib_list_head.next;
200
201 while (cur != NULL) {
202 /*
203 * compare length add 1 in order to include "\0"
204 * otherwise it may delete wrong lib, for example:
205 * lib1: test.so
206 * lib2: testa.so
207 * when input name is test, it may unlink test.so or testa.so
208 */
209 if (strncmp(lib_name, cur->name + PREFIX_LEN, (size_t)(strlen(lib_name) + 1)) == 0) {
210 if (unlink(cur->name) != 0)
211 tloge("unlink %s failed\n", cur->name);
212 /*
213 * for dynamic_drv, only unlink from tafs, donnot delete it from
214 * lib_list, to avoid teecd was killed
215 */
216 if (cur->type == IMG_TYPE_DYNAMIC_DRV || cur->type == IMG_TYPE_CRYPTO_DRV)
217 return;
218 pre->next = cur->next;
219 free(cur);
220 return;
221 } else {
222 pre = cur;
223 cur = cur->next;
224 }
225 }
226 tloge("%s not exist in lib list!\n", lib_name);
227 return;
228 }
229
process_unlink(const struct ta_unlink_lib_msg * ret_msg,uint32_t task_id)230 static void process_unlink(const struct ta_unlink_lib_msg *ret_msg, uint32_t task_id)
231 {
232 struct service_struct *cur_service = NULL;
233 struct session_struct *cur_session = NULL;
234
235 if (ret_msg == NULL) {
236 tloge("ret_msg is NULL!\n");
237 return;
238 }
239
240 if (!ret_msg->is_drvlib) {
241 if (find_task(task_id, &cur_service, &cur_session) == false) {
242 tloge("fail to find service or session!\n");
243 return;
244 }
245 } else {
246 TEE_UUID uuid = TEE_SERVICE_GLOBAL;
247 if (find_service(&uuid, 0, &cur_service) == INVALID_SERVICE_INDEX)
248 return;
249 }
250 tee_delete_single_libinfo(cur_service, ret_msg->lib_name);
251 return;
252 }
253
handle_unlink_dynamic_drv(uint32_t cmd_id,uint32_t task_id,const uint8_t * msg_buf,uint32_t msg_size)254 int32_t handle_unlink_dynamic_drv(uint32_t cmd_id, uint32_t task_id, const uint8_t *msg_buf, uint32_t msg_size)
255 {
256 struct ta_unlink_lib_msg msg;
257
258 (void)cmd_id;
259 if (msg_size <= sizeof(msg.lib_name)) {
260 tloge("msg_size:0x%x error\n", msg_size);
261 return GT_ERR_END_CMD;
262 }
263
264 uint32_t drv_id;
265 if (get_drvmgr_pid(&drv_id) != 0) {
266 tloge("get drvmgr taskid failed\n");
267 return GT_ERR_END_CMD;
268 }
269
270 if (taskid_to_pid(task_id) != drv_id) {
271 tloge("task:0x%x not support unlink dynamic drv lib\n", task_id);
272 return GT_ERR_END_CMD;
273 }
274
275 /*
276 * for dynamic_drv, only unlink it from tafs, donot delete it's libinfo
277 * from lib_list, to denied teecd was killed.
278 */
279 (void)memset_s(&msg, sizeof(msg), 0, sizeof(msg));
280 errno_t rc = memcpy_s(msg.lib_name, sizeof(msg.lib_name) - 1, msg_buf, sizeof(msg.lib_name) - 1);
281 if (rc != EOK) {
282 tloge("[error]memcpy_s failed, rc=%d, line:%d.\n", rc, __LINE__);
283 return GT_ERR_END_CMD;
284 }
285 msg.lib_name[LIB_NAME_MAX - 1] = '\0';
286 msg.is_drvlib = true;
287
288 process_unlink(&msg, 0); /* taskid not used when is_drvlib is true */
289
290 return GT_ERR_OK;
291 }
292