• 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_manager.h"
17 
18 #include <ctype.h>
19 #include <inttypes.h>
20 #include <limits.h>
21 
22 #include "init_cmds.h"
23 #include "init_hook.h"
24 #include "param_base.h"
25 #include "param_trie.h"
26 #include "param_utils.h"
27 #include "securec.h"
28 static DUMP_PRINTF g_printf = printf;
29 
30 static int ReadParamName(ParamHandle handle, char *name, uint32_t length);
31 
SystemCheckMatchParamWait(const char * name,const char * value)32 ParamNode *SystemCheckMatchParamWait(const char *name, const char *value)
33 {
34     ParamWorkSpace *paramSpace = GetParamWorkSpace();
35     PARAM_CHECK(paramSpace != NULL, return NULL, "Invalid paramSpace");
36     PARAM_WORKSPACE_CHECK(paramSpace, return NULL, "Invalid space");
37 
38     WorkSpace *workspace = GetWorkSpaceByName(name);
39     PARAM_CHECK(workspace != NULL, return NULL, "Failed to get workspace %s", name);
40     PARAM_LOGV("SystemCheckMatchParamWait name %s", name);
41     uint32_t nameLength = strlen(name);
42     ParamTrieNode *node = FindTrieNode(workspace, name, nameLength, NULL);
43     if (node == NULL || node->dataIndex == 0) {
44         return NULL;
45     }
46     ParamNode *param = (ParamNode *)GetTrieNode(workspace, node->dataIndex);
47     if (param == NULL) {
48         return NULL;
49     }
50     if ((param->keyLength != nameLength) || (strncmp(param->data, name, nameLength) != 0)) {  // compare name
51         return NULL;
52     }
53     ATOMIC_SYNC_OR_AND_FETCH(&param->commitId, PARAM_FLAGS_WAITED, MEMORY_ORDER_RELEASE);
54     if ((strncmp(value, "*", 1) == 0) || (strcmp(param->data + nameLength + 1, value) == 0)) { // compare value
55         return param;
56     }
57     char *tmp = strstr(value, "*");
58     if (tmp != NULL && (strncmp(param->data + nameLength + 1, value, tmp - value) == 0)) {
59         return param;
60     }
61     return NULL;
62 }
63 
ProcessParamTraversal(const WorkSpace * workSpace,const ParamTrieNode * node,const void * cookie)64 static int ProcessParamTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, const void *cookie)
65 {
66     ParamTraversalContext *context = (ParamTraversalContext *)cookie;
67     ParamTrieNode *current = (ParamTrieNode *)node;
68     if (current == NULL) {
69         return 0;
70     }
71     if (current->dataIndex == 0) {
72         return 0;
73     }
74     ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
75     if (entry == NULL) {
76         return 0;
77     }
78     if ((strcmp("#", context->prefix) != 0) && (strncmp(entry->data, context->prefix, strlen(context->prefix)) != 0)) {
79         return 0;
80     }
81     uint32_t index = PARAM_HANDLE(workSpace, current->dataIndex);
82     context->traversalParamPtr(index, context->context);
83     return 0;
84 }
85 
SystemTraversalParameter(const char * prefix,TraversalParamPtr traversalParameter,void * cookie)86 int SystemTraversalParameter(const char *prefix, TraversalParamPtr traversalParameter, void *cookie)
87 {
88     ParamWorkSpace *paramSpace = GetParamWorkSpace();
89     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
90     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
91     PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null");
92 
93 #ifdef PARAM_SUPPORT_SELINUX // load security label
94     ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX);
95     if (ops != NULL && ops->securityGetLabel != NULL) {
96         ops->securityGetLabel("open");
97     }
98 #endif
99     ParamTraversalContext context = {traversalParameter, cookie, "#"};
100     if (!(prefix == NULL || strlen(prefix) == 0)) {
101         int ret = CheckParamPermission(GetParamSecurityLabel(), prefix, DAC_READ);
102         PARAM_CHECK(ret == 0, return ret, "Forbid to traversal parameters %s", prefix);
103         context.prefix = (char *)prefix;
104     }
105 
106     WorkSpace *workSpace = GetNextWorkSpace(NULL);
107     if (workSpace != NULL && strcmp(workSpace->fileName, WORKSPACE_NAME_DAC) == 0) {
108         workSpace = GetNextWorkSpace(workSpace);
109     }
110     while (workSpace != NULL) {
111         PARAM_LOGV("SystemTraversalParameter prefix %s in space %s", context.prefix, workSpace->fileName);
112         WorkSpace *next = GetNextWorkSpace(workSpace);
113         ParamTrieNode *root = NULL;
114         if (prefix != NULL && strlen(prefix) != 0) {
115             root = FindTrieNode(workSpace, prefix, strlen(prefix), NULL);
116         }
117         PARAMSPACE_AREA_RD_LOCK(workSpace);
118         TraversalTrieNode(workSpace, root, ProcessParamTraversal, (const void *)&context);
119         PARAMSPACE_AREA_RW_UNLOCK(workSpace);
120         workSpace = next;
121     }
122     return 0;
123 }
124 
DumpTrieDataNodeTraversal(const WorkSpace * workSpace,const ParamTrieNode * node,const void * cookie)125 static int DumpTrieDataNodeTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, const void *cookie)
126 {
127     int verbose = *(int *)cookie;
128     ParamTrieNode *current = (ParamTrieNode *)node;
129     if (current == NULL) {
130         return 0;
131     }
132     if (verbose) {
133         PARAM_DUMP("\tTrie node info [%u,%u,%u] data: %u label: %u key length:%u \n\t  key: %s \n",
134             current->left, current->right, current->child,
135             current->dataIndex, current->labelIndex, current->length, current->key);
136     }
137     if (current->dataIndex != 0) {
138         ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
139         if (entry != NULL) {
140             PARAM_DUMP("\tparameter length info [%d] [%u, %u] \n\t  param: %s \n",
141                 entry->commitId, entry->keyLength, entry->valueLength, entry->data);
142         }
143     }
144     if (current->labelIndex != 0 && verbose) {
145         ParamSecurityNode *label = (ParamSecurityNode *)GetTrieNode(workSpace, current->labelIndex);
146         if (label != NULL) {
147             PARAM_DUMP("\tparameter label dac %u %u %o selinuxIndex %u \n",
148                 label->uid, label->gid, label->mode, label->selinuxIndex);
149         }
150     }
151     return 0;
152 }
153 
HashNodeTraverseForDump(WorkSpace * workSpace,int verbose)154 static void HashNodeTraverseForDump(WorkSpace *workSpace, int verbose)
155 {
156     PARAM_DUMP("    map file: %s \n", workSpace->fileName);
157     if (workSpace->area != NULL) {
158         PARAM_DUMP("    total size: %u \n", workSpace->area->dataSize);
159         PARAM_DUMP("    first offset: %u \n", workSpace->area->firstNode);
160         PARAM_DUMP("    current offset: %u \n", workSpace->area->currOffset);
161         PARAM_DUMP("    total node: %u \n", workSpace->area->trieNodeCount);
162         PARAM_DUMP("    total param node: %u \n", workSpace->area->paramNodeCount);
163         PARAM_DUMP("    total security node: %u\n", workSpace->area->securityNodeCount);
164         if (verbose) {
165             PARAM_DUMP("    commitId        : %" PRId64 "\n", workSpace->area->commitId);
166             PARAM_DUMP("    commitPersistId : %" PRId64 "\n", workSpace->area->commitPersistId);
167         }
168     }
169     PARAM_DUMP("    node info: \n");
170     PARAMSPACE_AREA_RD_LOCK(workSpace);
171     TraversalTrieNode(workSpace, NULL, DumpTrieDataNodeTraversal, (const void *)&verbose);
172     PARAMSPACE_AREA_RW_UNLOCK(workSpace);
173 }
174 
SystemDumpParameters(int verbose,int index,int (* dump)(const char * fmt,...))175 void SystemDumpParameters(int verbose, int index, int (*dump)(const char *fmt, ...))
176 {
177     if (dump != NULL) {
178         g_printf = dump;
179     } else {
180         g_printf = printf;
181     }
182     ParamWorkSpace *paramSpace = GetParamWorkSpace();
183     PARAM_CHECK(paramSpace != NULL, return, "Invalid paramSpace");
184     PARAM_WORKSPACE_CHECK(paramSpace, return, "Invalid space");
185     // check default dac
186     int ret = CheckParamPermission(GetParamSecurityLabel(), "#", DAC_READ);
187     PARAM_CHECK(ret == 0, return, "Forbid to dump parameters ");
188 #ifdef PARAM_SUPPORT_SELINUX // load security label
189     ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX);
190     if (ops != NULL && ops->securityGetLabel != NULL) {
191         ops->securityGetLabel("open");
192     }
193 #endif
194     PARAM_DUMP("Dump all parameters begin ...\n");
195     if (verbose) {
196         PARAM_DUMP("Local security information\n");
197         PARAM_DUMP("pid: %d uid: %u gid: %u \n",
198             paramSpace->securityLabel.cred.pid,
199             paramSpace->securityLabel.cred.uid,
200             paramSpace->securityLabel.cred.gid);
201     }
202     if (index > 0) {
203         WorkSpace *workSpace = GetWorkSpace(index);
204         if (workSpace != NULL) {
205             HashNodeTraverseForDump(workSpace, verbose);
206         }
207         return;
208     }
209     WorkSpace *workSpace = GetNextWorkSpace(NULL);
210     while (workSpace != NULL) {
211         WorkSpace *next = GetNextWorkSpace(workSpace);
212         HashNodeTraverseForDump(workSpace, verbose);
213         workSpace = next;
214     }
215     PARAM_DUMP("Dump all parameters finish\n");
216 }
217 
SysCheckParamExist(const char * name)218 INIT_LOCAL_API int SysCheckParamExist(const char *name)
219 {
220     ParamWorkSpace *paramSpace = GetParamWorkSpace();
221     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
222     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
223     PARAM_CHECK(name != NULL, return -1, "The name or handle is null");
224 
225     WorkSpace *workSpace = GetNextWorkSpace(NULL);
226     while (workSpace != NULL) {
227         PARAM_LOGV("SysCheckParamExist name %s in space %s", name, workSpace->fileName);
228         WorkSpace *next = GetNextWorkSpace(workSpace);
229         ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL);
230         if (node != NULL && node->dataIndex != 0) {
231             return 0;
232         } else if (node != NULL) {
233             return PARAM_CODE_NODE_EXIST;
234         }
235         workSpace = next;
236     }
237     return PARAM_CODE_NOT_FOUND;
238 }
239 
GetParamSecurityAuditData(const char * name,int type,ParamAuditData * auditData)240 INIT_INNER_API int GetParamSecurityAuditData(const char *name, int type, ParamAuditData *auditData)
241 {
242     UNUSED(type);
243     ParamWorkSpace *paramSpace = GetParamWorkSpace();
244     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
245     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
246     uint32_t labelIndex = 0;
247     // get from dac
248     WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
249     PARAM_CHECK(space != NULL, return -1, "Invalid workSpace");
250     FindTrieNode(space, name, strlen(name), &labelIndex);
251     ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
252     PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
253 
254     auditData->name = name;
255     auditData->dacData.uid = node->uid;
256     auditData->dacData.gid = node->gid;
257     auditData->dacData.mode = node->mode;
258 #ifdef PARAM_SUPPORT_SELINUX
259     const char *tmpName = (paramSpace->selinuxSpace.getParamLabel != NULL) ?
260         paramSpace->selinuxSpace.getParamLabel(name) : NULL;
261     if (tmpName != NULL) {
262         int ret = strcpy_s(auditData->label, sizeof(auditData->label), tmpName);
263         PARAM_CHECK(ret == 0, return 0, "Failed to copy label for %s", name);
264     }
265 #endif
266     return 0;
267 }
268 
CreateCtrlInfo(ServiceCtrlInfo ** ctrlInfo,const char * cmd,uint32_t offset,uint8_t ctrlParam,const char * format,...)269 static int CreateCtrlInfo(ServiceCtrlInfo **ctrlInfo, const char *cmd, uint32_t offset,
270     uint8_t ctrlParam, const char *format, ...)
271 {
272     *ctrlInfo = calloc(1, sizeof(ServiceCtrlInfo));
273     PARAM_CHECK(ctrlInfo != NULL, return -1, "Failed to alloc memory %s", cmd);
274     va_list vargs;
275     va_start(vargs, format);
276     int len = vsnprintf_s((*ctrlInfo)->realKey,
277         sizeof((*ctrlInfo)->realKey), sizeof((*ctrlInfo)->realKey) - 1, format, vargs);
278     va_end(vargs);
279     int ret = strcpy_s((*ctrlInfo)->cmdName, sizeof((*ctrlInfo)->cmdName), cmd);
280     (*ctrlInfo)->valueOffset = offset;
281     if (ret != 0 || len <= 0) {
282         free(*ctrlInfo);
283         return -1;
284     }
285     (*ctrlInfo)->ctrlParam = ctrlParam;
286     return 0;
287 }
288 
GetServiceCtrlInfoForPowerCtrl(const char * name,const char * value,ServiceCtrlInfo ** ctrlInfo)289 static int GetServiceCtrlInfoForPowerCtrl(const char *name, const char *value, ServiceCtrlInfo **ctrlInfo)
290 {
291     size_t size = 0;
292     const ParamCmdInfo *powerCtrlArg = GetStartupPowerCtl(&size);
293     PARAM_CHECK(powerCtrlArg != NULL, return -1, "Invalid ctrlInfo for %s", name);
294     uint32_t valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen("reboot") + 1;
295     if (strcmp(value, "reboot") == 0) {
296         return CreateCtrlInfo(ctrlInfo, "reboot", valueOffset, 1,
297             "%s%s.%s", OHOS_SERVICE_CTRL_PREFIX, "reboot", value);
298     }
299     for (size_t i = 0; i < size; i++) {
300         PARAM_LOGV("Get power ctrl %s name %s value %s", powerCtrlArg[i].name, name, value);
301         if (strncmp(value, powerCtrlArg[i].name, strlen(powerCtrlArg[i].name)) == 0) {
302             valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen(powerCtrlArg[i].replace) + 1;
303             return CreateCtrlInfo(ctrlInfo, powerCtrlArg[i].cmd, valueOffset, 1,
304                 "%s%s.%s", OHOS_SERVICE_CTRL_PREFIX, powerCtrlArg[i].replace, value);
305         }
306     }
307     // not found reboot, so reboot by normal
308     valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen("reboot") + 1;
309     return CreateCtrlInfo(ctrlInfo, "reboot.other", valueOffset, 1, "%s%s.%s",
310         OHOS_SERVICE_CTRL_PREFIX, "reboot", value);
311 }
312 
GetServiceCtrlInfo(const char * name,const char * value,ServiceCtrlInfo ** ctrlInfo)313 INIT_LOCAL_API int GetServiceCtrlInfo(const char *name, const char *value, ServiceCtrlInfo **ctrlInfo)
314 {
315     PARAM_CHECK(ctrlInfo != NULL, return -1, "Invalid ctrlInfo %s", name);
316     *ctrlInfo = NULL;
317     size_t size = 0;
318     if (strcmp("ohos.startup.powerctrl", name) == 0) {
319         return GetServiceCtrlInfoForPowerCtrl(name, value, ctrlInfo);
320     }
321     if (strncmp("ohos.ctl.", name, strlen("ohos.ctl.")) == 0) {
322         const ParamCmdInfo *ctrlParam = GetServiceStartCtrl(&size);
323         PARAM_CHECK(ctrlParam != NULL, return -1, "Invalid ctrlInfo for %s", name);
324         for (size_t i = 0; i < size; i++) {
325             if (strcmp(name, ctrlParam[i].name) == 0) {
326                 uint32_t valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen(ctrlParam[i].replace) + 1;
327                 return CreateCtrlInfo(ctrlInfo, ctrlParam[i].cmd, valueOffset, 1,
328                     "%s%s.%s", OHOS_SERVICE_CTRL_PREFIX, ctrlParam[i].replace, value);
329             }
330         }
331     }
332     if (strncmp("ohos.servicectrl.", name, strlen("ohos.servicectrl.")) == 0) {
333         const ParamCmdInfo *installParam = GetServiceCtl(&size);
334         PARAM_CHECK(installParam != NULL, return -1, "Invalid ctrlInfo for %s", name);
335         for (size_t i = 0; i < size; i++) {
336             if (strncmp(name, installParam[i].name, strlen(installParam[i].name)) == 0) {
337                 return CreateCtrlInfo(ctrlInfo, installParam[i].cmd, strlen(name) + 1, 1, "%s.%s", name, value);
338             }
339         }
340     }
341     const ParamCmdInfo *other = GetOtherSpecial(&size);
342     for (size_t i = 0; i < size; i++) {
343         if (strncmp(name, other[i].name, strlen(other[i].name)) == 0) {
344             return CreateCtrlInfo(ctrlInfo, other[i].cmd, strlen(other[i].replace), 0, "%s.%s", name, value);
345         }
346     }
347     return 0;
348 }
349 
CheckParameterSet(const char * name,const char * value,const ParamSecurityLabel * srcLabel,int * ctrlService)350 INIT_LOCAL_API int CheckParameterSet(const char *name,
351     const char *value, const ParamSecurityLabel *srcLabel, int *ctrlService)
352 {
353     ParamWorkSpace *paramSpace = GetParamWorkSpace();
354     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
355     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
356     PARAM_LOGV("CheckParameterSet name %s value: %s", name, value);
357     PARAM_CHECK(srcLabel != NULL && ctrlService != NULL, return -1, "Invalid param ");
358     int ret = CheckParamName(name, 0);
359     PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
360     ret = CheckParamValue(NULL, name, value, GetParamValueType(name));
361     PARAM_CHECK(ret == 0, return ret, "Illegal param value %s", value);
362     *ctrlService = 0;
363 
364     ServiceCtrlInfo *serviceInfo = NULL;
365     GetServiceCtrlInfo(name, value, &serviceInfo);
366     ret = CheckParamPermission(srcLabel, (serviceInfo == NULL) ? name : serviceInfo->realKey, DAC_WRITE);
367     if (ret == 0) {
368         if (serviceInfo == NULL) {
369             return 0;
370         }
371         if (serviceInfo->ctrlParam != 0) {  // ctrl param
372             *ctrlService |= PARAM_CTRL_SERVICE;
373         }
374 #if !(defined __LITEOS_A__ || defined __LITEOS_M__)
375         // do hook cmd
376         PARAM_LOGV("Check parameter settings realKey %s cmd: '%s' value: %s",
377             serviceInfo->realKey, serviceInfo->cmdName, (char *)serviceInfo->realKey + serviceInfo->valueOffset);
378         int cmdIndex = 0;
379         (void)GetMatchCmd(serviceInfo->cmdName, &cmdIndex);
380         DoCmdByIndex(cmdIndex, (char *)serviceInfo->realKey + serviceInfo->valueOffset, NULL);
381 #endif
382     }
383     if (serviceInfo != NULL) {
384         free(serviceInfo);
385     }
386     return ret;
387 }
388 
SystemGetParameterName(ParamHandle handle,char * name,unsigned int len)389 int SystemGetParameterName(ParamHandle handle, char *name, unsigned int len)
390 {
391     PARAM_CHECK(name != NULL && handle != 0, return -1, "The name is null");
392     return ReadParamName(handle, name, len);
393 }
394 
AddParam(WorkSpace * workSpace,uint8_t type,const char * name,const char * value,uint32_t * dataIndex)395 static int AddParam(WorkSpace *workSpace, uint8_t type, const char *name, const char *value, uint32_t *dataIndex)
396 {
397     ParamTrieNode *node = AddTrieNode(workSpace, name, strlen(name));
398     PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX,
399         "Failed to add node name %s space %s", name, workSpace->fileName);
400     ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
401     if (entry == NULL) {
402         uint32_t offset = AddParamNode(workSpace, type, name, strlen(name), value, strlen(value));
403         PARAM_CHECK(offset > 0, return PARAM_CODE_REACHED_MAX,
404             "Failed to allocate name %s space %s", name, workSpace->fileName);
405         SaveIndex(&node->dataIndex, offset);
406         ATOMIC_SYNC_ADD_AND_FETCH(&workSpace->area->commitId, 1, MEMORY_ORDER_RELEASE);
407 #ifdef PARAM_SUPPORT_SELINUX
408         WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
409         if (space != NULL && space != workSpace) { // dac commit is global commit
410             ATOMIC_SYNC_ADD_AND_FETCH(&space->area->commitId, 1, MEMORY_ORDER_RELEASE);
411         }
412 #endif
413     }
414     if (dataIndex != NULL) {
415         *dataIndex = node->dataIndex;
416     }
417     PARAM_LOGV("AddParam name %s value: %s", name, value);
418     return 0;
419 }
420 
UpdateParam(const WorkSpace * workSpace,uint32_t * dataIndex,const char * name,const char * value)421 static int UpdateParam(const WorkSpace *workSpace, uint32_t *dataIndex, const char *name, const char *value)
422 {
423     ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, *dataIndex);
424     PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX, "Failed to update param value %s %u", name, *dataIndex);
425     PARAM_CHECK(entry->keyLength == strlen(name), return PARAM_CODE_INVALID_NAME, "Failed to check name len %s", name);
426 
427     uint32_t valueLen = strlen(value);
428     uint32_t commitId = ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_RELAXED);
429     ATOMIC_STORE_EXPLICIT(&entry->commitId, commitId | PARAM_FLAGS_MODIFY, MEMORY_ORDER_RELAXED);
430     if (entry->valueLength < PARAM_VALUE_LEN_MAX && valueLen < PARAM_VALUE_LEN_MAX) {
431         int ret = PARAM_MEMCPY(entry->data + entry->keyLength + 1, PARAM_VALUE_LEN_MAX, value, valueLen + 1);
432         PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_VALUE, "Failed to copy value");
433         entry->valueLength = valueLen;
434     }
435     uint32_t flags = commitId & ~PARAM_FLAGS_COMMITID;
436     ATOMIC_STORE_EXPLICIT(&entry->commitId, (++commitId) | flags, MEMORY_ORDER_RELEASE);
437     ATOMIC_SYNC_ADD_AND_FETCH(&workSpace->area->commitId, 1, MEMORY_ORDER_RELEASE);
438 #ifdef PARAM_SUPPORT_SELINUX
439     WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
440     if (space != NULL && space != workSpace) { // dac commit is global commit
441         ATOMIC_SYNC_ADD_AND_FETCH(&space->area->commitId, 1, MEMORY_ORDER_RELEASE);
442     }
443 #endif
444     PARAM_LOGV("UpdateParam name %s value: %s", name, value);
445     futex_wake(&entry->commitId, INT_MAX);
446     return 0;
447 }
448 
WriteParam(const char * name,const char * value,uint32_t * dataIndex,int mode)449 INIT_LOCAL_API int WriteParam(const char *name, const char *value, uint32_t *dataIndex, int mode)
450 {
451     int flag = 0;
452     PARAM_LOGV("WriteParam %s", name);
453     ParamWorkSpace *paramSpace = GetParamWorkSpace();
454     PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace");
455     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space");
456     PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid name or value");
457     WorkSpace *workSpace = GetWorkSpaceByName(name);
458     PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
459 #ifdef PARAM_SUPPORT_SELINUX
460     if (strcmp(workSpace->fileName, WORKSPACE_NAME_DEF_SELINUX) == 0) {
461         flag = 1;
462     }
463 #endif
464     ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL);
465     int ret = 0;
466     if (node != NULL && node->dataIndex != 0) {
467         if (dataIndex != NULL) {
468             *dataIndex = node->dataIndex;
469         }
470         if ((mode & LOAD_PARAM_ONLY_ADD) == LOAD_PARAM_ONLY_ADD) {
471             return PARAM_CODE_READ_ONLY;
472         }
473         ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
474         PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX,
475             "Failed to update param value %s %u", name, node->dataIndex);
476         // use save type to check value
477         ret = CheckParamValue(node, name, value, entry->type);
478         PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value);
479         PARAMSPACE_AREA_RW_LOCK(workSpace);
480         ret = UpdateParam(workSpace, &node->dataIndex, name, value);
481         PARAMSPACE_AREA_RW_UNLOCK(workSpace);
482     } else {
483         uint8_t type = GetParamValueType(name);
484         ret = CheckParamValue(node, name, value, type);
485         PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value);
486         PARAMSPACE_AREA_RW_LOCK(workSpace);
487         ret = AddParam((WorkSpace *)workSpace, type, name, value, dataIndex);
488         PARAMSPACE_AREA_RW_UNLOCK(workSpace);
489     }
490     if ((ret == PARAM_CODE_REACHED_MAX) && (flag == 1)) {
491         PARAM_LOGE("Add node %s to space %s failed! memory is not enough, system reboot!", name, workSpace->fileName);
492         return PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH;
493     }
494     return ret;
495 }
496 
GetNextWorkSpace(WorkSpace * curr)497 INIT_LOCAL_API WorkSpace *GetNextWorkSpace(WorkSpace *curr)
498 {
499     ParamWorkSpace *paramSpace = GetParamWorkSpace();
500     PARAM_CHECK(paramSpace != NULL, return NULL, "Invalid paramSpace");
501     uint32_t i = (curr == NULL) ? 0 : (curr->spaceIndex + 1);
502     WorkSpace *workSpace = NULL;
503     for (; i < paramSpace->maxLabelIndex; ++i) {
504         workSpace = GetWorkSpace(i);
505         if (workSpace != NULL) {
506             return workSpace;
507         }
508     }
509     return NULL;
510 }
511 
GetParamValueType(const char * name)512 INIT_LOCAL_API uint8_t GetParamValueType(const char *name)
513 {
514     uint32_t labelIndex = 0;
515     WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
516     if (space == NULL) {
517         return PARAM_TYPE_STRING;
518     }
519     (void)FindTrieNode(space, name, strlen(name), &labelIndex);
520     ParamSecurityNode *securityNode = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
521     if (securityNode == NULL) {
522         return PARAM_TYPE_STRING;
523     }
524     return securityNode->type;
525 }
526 
CheckParamValueType(const char * name,const char * value,uint8_t paramType)527 static int CheckParamValueType(const char *name, const char *value, uint8_t paramType)
528 {
529     (void)name;
530     if (paramType == PARAM_TYPE_INT) {
531         long long int temp1 = 0;
532         if (strlen(value) > 1 && value[0] == '-' && StringToLL(value, &temp1) != 0) {
533             PARAM_LOGE("Illegal param value %s for int", value);
534             return PARAM_CODE_INVALID_VALUE;
535         }
536         unsigned long long int temp2 = 0;
537         if (StringToULL(value, &temp2) != 0) {
538             PARAM_LOGE("Illegal param value %s for int", value);
539             return PARAM_CODE_INVALID_VALUE;
540         }
541     } else if (paramType == PARAM_TYPE_BOOL) {
542         static const char *validValue[] = {
543             "1", "0", "true", "false", "y", "yes", "on", "off", "n", "no"
544         };
545         size_t i = 0;
546         for (; i < ARRAY_LENGTH(validValue); i++) {
547             if (strcasecmp(validValue[i], value) == 0) {
548                 break;
549             }
550         }
551         if (i >= ARRAY_LENGTH(validValue)) {
552             PARAM_LOGE("Illegal param value %s for bool", value);
553             return PARAM_CODE_INVALID_VALUE;
554         }
555     }
556     return 0;
557 }
558 
CheckParamValue(const ParamTrieNode * node,const char * name,const char * value,uint8_t paramType)559 INIT_LOCAL_API int CheckParamValue(const ParamTrieNode *node, const char *name, const char *value, uint8_t paramType)
560 {
561     if (IS_READY_ONLY(name)) {
562         PARAM_CHECK(strlen(value) < PARAM_CONST_VALUE_LEN_MAX,
563             return PARAM_CODE_INVALID_VALUE, "Illegal param value %s", value);
564         if (node != NULL && node->dataIndex != 0) {
565             PARAM_LOGE("Read-only param was already set %s", name);
566             return PARAM_CODE_READ_ONLY;
567         }
568     } else {
569         PARAM_CHECK(strlen(value) < GetParamMaxLen(paramType),
570             return PARAM_CODE_INVALID_VALUE, "Illegal param value %s length", value);
571     }
572     return CheckParamValueType(name, value, paramType);
573 }
574 
ReadParamName(ParamHandle handle,char * name,uint32_t length)575 static int ReadParamName(ParamHandle handle, char *name, uint32_t length)
576 {
577     PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
578     ParamWorkSpace *paramSpace = GetParamWorkSpace();
579     PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Param workspace has not init.");
580     PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
581     uint32_t labelIndex = 0;
582     uint32_t index = 0;
583     PARAM_GET_HANDLE_INFO(handle, labelIndex, index);
584     WorkSpace *workSpace = GetWorkSpace(labelIndex);
585     PARAM_CHECK(workSpace != NULL, return PARAM_CODE_NOT_FOUND, "Invalid workSpace for handle %x", handle);
586     ParamNode *entry = NULL;
587     if (PARAM_IS_ALIGNED(index)) {
588         entry = (ParamNode *)GetTrieNode(workSpace, index);
589     }
590     if (entry == NULL) {
591         return PARAM_CODE_NOT_FOUND;
592     }
593     PARAM_CHECK(length > entry->keyLength, return -1, "Invalid param size %u %u", entry->keyLength, length);
594     int ret = PARAM_MEMCPY(name, length, entry->data, entry->keyLength);
595     PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_PARAM, "Failed to copy name");
596     name[entry->keyLength] = '\0';
597     return 0;
598 }
599 
CheckParamName(const char * name,int info)600 INIT_LOCAL_API int CheckParamName(const char *name, int info)
601 {
602     PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
603     size_t nameLen = strlen(name);
604     if (nameLen >= PARAM_NAME_LEN_MAX) {
605         return PARAM_CODE_INVALID_NAME;
606     }
607     if (strcmp(name, "#") == 0) {
608         return 0;
609     }
610 
611     if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) {
612         PARAM_LOGE("CheckParamName %s %d", name, info);
613         return PARAM_CODE_INVALID_NAME;
614     }
615 
616     /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
617     /* Don't allow ".." to appear in a param name */
618     for (size_t i = 0; i < nameLen; i++) {
619         if (name[i] == '.') {
620             if (name[i - 1] == '.') {
621                 return PARAM_CODE_INVALID_NAME;
622             }
623             continue;
624         }
625         if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') {
626             continue;
627         }
628         if (isalnum(name[i])) {
629             continue;
630         }
631         return PARAM_CODE_INVALID_NAME;
632     }
633     return 0;
634 }
635 
CheckParamPermission_(WorkSpace ** workspace,ParamTrieNode ** node,const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)636 static int CheckParamPermission_(WorkSpace **workspace, ParamTrieNode **node,
637     const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
638 {
639     ParamWorkSpace *paramSpace = GetParamWorkSpace();
640     PARAM_CHECK(srcLabel != NULL, return DAC_RESULT_FORBIDED, "The srcLabel is null");
641     WorkSpace *dacSpace = GetWorkSpace(WORKSPACE_INDEX_DAC);
642     PARAM_CHECK(paramSpace->checkParamPermission != NULL, return DAC_RESULT_FORBIDED, "Invalid check permission");
643     ParamLabelIndex labelIndex = {0};
644     // search node from dac space, and get selinux label index
645     *node = FindTrieNode(dacSpace, name, strlen(name), &labelIndex.dacLabelIndex);
646     labelIndex.workspace = GetWorkSpaceByName(name);
647     PARAM_CHECK(labelIndex.workspace != NULL, return DAC_RESULT_FORBIDED, "Invalid workSpace for %s", name);
648     labelIndex.selinuxLabelIndex = labelIndex.workspace->spaceIndex;
649 
650     int ret = paramSpace->checkParamPermission(&labelIndex, srcLabel, name, mode);
651     PARAM_CHECK(ret == 0, return ret,
652         "Forbid to access %s label %u %u", name, labelIndex.dacLabelIndex, labelIndex.selinuxLabelIndex);
653     *workspace = labelIndex.workspace;
654     return ret;
655 }
656 
CheckParamPermission(const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)657 INIT_LOCAL_API int CheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
658 {
659     ParamTrieNode *entry = NULL;
660     WorkSpace *workspace = NULL;
661     return CheckParamPermission_(&workspace, &entry, srcLabel, name, mode);
662 }
663 
GetTrieNodeByHandle(ParamHandle handle)664 STATIC_INLINE ParamTrieNode *GetTrieNodeByHandle(ParamHandle handle)
665 {
666     PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return NULL);
667     uint32_t labelIndex = 0;
668     uint32_t index = 0;
669     PARAM_GET_HANDLE_INFO(handle, labelIndex, index);
670     WorkSpace *workSpace = GetWorkSpace(labelIndex);
671     PARAM_CHECK(workSpace != NULL, return NULL, "Invalid workSpace for handle %x", handle);
672     if (PARAM_IS_ALIGNED(index)) {
673         return (ParamTrieNode *)GetTrieNode(workSpace, index);
674     }
675     return NULL;
676 }
677 
ReadParamValue(ParamNode * entry,char * value,uint32_t * length)678 STATIC_INLINE int ReadParamValue(ParamNode *entry, char *value, uint32_t *length)
679 {
680     if (entry == NULL) {
681         return PARAM_CODE_NOT_FOUND;
682     }
683     if (value == NULL) {
684         *length = entry->valueLength + 1;
685         return 0;
686     }
687     PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_PARAM,
688         "Invalid value len %u %u", *length, entry->valueLength);
689     uint32_t commitId = ReadCommitId(entry);
690     return ReadParamValue_(entry, &commitId, value, length);
691 }
692 
SystemReadParam(const char * name,char * value,uint32_t * len)693 int SystemReadParam(const char *name, char *value, uint32_t *len)
694 {
695     PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
696     PARAM_CHECK(name != NULL && len != NULL, return -1, "The name or value is null");
697     ParamTrieNode *node = NULL;
698     WorkSpace *workspace = NULL;
699     int ret = CheckParamPermission_(&workspace, &node, GetParamSecurityLabel(), name, DAC_READ);
700     if (ret != 0) {
701         return ret;
702     }
703 #ifdef PARAM_SUPPORT_SELINUX
704     // search from real workspace
705     node = FindTrieNode(workspace, name, strlen(name), NULL);
706 #endif
707     if (node == NULL) {
708         return PARAM_CODE_NOT_FOUND;
709     }
710     return ReadParamValue((ParamNode *)GetTrieNode(workspace, node->dataIndex), value, len);
711 }
712 
SystemFindParameter(const char * name,ParamHandle * handle)713 int SystemFindParameter(const char *name, ParamHandle *handle)
714 {
715     PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
716     PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null");
717     *handle = -1;
718     ParamTrieNode *entry = NULL;
719     WorkSpace *workspace = NULL;
720     int ret = CheckParamPermission_(&workspace, &entry, GetParamSecurityLabel(), name, DAC_READ);
721     PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
722 #ifdef PARAM_SUPPORT_SELINUX
723     // search from real workspace
724     entry = FindTrieNode(workspace, name, strlen(name), NULL);
725 #endif
726     if (entry != NULL && entry->dataIndex != 0) {
727         *handle = PARAM_HANDLE(workspace, entry->dataIndex);
728         return 0;
729     } else if (entry != NULL) {
730         return PARAM_CODE_NODE_EXIST;
731     }
732     return PARAM_CODE_NOT_FOUND;
733 }
734 
SystemGetParameterCommitId(ParamHandle handle,uint32_t * commitId)735 int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId)
736 {
737     PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
738     PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
739     PARAM_CHECK(handle != 0 && commitId != NULL, return -1, "The handle is null");
740     ParamNode *entry = (ParamNode *)GetTrieNodeByHandle(handle);
741     if (entry == NULL) {
742         return PARAM_CODE_NOT_FOUND;
743     }
744     *commitId = ReadCommitId(entry);
745     return 0;
746 }
747 
GetSystemCommitId(void)748 long long GetSystemCommitId(void)
749 {
750     PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
751     WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
752     if (space == NULL) {
753         return 0;
754     }
755     return ATOMIC_UINT64_LOAD_EXPLICIT(&space->area->commitId, MEMORY_ORDER_ACQUIRE);
756 }
757 
SystemGetParameterValue(ParamHandle handle,char * value,unsigned int * len)758 int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len)
759 {
760     PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
761     PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
762     PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null");
763     return ReadParamValue((ParamNode *)GetTrieNodeByHandle(handle), value, len);
764 }