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 "param_trie.h"
17
18 #include <errno.h>
19
20 #include "init_param.h"
21 #include "param_base.h"
22 #include "param_manager.h"
23 #include "param_osadp.h"
24 #include "param_utils.h"
25 #include "param_include.h"
26 static uint32_t AllocateParamTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen);
27
GetRealFileName(WorkSpace * workSpace,char * buffer,uint32_t size)28 static int GetRealFileName(WorkSpace *workSpace, char *buffer, uint32_t size)
29 {
30 int ret = PARAM_SPRINTF(buffer, size, "%s/%s", PARAM_STORAGE_PATH, workSpace->fileName);
31 PARAM_CHECK(ret > 0, return -1, "Failed to copy file name %s", workSpace->fileName);
32 buffer[ret] = '\0';
33 return 0;
34 }
35
InitWorkSpace_(WorkSpace * workSpace,uint32_t spaceSize,int readOnly)36 static int InitWorkSpace_(WorkSpace *workSpace, uint32_t spaceSize, int readOnly)
37 {
38 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
39 PARAM_CHECK(sizeof(ParamTrieHeader) < spaceSize,
40 return PARAM_CODE_INVALID_PARAM, "Invalid spaceSize %u", spaceSize);
41
42 char buffer[FILENAME_LEN_MAX] = {0};
43 int ret = GetRealFileName(workSpace, buffer, sizeof(buffer));
44 PARAM_CHECK(ret == 0, return -1, "Failed to get file name %s", workSpace->fileName);
45 void *areaAddr = GetSharedMem(buffer, &workSpace->memHandle, spaceSize, readOnly);
46 PARAM_ONLY_CHECK(areaAddr != NULL, return PARAM_CODE_ERROR_MAP_FILE);
47 if (!readOnly) {
48 workSpace->area = (ParamTrieHeader *)areaAddr;
49 ATOMIC_UINT64_INIT(&workSpace->area->commitId, 0);
50 ATOMIC_UINT64_INIT(&workSpace->area->commitPersistId, 0);
51 workSpace->area->trieNodeCount = 0;
52 workSpace->area->paramNodeCount = 0;
53 workSpace->area->securityNodeCount = 0;
54 workSpace->area->dataSize = spaceSize - sizeof(ParamTrieHeader);
55 workSpace->area->currOffset = 0;
56 uint32_t offset = AllocateParamTrieNode(workSpace, "#", 1);
57 workSpace->area->firstNode = offset;
58 } else {
59 workSpace->area = (ParamTrieHeader *)areaAddr;
60 }
61 PARAM_LOGV("InitWorkSpace success, readOnly %d currOffset %u firstNode %u dataSize %u",
62 readOnly, workSpace->area->currOffset, workSpace->area->firstNode, workSpace->area->dataSize);
63 return 0;
64 }
65
AllocateParamTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen)66 static uint32_t AllocateParamTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen)
67 {
68 uint32_t len = keyLen + sizeof(ParamTrieNode) + 1;
69 len = PARAM_ALIGN(len);
70 PARAM_CHECK((workSpace->area->currOffset + len) < workSpace->area->dataSize, return 0,
71 "Failed to allocate currOffset %d, dataSize %d space %s",
72 workSpace->area->currOffset, workSpace->area->dataSize, workSpace->fileName);
73 ParamTrieNode *node = (ParamTrieNode *)(workSpace->area->data + workSpace->area->currOffset);
74 node->length = keyLen;
75 int ret = PARAM_MEMCPY(node->key, keyLen, key, keyLen);
76 PARAM_CHECK(ret == 0, return 0, "Failed to copy key");
77 node->key[keyLen] = '\0';
78 node->left = 0;
79 node->right = 0;
80 node->child = 0;
81 node->dataIndex = 0;
82 node->labelIndex = 0;
83 uint32_t offset = workSpace->area->currOffset;
84 workSpace->area->currOffset += len;
85 workSpace->area->trieNodeCount++;
86 return offset;
87 }
88
InitWorkSpace(WorkSpace * workSpace,int onlyRead,uint32_t spaceSize)89 INIT_LOCAL_API int InitWorkSpace(WorkSpace *workSpace, int onlyRead, uint32_t spaceSize)
90 {
91 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid workSpace");
92 if (PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
93 return 0;
94 }
95 int ret = InitWorkSpace_(workSpace, spaceSize, onlyRead);
96 PARAM_ONLY_CHECK(ret == 0, return ret);
97 PARAM_SET_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT);
98 PARAM_LOGV("InitWorkSpace %s for %s", workSpace->fileName, (onlyRead == 0) ? "init" : "other");
99 return ret;
100 }
101
CloseWorkSpace(WorkSpace * workSpace)102 INIT_LOCAL_API void CloseWorkSpace(WorkSpace *workSpace)
103 {
104 PARAM_CHECK(workSpace != NULL, return, "The workspace is null");
105 PARAM_LOGV("CloseWorkSpace %s", workSpace->fileName);
106 if (!PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
107 return;
108 }
109 PARAM_CHECK(workSpace->area != NULL, return, "The workspace area is null");
110 #ifdef WORKSPACE_AREA_NEED_MUTEX
111 ParamRWMutexDelete(&workSpace->rwlock);
112 #endif
113 FreeSharedMem(&workSpace->memHandle, workSpace->area, workSpace->area->dataSize);
114 workSpace->area = NULL;
115 }
116
CheckWorkSpace(const WorkSpace * workSpace)117 static int CheckWorkSpace(const WorkSpace *workSpace)
118 {
119 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return -1, "The workspace is null");
120 if (!PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
121 return -1;
122 }
123 return 0;
124 }
125
CompareParamTrieNode(const ParamTrieNode * node,const char * key,uint32_t keyLen)126 static int CompareParamTrieNode(const ParamTrieNode *node, const char *key, uint32_t keyLen)
127 {
128 if (node->length > keyLen) {
129 return -1;
130 } else if (node->length < keyLen) {
131 return 1;
132 }
133 return memcmp(node->key, key, keyLen);
134 }
135
AddToSubTrie(WorkSpace * workSpace,ParamTrieNode * current,const char * key,uint32_t keyLen)136 static ParamTrieNode *AddToSubTrie(WorkSpace *workSpace, ParamTrieNode *current, const char *key, uint32_t keyLen)
137 {
138 if (current == NULL) {
139 return NULL;
140 }
141 ParamTrieNode *subTrie = NULL;
142 int ret = CompareParamTrieNode(current, key, keyLen);
143 if (ret == 0) {
144 return current;
145 }
146 if (ret < 0) {
147 subTrie = GetTrieNode(workSpace, current->left);
148 if (subTrie == NULL) {
149 uint32_t offset = AllocateParamTrieNode(workSpace, key, keyLen);
150 PARAM_CHECK(offset != 0, return NULL,
151 "Failed to allocate key '%s' in space '%s'", key, workSpace->fileName);
152 SaveIndex(¤t->left, offset);
153 return GetTrieNode(workSpace, current->left);
154 }
155 } else {
156 subTrie = GetTrieNode(workSpace, current->right);
157 if (subTrie == NULL) {
158 uint32_t offset = AllocateParamTrieNode(workSpace, key, keyLen);
159 PARAM_CHECK(offset != 0, return NULL,
160 "Failed to allocate key '%s' in space '%s'", key, workSpace->fileName);
161 SaveIndex(¤t->right, offset);
162 return GetTrieNode(workSpace, current->right);
163 }
164 }
165 return AddToSubTrie(workSpace, subTrie, key, keyLen);
166 }
167
AddTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen)168 ParamTrieNode *AddTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen)
169 {
170 PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid param ");
171 PARAM_CHECK(CheckWorkSpace(workSpace) == 0, return 0, "Invalid workSpace %s", key);
172 const char *remainingKey = key;
173 ParamTrieNode *current = GetTrieRoot(workSpace);
174 PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key);
175 while (1) {
176 uint32_t subKeyLen = 0;
177 char *subKey = NULL;
178 GetNextKey(&remainingKey, &subKey, &subKeyLen, key + keyLen);
179 if (!subKeyLen) {
180 return NULL;
181 }
182 if (current->child != 0) { // 如果child存在,则检查是否匹配
183 ParamTrieNode *next = GetTrieNode(workSpace, current->child);
184 current = AddToSubTrie(workSpace, next, remainingKey, subKeyLen);
185 } else {
186 uint32_t dataOffset = AllocateParamTrieNode(workSpace, remainingKey, subKeyLen);
187 PARAM_CHECK(dataOffset != 0, return NULL,
188 "Failed to allocate key '%s' in space '%s'", key, workSpace->fileName);
189 SaveIndex(¤t->child, dataOffset);
190 current = (ParamTrieNode *)GetTrieNode(workSpace, current->child);
191 }
192 if (current == NULL) {
193 return NULL;
194 }
195 if (subKey == NULL || strcmp(subKey, ".") == 0) {
196 break;
197 }
198 remainingKey = subKey + 1;
199 }
200 return current;
201 }
202
TraversalSubTrieNode(const WorkSpace * workSpace,const ParamTrieNode * current,TraversalTrieNodePtr walkFunc,const void * cookie)203 static int TraversalSubTrieNode(const WorkSpace *workSpace,
204 const ParamTrieNode *current, TraversalTrieNodePtr walkFunc, const void *cookie)
205 {
206 if (current == NULL) {
207 return 0;
208 }
209 walkFunc(workSpace, (ParamTrieNode *)current, cookie);
210 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie);
211 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie);
212 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie);
213 return 0;
214 }
215
TraversalTrieNode(const WorkSpace * workSpace,const ParamTrieNode * root,TraversalTrieNodePtr walkFunc,const void * cookie)216 INIT_LOCAL_API int TraversalTrieNode(const WorkSpace *workSpace,
217 const ParamTrieNode *root, TraversalTrieNodePtr walkFunc, const void *cookie)
218 {
219 PARAM_CHECK(walkFunc != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
220 PARAM_CHECK(CheckWorkSpace(workSpace) == 0, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
221 ParamTrieNode *current = (ParamTrieNode *)root;
222 if (root == NULL) {
223 current = GetTrieRoot(workSpace);
224 }
225 PARAM_CHECK(current != NULL, return 0, "Invalid current node");
226
227 walkFunc(workSpace, (ParamTrieNode *)current, cookie);
228 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie);
229 if (root == NULL) {
230 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie);
231 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie);
232 }
233 return 0;
234 }
235
AddParamSecurityNode(WorkSpace * workSpace,const ParamAuditData * auditData)236 INIT_LOCAL_API uint32_t AddParamSecurityNode(WorkSpace *workSpace, const ParamAuditData *auditData)
237 {
238 PARAM_CHECK(CheckWorkSpace(workSpace) == 0, return 0, "Invalid workSpace");
239 PARAM_CHECK(auditData != NULL, return 0, "Invalid auditData");
240 uint32_t realLen = sizeof(ParamSecurityNode);
241 PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
242 "Failed to allocate currOffset %u, dataSize %u datalen %u",
243 workSpace->area->currOffset, workSpace->area->dataSize, realLen);
244 ParamSecurityNode *node = (ParamSecurityNode *)(workSpace->area->data + workSpace->area->currOffset);
245 node->uid = auditData->dacData.uid;
246 node->gid = auditData->dacData.gid;
247 node->mode = auditData->dacData.mode;
248 node->type = auditData->dacData.paramType & PARAM_TYPE_MASK;
249 #ifdef PARAM_SUPPORT_SELINUX
250 node->selinuxIndex = auditData->selinuxIndex;
251 #else
252 node->selinuxIndex = 0;
253 #endif
254 uint32_t offset = workSpace->area->currOffset;
255 workSpace->area->currOffset += realLen;
256 workSpace->area->securityNodeCount++;
257 return offset;
258 }
259
AddParamNode(WorkSpace * workSpace,uint8_t type,const char * key,uint32_t keyLen,const char * value,uint32_t valueLen)260 INIT_LOCAL_API uint32_t AddParamNode(WorkSpace *workSpace, uint8_t type,
261 const char *key, uint32_t keyLen, const char *value, uint32_t valueLen)
262 {
263 PARAM_CHECK(key != NULL && value != NULL, return 0, "Invalid param");
264 PARAM_CHECK(CheckWorkSpace(workSpace) == 0, return 0, "Invalid workSpace %s", key);
265
266 uint32_t realLen = sizeof(ParamNode) + 1 + 1;
267 // for const parameter, alloc memory on demand
268 if ((valueLen > PARAM_VALUE_LEN_MAX) || IS_READY_ONLY(key)) {
269 realLen += keyLen + valueLen;
270 } else {
271 realLen += keyLen + GetParamMaxLen(type);
272 }
273 realLen = PARAM_ALIGN(realLen);
274 PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
275 "Failed to allocate currOffset %u, dataSize %u datalen %u",
276 workSpace->area->currOffset, workSpace->area->dataSize, realLen);
277
278 ParamNode *node = (ParamNode *)(workSpace->area->data + workSpace->area->currOffset);
279 ATOMIC_INIT(&node->commitId, 0);
280
281 node->type = type;
282 node->keyLength = keyLen;
283 node->valueLength = valueLen;
284 int ret = PARAM_SPRINTF(node->data, realLen, "%s=%s", key, value);
285 PARAM_CHECK(ret > 0, return 0, "Failed to sprint key and value");
286 uint32_t offset = workSpace->area->currOffset;
287 workSpace->area->currOffset += realLen;
288 workSpace->area->paramNodeCount++;
289 return offset;
290 }
291
SaveIndex(uint32_t * index,uint32_t offset)292 INIT_LOCAL_API void SaveIndex(uint32_t *index, uint32_t offset)
293 {
294 *index = offset;
295 }
296
FindTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen,uint32_t * matchLabel)297 INIT_LOCAL_API ParamTrieNode *FindTrieNode(WorkSpace *workSpace,
298 const char *key, uint32_t keyLen, uint32_t *matchLabel)
299 {
300 PARAM_ONLY_CHECK(key != NULL && keyLen > 0, return NULL);
301 PARAM_CHECK(workSpace != NULL, return NULL, "Invalid workspace for %s", key);
302 uint32_t tmpMatchLen = 0;
303 ParamTrieNode *node = NULL;
304 PARAMSPACE_AREA_RD_LOCK(workSpace);
305 node = FindTrieNode_(workSpace, key, keyLen, &tmpMatchLen);
306 PARAMSPACE_AREA_RW_UNLOCK(workSpace);
307 if (matchLabel != NULL) {
308 *matchLabel = tmpMatchLen;
309 }
310 if (node != NULL && node->dataIndex != 0) {
311 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
312 if (entry != NULL && entry->keyLength == keyLen) {
313 return node;
314 }
315 return NULL;
316 }
317 return node;
318 }
319
GetParamMaxLen(uint8_t type)320 INIT_LOCAL_API uint32_t GetParamMaxLen(uint8_t type)
321 {
322 static const uint32_t typeLengths[] = {
323 PARAM_VALUE_LEN_MAX, 32, 8 // 8 max bool length 32 max int length
324 };
325 if (type >= ARRAY_LENGTH(typeLengths)) {
326 return PARAM_VALUE_LEN_MAX;
327 }
328 return typeLengths[type];
329 }
330
GetParamNode(uint32_t index,const char * name)331 INIT_LOCAL_API ParamNode *GetParamNode(uint32_t index, const char *name)
332 {
333 uint32_t labelIndex = 0;
334 WorkSpace *space = GetWorkSpace(index);
335 ParamTrieNode *entry = FindTrieNode(space, name, strlen(name), &labelIndex);
336 if (entry == NULL || entry->dataIndex == 0) {
337 return NULL;
338 }
339 return (ParamNode *)GetTrieNode(space, entry->dataIndex);
340 }
341
AddParamEntry(uint32_t index,uint8_t type,const char * name,const char * value)342 INIT_LOCAL_API int AddParamEntry(uint32_t index, uint8_t type, const char *name, const char *value)
343 {
344 WorkSpace *workSpace = GetWorkSpace(WORKSPACE_INDEX_BASE);
345 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_ERROR, "Invalid workspace");
346 ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL);
347 if (node != NULL && node->dataIndex != 0) {
348 return 0;
349 }
350 node = AddTrieNode(workSpace, name, strlen(name));
351 PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node");
352 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
353 if (entry == NULL) {
354 uint32_t offset = AddParamNode(workSpace, type, name, strlen(name), value, strlen(value));
355 PARAM_CHECK(offset > 0, return PARAM_CODE_REACHED_MAX, "Failed to allocate name %s", name);
356 SaveIndex(&node->dataIndex, offset);
357 }
358 return 0;
359 }
360
AddSecurityLabel(const ParamAuditData * auditData)361 INIT_LOCAL_API int AddSecurityLabel(const ParamAuditData *auditData)
362 {
363 PARAM_CHECK(auditData != NULL && auditData->name != NULL, return -1, "Invalid auditData");
364 WorkSpace *workSpace = GetWorkSpace(WORKSPACE_INDEX_DAC);
365 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
366 ParamTrieNode *node = GetTrieRoot(workSpace);
367 if ((node == NULL) || (CompareParamTrieNode(node, auditData->name, strlen(auditData->name)) != 0)) {
368 node = FindTrieNode(workSpace, auditData->name, strlen(auditData->name), NULL);
369 if (node == NULL) {
370 node = AddTrieNode(workSpace, auditData->name, strlen(auditData->name));
371 }
372 PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, "Failed to add node %s", auditData->name);
373 }
374 uint32_t offset = node->labelIndex;
375 if (node->labelIndex == 0) { // can not support update for label
376 offset = AddParamSecurityNode(workSpace, auditData);
377 PARAM_CHECK(offset != 0, return PARAM_CODE_REACHED_MAX, "Failed to add label");
378 SaveIndex(&node->labelIndex, offset);
379 } else {
380 ParamSecurityNode *label = (ParamSecurityNode *)GetTrieNode(workSpace, node->labelIndex);
381 PARAM_CHECK(label != NULL, return -1, "Failed to get trie node");
382 #ifdef PARAM_SUPPORT_SELINUX
383 if (auditData->selinuxIndex != 0) {
384 label->selinuxIndex = auditData->selinuxIndex;
385 } else
386 #endif
387 {
388 #ifdef STARTUP_INIT_TEST
389 label->mode = auditData->dacData.mode;
390 label->uid = auditData->dacData.uid;
391 label->gid = auditData->dacData.gid;
392 label->type = auditData->dacData.paramType & PARAM_TYPE_MASK;
393 #endif
394 PARAM_LOGV("Repeat to add label for name %s", auditData->name);
395 }
396 }
397 PARAM_LOGV("AddSecurityLabel label %d gid %d uid %d mode %o type:%d name: %s", offset,
398 auditData->dacData.gid, auditData->dacData.uid, auditData->dacData.mode,
399 auditData->dacData.paramType, auditData->name);
400 return 0;
401 }