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