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_task_exception.h"
13 #include <stddef.h>
14 #include <dlist.h>
15 #include "securec.h"
16 #include "tee_log.h"
17 #include "ta_framework.h"
18 #include "init.h"
19 #include "initlib.h"
20 #include "gtask_config_hal.h"
21 #include "tee_config.h"
22 #include "task_adaptor_pub.h"
23 #include "gtask_core.h"
24 #include "gtask_inner.h"
25 #include "service_manager.h"
26 #include "session_manager.h"
27 #include "global_task.h"
28 #include "tee_drv_internal.h"
29 #include "tee_task_config.h"
30 #include "tee_task.h"
31 #include "timer.h"
32 #include <ipclib_hal.h>
33
response_to_ca(const smc_cmd_t * cmd)34 static void response_to_ca(const smc_cmd_t *cmd)
35 {
36 if (put_last_out_cmd(cmd) != GT_ERR_OK)
37 tloge("put ns cmd fail\n");
38 }
39
response_to_ta(const smc_cmd_t * cmd,uint32_t father_task_id)40 static void response_to_ta(const smc_cmd_t *cmd, uint32_t father_task_id)
41 {
42 struct ta2ta_ret_msg ret_msg = { 0 };
43
44 ret_msg.ret = cmd->ret_val;
45 if (memcpy_s(&ret_msg.cmd, sizeof(ret_msg.cmd), cmd, sizeof(*cmd)) != EOK) {
46 tloge("memcpy ta2ta back cmd failed\n");
47 ret_msg.ret = TEE_ERROR_GENERIC;
48 }
49
50 (void)ipc_msg_snd(TA2TA_CALL, father_task_id, &ret_msg, sizeof(ret_msg));
51 }
52
ta_exception_response(smc_cmd_t * cmd,uint32_t cmd_type,uint32_t father_task_id)53 static void ta_exception_response(smc_cmd_t *cmd, uint32_t cmd_type, uint32_t father_task_id)
54 {
55 cmd->err_origin = TEE_ORIGIN_TRUSTED_APP;
56 cmd->ret_val = TEE_ERROR_TARGET_DEAD;
57
58 if (cmd_type == CMD_TYPE_NS_TO_SECURE)
59 response_to_ca(cmd);
60 else if (cmd_type == CMD_TYPE_SECURE_TO_SECURE)
61 response_to_ta(cmd, father_task_id);
62 else
63 tloge("unknown cmd type %u\n", cmd_type);
64 }
65
66 static void try_release_dead_father(uint32_t task_id);
release_cur_session(struct service_struct * crash_srv,struct session_struct * sess)67 static TEE_Result release_cur_session(struct service_struct *crash_srv, struct session_struct *sess)
68 {
69 uint32_t father_task_id = sess->ta2ta_from_taskid;
70
71 tlogi("release session 0x%x, service name is %s\n", sess->session_id, crash_srv->name);
72 if (sess->wait_ta_back_msg) {
73 /* if session is killed when running, we should send response to CA or Father TA */
74 tlogi("session 0x%x need response, cmd type=%u, father_task_id=0x%x\n", sess->session_id, sess->cmd_type,
75 sess->ta2ta_from_taskid);
76 ta_exception_response(&sess->cmd_in, sess->cmd_type, sess->ta2ta_from_taskid);
77 }
78 int32_t ret = release_session(crash_srv, sess);
79 if (ret != 0) {
80 tloge("release session failed\n");
81 return TEE_ERROR_GENERIC;
82 }
83
84 /* in case of more than one TA has exception, we check father session here to clear dead father */
85 if (father_task_id != SMCMGR_PID)
86 try_release_dead_father(father_task_id);
87 return TEE_SUCCESS;
88 }
89
90 /* we only close child TA here, if child TA has child, like TA1->TA2->TA3, TA2 should close TA3 itself */
close_child_session(const struct session_struct * sess)91 static TEE_Result close_child_session(const struct session_struct *sess)
92 {
93 TEE_Result ret = TEE_SUCCESS;
94 struct session_struct *sess_context = NULL;
95
96 dlist_for_each_entry(sess_context, &(sess->child_ta_sess_head), struct session_struct, child_ta_sess_list)
97 {
98 sess_context->session_status = TA_STATUS_FATHER_DEAD;
99 /* session is running, we will wait ack */
100 if (sess_context->wait_ta_back_msg) {
101 tlogi("child session 0x%x is running, will wait ack\n", sess_context->session_id);
102 continue;
103 }
104 if (close_session_async(sess_context) != TEE_SUCCESS) {
105 ret = TEE_ERROR_GENERIC;
106 tloge("close session 0x%x async failed\n", sess_context->session_id);
107 }
108 }
109 return ret;
110 }
111
try_release_session(struct service_struct * crash_srv,struct session_struct * sess)112 static TEE_Result try_release_session(struct service_struct *crash_srv, struct session_struct *sess)
113 {
114 sess->session_status = TA_STATUS_SELF_DEAD;
115 if (sess->agent_pending) {
116 /* we should wait agent response */
117 tlogi("service %s, session 0x%x is waiting for agent response, will release later\n", crash_srv->name,
118 sess->session_id);
119 return TEE_SUCCESS;
120 }
121 if (dlist_empty(&sess->child_ta_sess_head)) {
122 /* if session has no child, just release itself */
123 return release_cur_session(crash_srv, sess);
124 } else {
125 /* if session has child sess, release child sess first */
126 tlogi("service %s, session 0x%x has child session, will close child session first\n", crash_srv->name,
127 sess->session_id);
128 return close_child_session(sess);
129 }
130 }
131
release_service(struct service_struct * dead_srv)132 static void release_service(struct service_struct *dead_srv)
133 {
134 TEE_UUID uuid = { 0 };
135 struct service_struct dyn_srv;
136
137 tlogi("start release service %s img_type:%u\n", dead_srv->name, dead_srv->img_type);
138 if (is_build_in_service(&dead_srv->property.uuid) || dead_srv->img_type == IMG_TYPE_DYNAMIC_SRV) {
139 (void)memcpy_s(&uuid, sizeof(TEE_UUID), &dead_srv->property.uuid, sizeof(TEE_UUID));
140 (void)memcpy_s(&dyn_srv, sizeof(struct service_struct), dead_srv, sizeof(struct service_struct));
141 process_release_service(dead_srv, TA_REGION_FOR_REUSE);
142 if (dead_srv->img_type == IMG_TYPE_DYNAMIC_SRV)
143 load_dynamic_service(&dyn_srv);
144 else
145 load_internal_task(&uuid);
146 } else {
147 process_release_service(dead_srv, TA_REGION_RELEASE);
148 }
149 }
150
try_release_exception_srv(struct service_struct * srv)151 static void try_release_exception_srv(struct service_struct *srv)
152 {
153 struct session_struct *sess_context = NULL;
154 struct session_struct *sess_tmp = NULL;
155
156 recycle_srvc_thread(srv);
157 srv->is_service_dead = true;
158 dlist_for_each_entry_safe(sess_context, sess_tmp, &(srv->session_head), struct session_struct, session_list)
159 {
160 TEE_Result ret = try_release_session(srv, sess_context);
161 if (ret != TEE_SUCCESS)
162 tloge("try release session failed, ret=0x%x\n", ret);
163 }
164
165 /* session_count 0 means all sessions have beed released */
166 if (srv->session_count == 0) {
167 release_service(srv);
168 } else {
169 tlogi("will release service %s later, still have %d session to release\n", srv->name, srv->session_count);
170 }
171 }
172
try_release_dead_father(uint32_t task_id)173 static void try_release_dead_father(uint32_t task_id)
174 {
175 struct service_struct *service = NULL;
176 struct session_struct *session = NULL;
177
178 if (!find_task_dead(task_id, &service, &session)) {
179 tloge("find father ta 0x%x failed\n", task_id);
180 return;
181 }
182
183 if (session->session_status != TA_STATUS_SELF_DEAD) {
184 tloge("something wrong, father ta 0x%x is not dead\n", task_id);
185 return;
186 }
187
188 if (!dlist_empty(&session->child_ta_sess_head)) {
189 tloge("father ta 0x%x still have child session, will release later\n", task_id);
190 return;
191 }
192
193 TEE_Result ret = release_cur_session(service, session);
194 if (ret != TEE_SUCCESS) {
195 tloge("release dead father failed, task id is 0x%x\n", task_id);
196 return;
197 }
198
199 if (service->session_count == 0)
200 release_service(service);
201 }
202
ta_exception_handle_ack(int32_t sess_status,uint32_t task_id,uint32_t father_task_id)203 void ta_exception_handle_ack(int32_t sess_status, uint32_t task_id, uint32_t father_task_id)
204 {
205 struct service_struct *service = NULL;
206 struct session_struct *session = NULL;
207
208 if (sess_status == TA_STATUS_NORMAL)
209 return;
210
211 if (sess_status == TA_STATUS_SELF_DEAD) {
212 tloge("something wrong, dead ta 0x%x can not send ack\n", task_id);
213 return;
214 }
215
216 /* handle TA_STATUS_FATHER_DEAD */
217 if (find_task(task_id, &service, &session)) {
218 /* because its father is dead, we will close this session async */
219 if (close_session_async(session) != TEE_SUCCESS)
220 tloge("close session 0x%x async failed\n", session->session_id);
221 } else {
222 /* cur session has been closed, we will try release its dead father */
223 try_release_dead_father(father_task_id);
224 }
225 }
226
process_ta_agent_ack(struct service_struct * srv,struct session_struct * sess)227 static void process_ta_agent_ack(struct service_struct *srv, struct session_struct *sess)
228 {
229 if (sess->session_status != TA_STATUS_SELF_DEAD) {
230 tloge("something wrong, task 0x%x is not dead\n", sess->task_id);
231 return;
232 }
233
234 sess->agent_pending = false;
235 TEE_Result ret = try_release_session(srv, sess);
236 if (ret != TEE_SUCCESS)
237 tloge("try release session failed, ret=0x%x\n", ret);
238
239 if (srv->session_count == 0)
240 release_service(srv);
241 }
242
ta_exception_handle_buildin_agent_ack(uint32_t task_id)243 void ta_exception_handle_buildin_agent_ack(uint32_t task_id)
244 {
245 struct service_struct *srv = NULL;
246 struct session_struct *sess = NULL;
247
248 if (!find_task_dead(task_id, &srv, &sess)) {
249 tloge("find dead task 0x%x failed\n", task_id);
250 return;
251 }
252 process_ta_agent_ack(srv, sess);
253 }
254
ta_exception_handle_agent_ack(const smc_cmd_t * cmd)255 TEE_Result ta_exception_handle_agent_ack(const smc_cmd_t *cmd)
256 {
257 const TEE_UUID *uuid = NULL;
258 struct service_struct *srv = NULL;
259 struct session_struct *sess = NULL;
260
261 if (cmd == NULL)
262 return TEE_ERROR_BAD_PARAMETERS;
263
264 uuid = (const TEE_UUID *)(uintptr_t)cmd->uuid;
265 srv = find_service_dead(uuid, service_index_of_context(cmd->context));
266 if (srv == NULL) {
267 tloge("dead service not found uuid = %x-%x\n", uuid->timeLow, uuid->timeMid);
268 return TEE_ERROR_SERVICE_NOT_EXIST;
269 }
270
271 sess = find_session_with_dev_file_id(session_id_of_context(cmd->context), cmd->dev_file_id, srv);
272 if (sess == NULL) {
273 tloge("session[%u] not exist in service[%s]\n", session_id_of_context(cmd->context), srv->name);
274 return TEE_ERROR_SESSION_NOT_EXIST;
275 }
276
277 process_ta_agent_ack(srv, sess);
278 return TEE_SUCCESS;
279 }
280
find_block_child_session(const struct session_struct * father_sess)281 static struct session_struct *find_block_child_session(const struct session_struct *father_sess)
282 {
283 struct session_struct *child_sess = NULL;
284 struct session_struct *grandson_sess = NULL;
285
286 dlist_for_each_entry(child_sess, &(father_sess->child_ta_sess_head), struct session_struct, child_ta_sess_list)
287 {
288 /* find a block child */
289 if (child_sess->wait_ta_back_msg) {
290 grandson_sess = find_block_child_session(child_sess);
291 if (grandson_sess != NULL)
292 return grandson_sess;
293 else
294 return child_sess;
295 }
296 }
297 return NULL;
298 }
299
check_core_service(const TEE_UUID * uuid)300 static bool check_core_service(const TEE_UUID *uuid)
301 {
302 return is_gtask_by_uuid(uuid) || is_internal_task_by_uuid(uuid);
303 }
304
process_kill_task(struct service_struct * srv,const struct session_struct * sess)305 static TEE_Result process_kill_task(struct service_struct *srv, const struct session_struct *sess)
306 {
307 struct session_struct *child_sess = NULL;
308 struct service_struct *block_srv = NULL;
309
310 if (srv == NULL || sess == NULL) {
311 tloge("process kill task error, invalid param\n");
312 return TEE_ERROR_BAD_PARAMETERS;
313 }
314
315 if (check_core_service(&srv->property.uuid)) {
316 tloge("process kill task error, can not kill a core service\n");
317 return TEE_ERROR_BAD_PARAMETERS;
318 }
319
320 tlogi("start process kill task, block task name=%s, session id=0x%x, ca pid=%u\n", srv->name, sess->session_id,
321 sess->cmd_in.ca_pid);
322
323 if (sess->agent_pending) {
324 tloge("killing a agent pending ta or dyn svc, delay it, cmd id = 0x%x\n", sess->cmd_in.cmd_id);
325 return TEE_ERROR_BUSY;
326 }
327
328 if (!sess->wait_ta_back_msg) {
329 tloge("unexpected status:sess is not running\n");
330 return TEE_ERROR_BAD_STATE;
331 }
332
333 child_sess = find_block_child_session(sess);
334 if (child_sess != NULL) {
335 /* if child_sess block, we kill child TA */
336 block_srv = find_service_by_task_id(child_sess->task_id);
337 if (block_srv == NULL) {
338 tloge("find child block srv failed, task id 0x%x\n", child_sess->task_id);
339 return TEE_ERROR_SERVICE_NOT_EXIST;
340 }
341 tlogi("find child TA block, start kill task %s\n", block_srv->name);
342 } else {
343 /* if no child_sess block, that means cur TA block, we kill cur TA */
344 block_srv = srv;
345 }
346 try_release_exception_srv(block_srv);
347 return TEE_SUCCESS;
348 }
349
handle_kill_task(const smc_cmd_t * cmd)350 int32_t handle_kill_task(const smc_cmd_t *cmd)
351 {
352 struct service_struct *srv = NULL;
353 struct session_struct *sess = NULL;
354
355 if (cmd == NULL) {
356 tloge("handle kill task error, invalid param\n");
357 return GT_ERR_END_CMD;
358 }
359
360 tlogi("receive kill task msg\n");
361
362 const TEE_UUID *uuid = (const TEE_UUID *)(uintptr_t)cmd->uuid;
363 if (find_service(uuid, service_index_of_context(cmd->context), &srv) == -1) {
364 tloge("find normal service failed, try to find dead service, uuid = %x-%x\n", uuid->timeLow, uuid->timeMid);
365 /* in case of multi ta have exception at the same time */
366 srv = find_service_dead(uuid, service_index_of_context(cmd->context));
367 if (srv == NULL) {
368 tloge("find dead service failed, return error\n");
369 return GT_ERR_END_CMD;
370 }
371 }
372
373 sess = find_session_with_dev_file_id(session_id_of_context(cmd->context), cmd->dev_file_id, srv);
374 if (sess == NULL) {
375 tloge("find session %u failed in service %s\n", session_id_of_context(cmd->context), srv->name);
376 return GT_ERR_END_CMD;
377 }
378 if (process_kill_task(srv, sess) != TEE_SUCCESS)
379 return GT_ERR_END_CMD;
380
381 return GT_ERR_OK;
382 }
383
process_task_crash(uint32_t cmd_id,uint32_t task_id,const uint8_t * msg_buf,uint32_t msg_size)384 int32_t process_task_crash(uint32_t cmd_id, uint32_t task_id, const uint8_t *msg_buf,
385 uint32_t msg_size)
386 {
387 uint32_t crash_task_id;
388
389 (void)cmd_id;
390 /* check msg sender */
391 if (!is_sys_task(task_id)) {
392 tloge("recv task crash msg from wrong sender 0x%x\n", task_id);
393 return GT_ERR_END_CMD;
394 }
395
396 if (msg_buf == NULL || msg_size < sizeof(crash_task_id)) {
397 tloge("recv task crash msg error, msg size is %u\n", msg_size);
398 return GT_ERR_END_CMD;
399 }
400
401 crash_task_id = *(const uint32_t *)(uintptr_t)msg_buf;
402
403 /* check service exist & valid */
404 struct service_struct *crash_srv = find_service_by_task_id(crash_task_id);
405 if (crash_srv == NULL || is_gtask_by_uuid(&(crash_srv->property.uuid))) {
406 tloge("process task crash failed: invalid task id 0x%x\n", crash_task_id);
407 tee_drv_task_exit(crash_task_id);
408 return GT_ERR_END_CMD;
409 }
410
411 tlogi("recv task crash msg, task_name=%s, task_id=0x%x\n", crash_srv->name, crash_task_id);
412
413 try_release_exception_srv(crash_srv);
414
415 /* if internal task crash, we should call callback */
416 if (is_internal_task_by_task_id(crash_task_id)) {
417 tloge("internal task crash\n");
418 task_adapt_crash_callback(crash_task_id);
419 }
420 return GT_ERR_OK;
421 }
422