1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "code_signature_analysis_kit.h"
17 #include <pthread.h>
18 #include <stdint.h>
19 #include <securec.h>
20
21 ModelManagerApi *g_securityGuardFunc = NULL;
22 ModelApi *g_modelFunc = NULL;
23 RetListener g_retListener = NULL;
24 AppRiskInfo *g_modelDataHead = NULL;
25 uint32_t g_riskAppCount = 0;
26 pthread_mutex_t g_modelVisitLock;
27 #define MAX_RISK_APP_COUNT (1024 * 100)
28
FindExistingNode(uint32_t tokenId)29 static AppRiskInfo *FindExistingNode(uint32_t tokenId)
30 {
31 AppRiskInfo *node = g_modelDataHead->next;
32 while (node != NULL) {
33 if (node->tokenId == tokenId) {
34 break;
35 } else {
36 node = node->next;
37 }
38 }
39 return node;
40 }
41
IsRiskStatusChanged(AppRiskInfo * node)42 static int32_t IsRiskStatusChanged(AppRiskInfo *node)
43 {
44 int64_t totalCount = 0;
45 int32_t eventCount = 0;
46 RiskPolicyType policy = node->status.policy;
47
48 for (int32_t i = 0; i < CODE_SIGNATURE_ERROR_TYPE_SIZE; i++) {
49 TimeStampNode *tmp = ((node->errInfoList)[i]).timeStampChain;
50 totalCount += tmp->timeStamp.timeStampCount;
51 eventCount += (tmp->timeStamp.timeStampCount != 0) ? 1 : 0;
52 }
53 node->status.eventCount = eventCount;
54 node->status.totalCount = totalCount;
55 if ((totalCount > MAX_CODE_SIGNATURE_ERROR_NUM) || (eventCount == CODE_SIGNATURE_ERROR_TYPE_SIZE)) {
56 node->status.policy = LOG_REPORT;
57 } else {
58 node->status.policy = NO_SECURITY_RISK;
59 }
60
61 int32_t isChanged = (node->status.policy != policy) ? STATUS_CHANGED : STATUS_NOT_CHANGED;
62 if ((node->status.policy == NO_SECURITY_RISK) && (policy != NO_SECURITY_RISK)) {
63 if (g_riskAppCount > 0) {
64 g_riskAppCount--;
65 }
66 MODEL_LOG_INFO("[%s]:g_riskAppCount reduced.", __func__);
67 } else if ((node->status.policy != NO_SECURITY_RISK) && (policy == NO_SECURITY_RISK)) {
68 if (g_riskAppCount < MAX_RISK_APP_COUNT) {
69 g_riskAppCount++;
70 }
71 MODEL_LOG_INFO("[%s]:g_riskAppCount added.", __func__);
72 }
73 return isChanged;
74 }
75
DataPreProcess(const CodeSignatureReportedInfo * report,AppRiskInfo * node,uint32_t optType)76 static int32_t DataPreProcess(const CodeSignatureReportedInfo *report,
77 AppRiskInfo *node,
78 uint32_t optType)
79 {
80 TimeStampNode *head = ((node->errInfoList)[report->errorType]).timeStampChain;
81 if (optType == OUT_OF_STORAGE_LIFE) {
82 TimeStampNode *tmpNode = head->next;
83 TimeStampNode *tmpNodePrev = head;
84 while ((tmpNode != NULL) && (tmpNode->timeStamp.timeStampMs > report->timeStampMs)) {
85 tmpNode = tmpNode->next;
86 tmpNodePrev = tmpNodePrev->next;
87 }
88 tmpNodePrev->next = NULL;
89 // Delete all the event timestamps which are out of storage life.
90 while (tmpNode != NULL) {
91 TimeStampNode *deleted = tmpNode;
92 tmpNode = tmpNode->next;
93 free(deleted);
94 deleted = NULL;
95 head->timeStamp.timeStampCount--;
96 }
97 return OPER_SUCCESS;
98 }
99
100 // Insert the newest report timestamp in the chain head.
101 if (optType == EVENT_REPORTED) {
102 TimeStampNode *tmp = NULL;
103 tmp = (TimeStampNode *)malloc(sizeof(TimeStampNode));
104 if (tmp == NULL) {
105 MODEL_LOG_ERROR("[%s]:malloc failed.", __func__);
106 return MEMORY_OPER_FAILED;
107 }
108 (void)memset_s(tmp, sizeof(TimeStampNode), 0, sizeof(TimeStampNode));
109 tmp->timeStamp.timeStampMs = report->timeStampMs;
110 tmp->next = head->next;
111 head->next = tmp;
112 head->timeStamp.timeStampCount++;
113 }
114 return OPER_SUCCESS;
115 }
116
AppRiskInfoNodeInit(void)117 static AppRiskInfo *AppRiskInfoNodeInit(void)
118 {
119 AppRiskInfo *node = (AppRiskInfo *)malloc(sizeof(AppRiskInfo));
120 if (node == NULL) {
121 MODEL_LOG_ERROR("[%s]:malloc failed.", __func__);
122 return NULL;
123 }
124 (void)memset_s(node, sizeof(AppRiskInfo), 0, sizeof(AppRiskInfo));
125
126 TimeStampNode *tmp = NULL;
127 tmp = (TimeStampNode *)malloc(sizeof(TimeStampNode) * CODE_SIGNATURE_ERROR_TYPE_SIZE);
128 if (tmp == NULL) {
129 MODEL_LOG_ERROR("[%s]:malloc failed.", __func__);
130 free(node);
131 return NULL;
132 }
133 (void)memset_s(tmp, sizeof(TimeStampNode) * CODE_SIGNATURE_ERROR_TYPE_SIZE,
134 0, sizeof(TimeStampNode) * CODE_SIGNATURE_ERROR_TYPE_SIZE);
135
136 for (int32_t i = 0; i < CODE_SIGNATURE_ERROR_TYPE_SIZE; i++) {
137 tmp[i].next = NULL;
138 tmp[i].timeStamp.timeStampCount = 0;
139 (node->errInfoList[i]).timeStampChain = &(tmp[i]);
140 }
141 node->status.eventCount = 0;
142 node->status.totalCount = 0;
143 node->status.policy = NO_SECURITY_RISK;
144 node->next = g_modelDataHead->next;
145 g_modelDataHead->next = node;
146 return node;
147 }
148
ReleaseTimeStampChain(AppRiskInfo * node)149 static void ReleaseTimeStampChain(AppRiskInfo *node)
150 {
151 for (int32_t i = 0; i < CODE_SIGNATURE_ERROR_TYPE_SIZE; i++) {
152 TimeStampNode *head = (node->errInfoList[i]).timeStampChain->next;
153 while (head != NULL) {
154 TimeStampNode *tmp = head->next;
155 free(head);
156 head = tmp;
157 }
158 }
159 // Free timeStampChain head for each error type. They was allocated together.
160 free(node->errInfoList[0].timeStampChain);
161 return;
162 }
163
SetResultInfoAccordingToNode(NotifyRiskResultInfo * result,AppRiskInfo * node)164 static void SetResultInfoAccordingToNode(NotifyRiskResultInfo *result, AppRiskInfo *node)
165 {
166 result->eventId = APPLICATION_RISK_EVENT_ID;
167 result->tokenId = node->tokenId;
168 result->policy = node->status.policy;
169 }
170
UpdateInfoInCurrNode(const CodeSignatureReportedInfo * report,AppRiskInfo * node,uint32_t optType)171 static int32_t UpdateInfoInCurrNode(const CodeSignatureReportedInfo *report, AppRiskInfo *node, uint32_t optType)
172 {
173 int32_t res = DataPreProcess(report, node, optType);
174 if (res != OPER_SUCCESS) {
175 return res;
176 }
177 res = IsRiskStatusChanged(node);
178 if (g_riskAppCount >= MAX_RISK_APP_COUNT) {
179 return RISK_APP_NUM_EXCEEDED;
180 }
181 if (res == STATUS_NOT_CHANGED) {
182 return OPER_SUCCESS;
183 }
184 if (g_retListener == NULL) {
185 return OPER_SUCCESS;
186 }
187 /* Notify the SG db about APPLICATION_RISK_EVENT_ID change */
188 NotifyRiskResultInfo *result = (NotifyRiskResultInfo *)malloc(sizeof(NotifyRiskResultInfo));
189 if (result == NULL) {
190 MODEL_LOG_ERROR("[%s]:malloc failed.", __func__);
191 return MEMORY_OPER_FAILED;
192 }
193 (void)memset_s(result, sizeof(NotifyRiskResultInfo), 0, sizeof(NotifyRiskResultInfo));
194 SetResultInfoAccordingToNode(result, node);
195
196 // Notify the change.
197 g_retListener((uint8_t *)result, sizeof(NotifyRiskResultInfo));
198 free(result);
199 return OPER_SUCCESS;
200 }
201
AddNewAppInfoNode(const CodeSignatureReportedInfo * report,uint32_t optType)202 static int32_t AddNewAppInfoNode(const CodeSignatureReportedInfo *report, uint32_t optType)
203 {
204 AppRiskInfo *node = AppRiskInfoNodeInit();
205 if (node == NULL) {
206 return MEMORY_OPER_FAILED;
207 }
208
209 node->tokenId = report->tokenId;
210 int32_t res = strcpy_s(node->bundleName, MAX_BUNDLE_NAME_LENGTH - 1, report->bundleName);
211 if (res != OPER_SUCCESS) {
212 MODEL_LOG_ERROR("[%s]:strcpy_s failed errno %d.", __func__, errno);
213 ReleaseTimeStampChain(node);
214 free(node);
215 return res;
216 }
217
218 res = DataPreProcess(report, node, optType);
219 if (res != OPER_SUCCESS) {
220 ReleaseTimeStampChain(node);
221 free(node);
222 return res;
223 }
224
225 (void)IsRiskStatusChanged(node);
226 return OPER_SUCCESS;
227 }
228
DataProcess(const CodeSignatureReportedInfo * report,uint32_t optType)229 static int32_t DataProcess(const CodeSignatureReportedInfo *report, uint32_t optType)
230 {
231 if (report->tokenId == INVALID_TOKEN_ID) {
232 MODEL_LOG_ERROR("[%s]:tokenId is invalid.", __func__);
233 return INPUT_TOKEN_ID_INVALID;
234 }
235 if (report->errorType >= CODE_SIGNATURE_ERROR_TYPE_BUFF) {
236 MODEL_LOG_ERROR("[%s]:errorType %d is invalid.", __func__, report->errorType);
237 return INPUT_EVENT_TYPE_INVALID;
238 }
239 if (optType >= DATA_CHANGE_TYPE_BUFF) {
240 MODEL_LOG_ERROR("[%s]:optType %u is invalid.", __func__, optType);
241 return INPUT_OPER_TYPE_INVALID;
242 }
243
244 (void)pthread_mutex_lock(&g_modelVisitLock);
245 if (g_modelDataHead == NULL) {
246 MODEL_LOG_ERROR("[%s]:model is released.", __func__);
247 (void)pthread_mutex_unlock(&g_modelVisitLock);
248 return MODEL_INIT_NOT_COMPLETED;
249 }
250 AppRiskInfo *node = FindExistingNode(report->tokenId);
251 if (node != NULL) {
252 int32_t res = UpdateInfoInCurrNode(report, node, optType);
253 (void)pthread_mutex_unlock(&g_modelVisitLock);
254 return res;
255 }
256
257 // The deleted data is not in model cache already.
258 if (optType == OUT_OF_STORAGE_LIFE) {
259 (void)pthread_mutex_unlock(&g_modelVisitLock);
260 return OPER_SUCCESS;
261 }
262
263 int32_t res = AddNewAppInfoNode(report, optType);
264 (void)pthread_mutex_unlock(&g_modelVisitLock);
265
266 return res;
267 }
268
DatabaseListener(uint32_t optType,uint8_t * result,uint32_t resultLen)269 static void DatabaseListener(uint32_t optType, uint8_t *result, uint32_t resultLen)
270 {
271 if ((result == NULL) || (resultLen != sizeof(CodeSignatureReportedInfo))) {
272 MODEL_LOG_ERROR("[%s]:ResultLen %u.", __func__, resultLen);
273 return;
274 }
275
276 CodeSignatureReportedInfo *report = (CodeSignatureReportedInfo *)result;
277 int32_t res = DataProcess(report, optType);
278 if (res != OPER_SUCCESS) {
279 MODEL_LOG_ERROR("[%s]:DataProcess failed. Res %d.", __func__, res);
280 }
281 return;
282 }
283
Init(ModelManagerApi * api)284 int32_t Init(ModelManagerApi *api)
285 {
286 if (api == NULL) {
287 MODEL_LOG_ERROR("[%s]:Input api func is null.", __func__);
288 return INPUT_POINT_NULL;
289 }
290
291 (void)pthread_mutex_lock(&g_modelVisitLock);
292 if (g_modelDataHead != NULL) {
293 MODEL_LOG_ERROR("[%s]:Init has been completed already.", __func__);
294 (void)pthread_mutex_unlock(&g_modelVisitLock);
295 return INIT_OPER_REPEAT;
296 }
297 g_securityGuardFunc = api;
298
299 g_modelDataHead = (AppRiskInfo *)malloc(sizeof(AppRiskInfo));
300 if (g_modelDataHead == NULL) {
301 MODEL_LOG_ERROR("[%s]:malloc failed.", __func__);
302 (void)pthread_mutex_unlock(&g_modelVisitLock);
303 return MEMORY_OPER_FAILED;
304 }
305 (void)memset_s(g_modelDataHead, sizeof(AppRiskInfo), 0, sizeof(AppRiskInfo));
306 g_modelDataHead->next = NULL;
307
308 // Set the func where to subscribe the db change.
309 int64_t csErrEventId = CODE_SIGNATURE_ERROR_EVENT_ID;
310 uint32_t eventIdLen = 1;
311 g_securityGuardFunc->subscribeDb(&csErrEventId, eventIdLen, DatabaseListener);
312
313 (void)pthread_mutex_unlock(&g_modelVisitLock);
314 return OPER_SUCCESS;
315 }
316
Release(void)317 void Release(void)
318 {
319 (void)pthread_mutex_lock(&g_modelVisitLock);
320 if (g_modelDataHead == NULL) {
321 MODEL_LOG_ERROR("[%s]:Model has been release already.", __func__);
322 (void)pthread_mutex_unlock(&g_modelVisitLock);
323 return;
324 }
325
326 while (g_modelDataHead->next != NULL) {
327 AppRiskInfo *node = g_modelDataHead->next;
328 g_modelDataHead->next = node->next;
329 ReleaseTimeStampChain(node);
330 free(node);
331 }
332 free(g_modelDataHead);
333 g_modelDataHead = NULL;
334 g_retListener = NULL;
335 g_securityGuardFunc = NULL;
336 g_riskAppCount = 0;
337
338 (void)pthread_mutex_unlock(&g_modelVisitLock);
339 return;
340 }
341
GetResult(uint8_t * result,uint32_t * resultLen)342 int32_t GetResult(uint8_t *result, uint32_t *resultLen)
343 {
344 if (result == NULL) {
345 return INPUT_POINT_NULL;
346 }
347
348 (void)pthread_mutex_lock(&g_modelVisitLock);
349 if (g_modelDataHead == NULL) {
350 (void)pthread_mutex_unlock(&g_modelVisitLock);
351 return MODEL_INIT_NOT_COMPLETED;
352 }
353
354 unsigned long long neededLen = g_riskAppCount * sizeof(NotifyRiskResultInfo);
355 if (*resultLen < neededLen) {
356 MODEL_LOG_ERROR("[%s]:ResultLen %u is smaller than needed %llu", __func__, *resultLen, neededLen);
357 (void)pthread_mutex_unlock(&g_modelVisitLock);
358 return SHORT_OF_MEMORY;
359 }
360 if (neededLen == 0) {
361 *resultLen = 0;
362 (void)pthread_mutex_unlock(&g_modelVisitLock);
363 return OPER_SUCCESS;
364 }
365
366 NotifyRiskResultInfo *data = (NotifyRiskResultInfo *)malloc(neededLen);
367 if (data == NULL) {
368 (void)pthread_mutex_unlock(&g_modelVisitLock);
369 return SHORT_OF_MEMORY;
370 }
371 AppRiskInfo *node = g_modelDataHead->next;
372 uint32_t index = 0;
373 while (node != NULL) {
374 if (index == g_riskAppCount) {
375 break;
376 }
377 if (node->status.policy > NO_SECURITY_RISK) {
378 SetResultInfoAccordingToNode(&(data[index]), node);
379 index++;
380 }
381 node = node->next;
382 }
383 int32_t ret = memcpy_s(result, *resultLen, data, sizeof(NotifyRiskResultInfo) * index);
384 if (ret != OPER_SUCCESS) {
385 MODEL_LOG_ERROR("[%s]:memcpy_s failed", __func__);
386 *resultLen = 0;
387 } else {
388 *resultLen = sizeof(NotifyRiskResultInfo) * index;
389 }
390 free(data);
391 data = NULL;
392 (void)pthread_mutex_unlock(&g_modelVisitLock);
393 return ret;
394 }
395
SubscribeResult(RetListener listener)396 int32_t SubscribeResult(RetListener listener)
397 {
398 if (listener == NULL) {
399 MODEL_LOG_ERROR("[%s]:Listener is null", __func__);
400 return INPUT_POINT_NULL;
401 }
402
403 (void)pthread_mutex_lock(&g_modelVisitLock);
404 if (g_modelDataHead == NULL) {
405 MODEL_LOG_ERROR("[%s]:Init is not completed yet", __func__);
406 (void)pthread_mutex_unlock(&g_modelVisitLock);
407 return MODEL_INIT_NOT_COMPLETED;
408 }
409 g_retListener = listener;
410 (void)pthread_mutex_unlock(&g_modelVisitLock);
411 return OPER_SUCCESS;
412 }
413
GetModelApi(void)414 ModelApi *GetModelApi(void)
415 {
416 int32_t res = pthread_mutex_init(&g_modelVisitLock, NULL);
417 if (res != OPER_SUCCESS) {
418 MODEL_LOG_ERROR("[%s]:pthread_mutex_init failed, res %d.", __func__, res);
419 return NULL;
420 }
421
422 if (g_modelFunc != NULL) {
423 return g_modelFunc;
424 }
425 g_modelFunc = (ModelApi *)malloc(sizeof(ModelApi));
426 if (g_modelFunc == NULL) {
427 MODEL_LOG_ERROR("[%s]: malloc failed", __func__);
428 (void)pthread_mutex_destroy(&g_modelVisitLock);
429 return g_modelFunc;
430 }
431 (void)memset_s(g_modelFunc, sizeof(ModelApi), 0, sizeof(ModelApi));
432 g_modelFunc->init = Init;
433 g_modelFunc->release = Release;
434 g_modelFunc->getResult = GetResult;
435 g_modelFunc->subscribeResult = SubscribeResult;
436
437 return g_modelFunc;
438 }
439