1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "cmdmonitor.h"
33 #include <securec.h>
34 #include "smc.h"
35 #include "tc_ns_log.h"
36 #include "tzdriver_compat.h"
37
38 const char g_cmdMonitorWhiteTable[][TASK_COMM_LEN] = {
39 #ifdef DEF_ENG
40 {"tee_test_ut"},
41 #endif
42 };
43 const uint32_t g_whiteTableThreadNum = sizeof(g_cmdMonitorWhiteTable) /
44 TASK_COMM_LEN;
45
46 static int g_cmdNeedArchiveLog = 0;
47 static LINUX_LIST_HEAD(g_cmdMonitorList);
48 static int g_cmdMonitorListSize = 0;
49 /* report 2 hours */
50 #define MAX_CMD_MONITOR_LIST 200
51 #define MAX_AGENT_CALL_COUNT 250
52 static DEFINE_MUTEX(g_cmdMonitorLock);
53 struct CmdMonitor {
54 struct list_head list;
55 struct timespec sendTime;
56 int count;
57 bool returned;
58 bool isReported;
59 int pid;
60 int tid;
61 char pName[TASK_COMM_LEN];
62 char tName[TASK_COMM_LEN];
63 unsigned int lastCmdId;
64 long long timeTotal;
65 int agentCallCount;
66 };
67 static struct delayed_work g_cmdMonitorWork;
68 static struct delayed_work g_cmdMonitorWorkArchive;
69 static int g_teeDetectTaCrash = 0;
70 enum {
71 TYPE_CRASH_TA = 1,
72 TYPE_CRASH_TEE = 2,
73 };
74
TzDebugArchiveLog(void)75 void TzDebugArchiveLog(void)
76 {
77 schedule_delayed_work(&g_cmdMonitorWorkArchive, MsecsToJiffies(0));
78 }
79
CmdMonitorTaCrash(int32_t type)80 void CmdMonitorTaCrash(int32_t type)
81 {
82 g_teeDetectTaCrash = ((type == TYPE_CRASH_TEE) ? TYPE_CRASH_TEE :
83 TYPE_CRASH_TA);
84 TzDebugArchiveLog();
85 }
86
IsThreadInWhiteTable(const char * tName)87 static bool IsThreadInWhiteTable(const char *tName)
88 {
89 uint32_t i;
90
91 if (tName == NULL) {
92 return false;
93 }
94
95 for (i = 0; i < g_whiteTableThreadNum; i++) {
96 if (!strcmp(tName, g_cmdMonitorWhiteTable[i])) {
97 return true;
98 }
99 }
100 return false;
101 }
102
IsThreadReported(unsigned int tid)103 bool IsThreadReported(unsigned int tid)
104 {
105 bool ret = false;
106 struct CmdMonitor *monitor = NULL;
107
108 mutex_lock(&g_cmdMonitorLock);
109 list_for_each_entry(monitor, &g_cmdMonitorList, list) {
110 if (monitor->tid == tid) {
111 ret = (monitor->isReported ||
112 monitor->agentCallCount > MAX_AGENT_CALL_COUNT);
113 break;
114 }
115 }
116 mutex_unlock(&g_cmdMonitorLock);
117 return ret;
118 }
119
CmdMonitorResetContext(void)120 void CmdMonitorResetContext(void)
121 {
122 struct CmdMonitor *monitor = NULL;
123 int pid = OsCurrTaskGet()->processID;
124 int tid = OsCurrTaskGet()->taskID;
125
126 mutex_lock(&g_cmdMonitorLock);
127 list_for_each_entry(monitor, &g_cmdMonitorList, list) {
128 if (monitor->pid == pid && monitor->tid == tid) {
129 monitor->sendTime = CurrentKernelTime();
130 if (monitor->agentCallCount + 1 < 0) {
131 tloge("agent call count add overflow\n");
132 } else {
133 monitor->agentCallCount++;
134 }
135 break;
136 }
137 }
138 mutex_unlock(&g_cmdMonitorLock);
139 }
140
CmdMonitorTick(void)141 static void CmdMonitorTick(void)
142 {
143 long long timeDif;
144 struct CmdMonitor *monitor = NULL;
145 struct CmdMonitor *tmp = NULL;
146 struct timespec nowTime = CurrentKernelTime();
147
148 mutex_lock(&g_cmdMonitorLock);
149 list_for_each_entry_safe(monitor, tmp, &g_cmdMonitorList, list) {
150 if (monitor->returned == true) {
151 g_cmdMonitorListSize--;
152 tloge("[CmdMonitorTick] pid:%d, pName:%s, tid:%d, tName:%s, \
153 lastCmdId:%u, count:%d, agent call count:%d, timeTotal:%lld us returned, remained command(s):%d\n",
154 monitor->pid, monitor->pName, monitor->tid,
155 monitor->tName, monitor->lastCmdId,
156 monitor->count, monitor->agentCallCount,
157 monitor->timeTotal, g_cmdMonitorListSize);
158 list_del(&monitor->list);
159 free(monitor);
160 monitor = NULL;
161 continue;
162 }
163 /* not return, we need to check */
164
165 /*
166 * get time value D (timeDif=nowTime-sendTime), we do not care about overflow
167 * 1 year means 1000 * (60*60*24*365) = 0x757B12C00
168 * only 5bytes, will not overflow
169 */
170 timeDif = MSEC_PER_SEC * (nowTime.tv_sec - monitor->sendTime.tv_sec) +
171 (nowTime.tv_nsec - monitor->sendTime.tv_nsec) / NSEC_PER_MSEC;
172
173 /* Temporally change timeout to 25s, we log the teeos log,and report */
174 if ((timeDif > TEMPORALLY_CHAGE_TIMEOUT) && (!monitor->isReported)) {
175 monitor->isReported = true;
176 /* print tee stask */
177 tloge("[CmdMonitorTick] pid:%d, pName:%s, tid:%d, tName:%s, \
178 lastCmdId:%u, agent call count:%d, timeDif:%lld ms and report\n",
179 monitor->pid, monitor->pName, monitor->tid,
180 monitor->tName, monitor->lastCmdId,
181 monitor->agentCallCount, timeDif);
182 /* threads out of white table need info dump */
183 if (!(IsThreadInWhiteTable(monitor->tName))) {
184 ShowCmdBitmapWithLock();
185 g_cmdNeedArchiveLog = 1;
186 WakeupTcSiq();
187 }
188 } else if (timeDif > 1 * MSEC_PER_SEC) {
189 tloge("[CmdMonitorTick] pid=%d, pName=%s, tid=%d, \
190 lastCmdId=%u, agent call count:%d, timeDif=%lld ms\n",
191 monitor->pid, monitor->pName, monitor->tid,
192 monitor->lastCmdId, monitor->agentCallCount,
193 timeDif);
194 }
195 }
196 if (g_cmdMonitorListSize > 0) {
197 /* if have cmd in monitor list, we need tick */
198 schedule_delayed_work(&g_cmdMonitorWork, MsecsToJiffies(MSEC_PER_SEC));
199 }
200 mutex_unlock(&g_cmdMonitorLock);
201 }
CmdMonitorTickfn(struct work_struct * work)202 static void CmdMonitorTickfn(struct work_struct *work)
203 {
204 (void)(work);
205 CmdMonitorTick();
206 }
207
CmdMonitorArchivefn(struct work_struct * work)208 static void CmdMonitorArchivefn(struct work_struct *work)
209 {
210 (void)(work);
211 }
212
InitMonitorLocked(void)213 static struct CmdMonitor *InitMonitorLocked(void)
214 {
215 struct CmdMonitor *newItem = NULL;
216
217 newItem = calloc(1, sizeof(*newItem));
218 if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)newItem)) {
219 tloge("[CmdMonitorTick]calloc failed\n");
220 return NULL;
221 }
222 newItem->sendTime = CurrentKernelTime();
223 newItem->count = 1;
224 newItem->agentCallCount = 0;
225 newItem->returned = false;
226 newItem->isReported = false;
227 newItem->pid = OsCurrTaskGet()->processID;
228 newItem->tid = OsCurrTaskGet()->taskID;
229
230 LosProcessCB *runProcess = OS_PCB_FROM_PID(newItem->pid);
231 if (strncpy_s(newItem->pName, TASK_COMM_LEN, runProcess->processName, OS_PCB_NAME_LEN) != EOK) {
232 free(newItem);
233 newItem = NULL;
234 return NULL;
235 }
236 if (strncpy_s(newItem->tName, TASK_COMM_LEN, OsCurrTaskGet()->taskName, OS_TCB_NAME_LEN) != EOK) {
237 free(newItem);
238 newItem = NULL;
239 return NULL;
240 }
241 INIT_LIST_HEAD(&newItem->list);
242 list_add_tail(&newItem->list, &g_cmdMonitorList);
243 g_cmdMonitorListSize++;
244 return newItem;
245 }
246
CmdMonitorLog(const TcNsSmcCmd * cmd)247 void CmdMonitorLog(const TcNsSmcCmd *cmd)
248 {
249 int foundFlag = 0;
250 int pid;
251 int tid;
252 struct CmdMonitor *monitor = NULL;
253 struct CmdMonitor *newItem = NULL;
254
255 if (cmd == NULL) {
256 return;
257 }
258 pid = OsCurrTaskGet()->processID;
259 tid = OsCurrTaskGet()->taskID;
260 mutex_lock(&g_cmdMonitorLock);
261 do {
262 list_for_each_entry(monitor, &g_cmdMonitorList, list) {
263 if (monitor->pid == pid && monitor->tid == tid) {
264 foundFlag = 1;
265 /* restart */
266 monitor->sendTime = CurrentKernelTime();
267 monitor->count++;
268 monitor->returned = false;
269 monitor->isReported = false;
270 monitor->lastCmdId = cmd->cmdId;
271 monitor->agentCallCount = 0;
272 break;
273 }
274 }
275 if (foundFlag == 0) {
276 if (g_cmdMonitorListSize > MAX_CMD_MONITOR_LIST - 1) {
277 tloge("[CmdMonitorTick]MAX_CMD_MONITOR_LIST\n");
278 break;
279 }
280 newItem = InitMonitorLocked();
281 if (newItem == NULL) {
282 tloge("[CmdMonitorTick]init_monitor failed\n");
283 break;
284 }
285 newItem->lastCmdId = cmd->cmdId;
286 /* the first cmd will cause timer */
287 if (g_cmdMonitorListSize == 1) {
288 schedule_delayed_work(&g_cmdMonitorWork,
289 MsecsToJiffies(MSEC_PER_SEC));
290 }
291 }
292 } while (0);
293 mutex_unlock(&g_cmdMonitorLock);
294 }
295
CmdMonitorLogend(void)296 void CmdMonitorLogend(void)
297 {
298 int pid;
299 int tid;
300 struct CmdMonitor *monitor = NULL;
301
302 pid = OsCurrTaskGet()->processID;
303 tid = OsCurrTaskGet()->taskID;
304 mutex_lock(&g_cmdMonitorLock);
305 list_for_each_entry(monitor, &g_cmdMonitorList, list) {
306 if (monitor->pid == pid && monitor->tid == tid &&
307 monitor->returned == false) {
308 struct timespec nowTime = CurrentKernelTime();
309 /*
310 * get time value D (timeDif=nowTime-sendTime), we do not care about overflow
311 * 1 year means 1000000 * (60*60*24*365) = 0x1CAE8C13E000
312 * only 6bytes, will not overflow
313 */
314 long long timeDif = USEC_PER_SEC *
315 (nowTime.tv_sec - monitor->sendTime.tv_sec) +
316 (nowTime.tv_nsec - monitor->sendTime.tv_nsec) / NSEC_PER_USEC;
317 monitor->timeTotal += timeDif;
318 monitor->returned = true;
319 break;
320 }
321 }
322 mutex_unlock(&g_cmdMonitorLock);
323 }
324
DoCmdNeedArchivelog(void)325 void DoCmdNeedArchivelog(void)
326 {
327 if (g_cmdNeedArchiveLog == 1) {
328 g_cmdNeedArchiveLog = 0;
329 schedule_delayed_work(&g_cmdMonitorWorkArchive,
330 MsecsToJiffies(MSEC_PER_SEC));
331 }
332 }
InitCmdMonitor(void)333 void InitCmdMonitor(void)
334 {
335 InitDeferrableWork((struct delayed_work *)(uintptr_t)&g_cmdMonitorWork, CmdMonitorTickfn);
336 InitDeferrableWork((struct delayed_work *)(uintptr_t)&g_cmdMonitorWorkArchive, CmdMonitorArchivefn);
337 }
338