• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&current->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(&current->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(&current->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 }