1 /*
2  * Copyright (c) 2022 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 "cert_manager_session_mgr.h"
17 #include "cert_manager_mem.h"
18 #include "cm_log.h"
19 
20 #include <pthread.h>
21 #include <stdio.h>
22 
23 #include "hks_api.h"
24 #include "hks_param.h"
25 #include "hks_type.h"
26 
27 #include "securec.h"
28 
29 #define MAX_OPERATIONS_COUNT 15
30 
31 static struct DoubleList g_sessionList = { &g_sessionList, &g_sessionList };
32 static uint32_t g_sessionCount = 0;
33 static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
34 
DeleteHuksInitInfo(const struct CmBlob * handle)35 static void DeleteHuksInitInfo(const struct CmBlob *handle)
36 {
37     struct HksParamSet *paramSet = NULL;
38     if (HksInitParamSet(&paramSet) != HKS_SUCCESS) {
39         return;
40     }
41 
42     (void)HksAbort((const struct HksBlob *)handle, paramSet);
43     HksFreeParamSet(&paramSet);
44 }
45 
FreeSessionNode(struct CmSessionNode ** node)46 static void FreeSessionNode(struct CmSessionNode **node)
47 {
48     if ((node == NULL) || (*node == NULL)) {
49         return;
50     }
51 
52     CM_FREE_PTR((*node)->handle.data);
53     CM_FREE_PTR((*node)->info.uri.data);
54     CM_FREE_PTR(*node);
55 }
56 
57 /* Need to lock before calling RemoveAndFreeSessionNode */
RemoveAndFreeSessionNode(struct CmSessionNode ** sessionNode)58 static void RemoveAndFreeSessionNode(struct CmSessionNode **sessionNode)
59 {
60     if ((sessionNode == NULL) || (*sessionNode == NULL)) {
61         return;
62     }
63 
64     CmRemoveNodeFromList(&(*sessionNode)->listHead);
65     FreeSessionNode(sessionNode);
66 }
67 
68 /* Need to lock before calling DeleteFirstAbortableSession */
DeleteFirstAbortableSession(void)69 static int32_t DeleteFirstAbortableSession(void)
70 {
71     struct CmSessionNode *sessionNode = NULL;
72 
73     CM_DLIST_ITER(sessionNode, &g_sessionList) {
74         if (sessionNode->abortable) {
75             DeleteHuksInitInfo(&(sessionNode->handle));
76             RemoveAndFreeSessionNode(&sessionNode);
77             --g_sessionCount;
78             CM_LOG_D("delete session count: %u", g_sessionCount);
79             return CM_SUCCESS;
80         }
81     }
82 
83     return CMR_ERROR_NOT_FOUND;
84 }
85 
AddSessionNode(struct CmSessionNode * sessionNode)86 static int32_t AddSessionNode(struct CmSessionNode *sessionNode)
87 {
88     pthread_mutex_lock(&g_lock);
89 
90     if (g_sessionCount >= MAX_OPERATIONS_COUNT) {
91         CM_LOG_D("maximum number of sessions reached: delete oldest session.");
92         if (DeleteFirstAbortableSession() != CM_SUCCESS) {
93             pthread_mutex_unlock(&g_lock);
94             CM_LOG_E("not found abortable session");
95             return CMR_ERROR_SESSION_REACHED_LIMIT;
96         }
97     }
98 
99     CmAddNodeAtListTail(&g_sessionList, &sessionNode->listHead);
100     ++g_sessionCount;
101     CM_LOG_D("add session count:%u", g_sessionCount);
102     pthread_mutex_unlock(&g_lock);
103 
104     return HKS_SUCCESS;
105 }
106 
ConstructSessionInfo(const struct CmSessionNodeInfo * info,struct CmSessionNode * node)107 static int32_t ConstructSessionInfo(const struct CmSessionNodeInfo *info, struct CmSessionNode *node)
108 {
109     uint32_t size = info->uri.size;
110     uint8_t *data = (uint8_t *)CMMalloc(size);
111     if (data == NULL) {
112         CM_LOG_E("malloc uri data failed");
113         return CMR_ERROR_MALLOC_FAIL;
114     }
115     (void)memcpy_s(data, size, info->uri.data, size);
116 
117     node->info.userId = info->userId;
118     node->info.uid = info->uid;
119     node->info.uri.data = data;
120     node->info.uri.size = size;
121     return CM_SUCCESS;
122 }
123 
ConstructHandle(const struct CmBlob * handle,struct CmSessionNode * node)124 static int32_t ConstructHandle(const struct CmBlob *handle, struct CmSessionNode *node)
125 {
126     uint32_t size = handle->size;
127     uint8_t *data = (uint8_t *)CMMalloc(size);
128     if (data == NULL) {
129         CM_LOG_E("malloc handle data failed");
130         return CMR_ERROR_MALLOC_FAIL;
131     }
132     (void)memcpy_s(data, size, handle->data, size);
133 
134     node->handle.data = data;
135     node->handle.size = size;
136     return CM_SUCCESS;
137 }
138 
CmCreateSession(const struct CmSessionNodeInfo * info,const struct CmBlob * handle,bool abortable)139 int32_t CmCreateSession(const struct CmSessionNodeInfo *info, const struct CmBlob *handle, bool abortable)
140 {
141     struct CmSessionNode *node = (struct CmSessionNode *)CMMalloc(sizeof(struct CmSessionNode));
142     if (node == NULL) {
143         CM_LOG_E("malloc session node failed");
144         return CMR_ERROR_MALLOC_FAIL;
145     }
146     (void)memset_s(node, sizeof(struct CmSessionNode), 0, sizeof(struct CmSessionNode));
147 
148     int32_t ret;
149     do {
150         ret = ConstructSessionInfo(info, node);
151         if (ret != CM_SUCCESS) {
152             CM_LOG_E("construct session info failed, ret = %d", ret);
153             break;
154         }
155 
156         ret = ConstructHandle(handle, node);
157         if (ret != CM_SUCCESS) {
158             CM_LOG_E("construct handle failed, ret = %d", ret);
159             break;
160         }
161 
162         node->abortable = abortable;
163 
164         ret = AddSessionNode(node);
165         if (ret != CM_SUCCESS) {
166             CM_LOG_E("add session node failed, ret = %d", ret);
167             break;
168         }
169     } while (0);
170     if (ret != CM_SUCCESS) {
171         FreeSessionNode(&node);
172     }
173 
174     return ret;
175 }
176 
IsSameBlob(const struct CmBlob * blob1,const struct CmBlob * blob2)177 static bool IsSameBlob(const struct CmBlob *blob1, const struct CmBlob *blob2)
178 {
179     if (blob1->size != blob2->size) {
180         return false;
181     }
182     if (memcmp(blob1->data, blob2->data, blob1->size) != 0) {
183         return false;
184     }
185     return true;
186 }
187 
IsSameCaller(const struct CmSessionNodeInfo * info,const struct CmSessionNode * node)188 static bool IsSameCaller(const struct CmSessionNodeInfo *info, const struct CmSessionNode *node)
189 {
190     return (info->uid == node->info.uid) && (info->userId == node->info.userId);
191 }
192 
CmQuerySession(const struct CmSessionNodeInfo * info,const struct CmBlob * handle)193 struct CmSessionNode *CmQuerySession(const struct CmSessionNodeInfo *info, const struct CmBlob *handle)
194 {
195     struct CmSessionNode *node = NULL;
196     pthread_mutex_lock(&g_lock);
197     CM_DLIST_ITER(node, &g_sessionList) {
198         if (IsSameBlob(handle, &(node->handle)) && IsSameCaller(info, node)) {
199             pthread_mutex_unlock(&g_lock);
200             return node;
201         }
202     }
203     pthread_mutex_unlock(&g_lock);
204 
205     return NULL;
206 }
207 
CmDeleteSession(const struct CmBlob * handle)208 void CmDeleteSession(const struct CmBlob *handle)
209 {
210     struct CmSessionNode *node = NULL;
211     pthread_mutex_lock(&g_lock);
212     CM_DLIST_ITER(node, &g_sessionList) {
213         if (IsSameBlob(handle, &(node->handle))) {
214             RemoveAndFreeSessionNode(&node);
215             --g_sessionCount;
216             CM_LOG_D("delete session count: %u", g_sessionCount);
217             pthread_mutex_unlock(&g_lock);
218             return;
219         }
220     }
221     pthread_mutex_unlock(&g_lock);
222 }
223 
IsNeedDelete(enum CmSessionDeleteType deleteType,const struct CmSessionNodeInfo * info,const struct CmSessionNode * node)224 static bool IsNeedDelete(enum CmSessionDeleteType deleteType, const struct CmSessionNodeInfo *info,
225     const struct CmSessionNode *node)
226 {
227     switch (deleteType) {
228         case DELETE_SESSION_BY_USERID:
229             return info->userId == node->info.userId;
230         case DELETE_SESSION_BY_UID:
231             return IsSameCaller(info, node);
232         case DELETE_SESSION_BY_URI:
233             return IsSameBlob(&(info->uri), &(node->info.uri));
234         case DELETE_SESSION_BY_ALL:
235             return IsSameCaller(info, node) && IsSameBlob(&(info->uri), &(node->info.uri));
236         default:
237             return false;
238     }
239 }
240 
DeleteSessionNode(enum CmSessionDeleteType deleteType,const struct CmSessionNodeInfo * info,struct CmSessionNode ** nodeSession)241 static void DeleteSessionNode(enum CmSessionDeleteType deleteType, const struct CmSessionNodeInfo *info,
242     struct CmSessionNode **nodeSession)
243 {
244     struct CmSessionNode *node = *nodeSession;
245     if (IsNeedDelete(deleteType, info, node)) {
246         DeleteHuksInitInfo(&(node->handle));
247         RemoveAndFreeSessionNode(nodeSession);
248         --g_sessionCount;
249         CM_LOG_D("delete session count = %u", g_sessionCount);
250     }
251 }
252 
CmDeleteSessionByNodeInfo(enum CmSessionDeleteType deleteType,const struct CmSessionNodeInfo * info)253 void CmDeleteSessionByNodeInfo(enum CmSessionDeleteType deleteType, const struct CmSessionNodeInfo *info)
254 {
255     struct CmSessionNode *node = NULL;
256 
257     pthread_mutex_lock(&g_lock);
258     CM_DLIST_SAFT_ITER(node, &g_sessionList) {
259         if (node != NULL) {
260             DeleteSessionNode(deleteType, info, &node);
261         }
262     }
263     pthread_mutex_unlock(&g_lock);
264 }
265 
266