• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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