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