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(¶mSet) != HKS_SUCCESS) {
39 return;
40 }
41
42 (void)HksAbort((const struct HksBlob *)handle, paramSet);
43 HksFreeParamSet(¶mSet);
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