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"
28static DUMP_PRINTF g_printf = printf;
29
30static int ReadParamName(ParamHandle handle, char *name, uint32_t length);
31
32ParamNode *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
64static 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
86int 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
124static 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
161static 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
184void 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
239INIT_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
267INIT_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
296static 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
317static 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
341INIT_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
378INIT_LOCAL_API int CheckParameterSet(const char *name,
379    const char *value, const ParamSecurityLabel *srcLabel, int *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
417int 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
423static 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
450static 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 (entry->valueLength < PARAM_VALUE_LEN_MAX && valueLen < PARAM_VALUE_LEN_MAX) {
460        int ret = PARAM_MEMCPY(entry->data + entry->keyLength + 1, PARAM_VALUE_LEN_MAX, value, valueLen + 1);
461        PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_VALUE, "Failed to copy value");
462        entry->valueLength = valueLen;
463    }
464
465    uint32_t flags = commitId & ~PARAM_FLAGS_COMMITID;
466    uint32_t commitIdCount = (++commitId) & PARAM_FLAGS_COMMITID;
467    ATOMIC_STORE_EXPLICIT(&entry->commitId, flags | commitIdCount, MEMORY_ORDER_RELEASE);
468    ATOMIC_SYNC_ADD_AND_FETCH(&workSpace->area->commitId, 1, MEMORY_ORDER_RELEASE);
469#ifdef PARAM_SUPPORT_SELINUX
470    WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
471    if (space != NULL && space != workSpace) { // dac commit is global commit
472        ATOMIC_SYNC_ADD_AND_FETCH(&space->area->commitId, 1, MEMORY_ORDER_RELEASE);
473    }
474#endif
475    PARAM_LOGV("UpdateParam name %s value: %s", name, value);
476
477    if (((unsigned int)mode & LOAD_PARAM_PERSIST) != 0) {
478        entry->commitId |= PARAM_FLAGS_PERSIST;
479    }
480    futex_wake(&entry->commitId, INT_MAX);
481    return 0;
482}
483
484INIT_LOCAL_API int WriteParam(const char *name, const char *value, uint32_t *dataIndex, int mode)
485{
486    int flag = 0;
487    PARAM_LOGV("WriteParam %s", name);
488    ParamWorkSpace *paramSpace = GetParamWorkSpace();
489    PARAM_CHECK(paramSpace != NULL, return PARAM_WORKSPACE_NOT_INIT, "Invalid paramSpace");
490    PARAM_WORKSPACE_CHECK(paramSpace, return PARAM_WORKSPACE_NOT_INIT, "Invalid space");
491    PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid name or value");
492    WorkSpace *workSpace = GetWorkSpaceByName(name);
493    PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
494#ifdef PARAM_SUPPORT_SELINUX
495    if (strcmp(workSpace->fileName, WORKSPACE_NAME_DEF_SELINUX) == 0) {
496        flag = 1;
497    }
498#endif
499    ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL);
500    int ret = 0;
501    if (node != NULL && node->dataIndex != 0) {
502        if (dataIndex != NULL) {
503            *dataIndex = node->dataIndex;
504        }
505        if ((mode & LOAD_PARAM_ONLY_ADD) == LOAD_PARAM_ONLY_ADD) {
506            return PARAM_CODE_READ_ONLY;
507        }
508        ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
509        PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX,
510            "Failed to update param value %s %u", name, node->dataIndex);
511        // use save type to check value
512        ret = CheckParamValue(node, name, value, entry->type);
513        PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value);
514        PARAMSPACE_AREA_RW_LOCK(workSpace);
515        ret = UpdateParam(workSpace, &node->dataIndex, name, value, mode);
516        PARAMSPACE_AREA_RW_UNLOCK(workSpace);
517    } else {
518        uint8_t type = GetParamValueType(name);
519        ret = CheckParamValue(node, name, value, type);
520        PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value);
521        PARAMSPACE_AREA_RW_LOCK(workSpace);
522        ParamInfos paramInfos = {type, mode, name, value};
523        ret = AddParam((WorkSpace *)workSpace, paramInfos, dataIndex);
524        PARAMSPACE_AREA_RW_UNLOCK(workSpace);
525    }
526    if ((ret == PARAM_CODE_REACHED_MAX) && (flag == 1)) {
527        PARAM_LOGE("Add node %s to space %s failed! memory is not enough, system reboot!", name, workSpace->fileName);
528        return PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH;
529    }
530    return ret;
531}
532
533INIT_LOCAL_API WorkSpace *GetNextWorkSpace(WorkSpace *curr)
534{
535    ParamWorkSpace *paramSpace = GetParamWorkSpace();
536    PARAM_CHECK(paramSpace != NULL, return NULL, "Invalid paramSpace");
537    uint32_t i = (curr == NULL) ? 0 : (curr->spaceIndex + 1);
538    WorkSpace *workSpace = NULL;
539    for (; i < paramSpace->maxLabelIndex; ++i) {
540        workSpace = GetWorkSpace(i);
541        if (workSpace != NULL) {
542            return workSpace;
543        }
544    }
545    return NULL;
546}
547
548INIT_LOCAL_API uint8_t GetParamValueType(const char *name)
549{
550    uint32_t labelIndex = 0;
551    WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
552    if (space == NULL) {
553        return PARAM_TYPE_STRING;
554    }
555    (void)FindTrieNode(space, name, strlen(name), &labelIndex);
556    ParamSecurityNode *securityNode = (ParamSecurityNode *)GetTrieNode(space, labelIndex);
557    if (securityNode == NULL) {
558        return PARAM_TYPE_STRING;
559    }
560    return securityNode->type;
561}
562
563static int CheckParamValueType(const char *name, const char *value, uint8_t paramType)
564{
565    (void)name;
566    if (paramType == PARAM_TYPE_INT) {
567        long long int temp1 = 0;
568        if (strlen(value) > 1 && value[0] == '-' && StringToLL(value, &temp1) != 0) {
569            PARAM_LOGE("Illegal param value %s for int", value);
570            return PARAM_CODE_INVALID_VALUE;
571        }
572        unsigned long long int temp2 = 0;
573        if (StringToULL(value, &temp2) != 0) {
574            PARAM_LOGE("Illegal param value %s for int", value);
575            return PARAM_CODE_INVALID_VALUE;
576        }
577    } else if (paramType == PARAM_TYPE_BOOL) {
578        static const char *validValue[] = {
579            "1", "0", "true", "false", "y", "yes", "on", "off", "n", "no"
580        };
581        size_t i = 0;
582        for (; i < ARRAY_LENGTH(validValue); i++) {
583            if (strcasecmp(validValue[i], value) == 0) {
584                break;
585            }
586        }
587        if (i >= ARRAY_LENGTH(validValue)) {
588            PARAM_LOGE("Illegal param value %s for bool", value);
589            return PARAM_CODE_INVALID_VALUE;
590        }
591    }
592    return 0;
593}
594
595INIT_LOCAL_API int CheckParamValue(const ParamTrieNode *node, const char *name, const char *value, uint8_t paramType)
596{
597    if (IS_READY_ONLY(name)) {
598        PARAM_CHECK(strlen(value) < PARAM_CONST_VALUE_LEN_MAX,
599            return PARAM_CODE_INVALID_VALUE, "Illegal param value %s", value);
600        if (node != NULL && node->dataIndex != 0) {
601            PARAM_LOGE("Read-only param was already set %s", name);
602            return PARAM_CODE_READ_ONLY;
603        }
604    } else {
605        PARAM_CHECK(strlen(value) < GetParamMaxLen(paramType),
606            return PARAM_CODE_INVALID_VALUE, "Illegal param value %s length", value);
607    }
608    return CheckParamValueType(name, value, paramType);
609}
610
611static int ReadParamName(ParamHandle handle, char *name, uint32_t length)
612{
613    PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
614    ParamWorkSpace *paramSpace = GetParamWorkSpace();
615    PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Param workspace has not init.");
616    PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
617    uint32_t labelIndex = 0;
618    uint32_t index = 0;
619    PARAM_GET_HANDLE_INFO(handle, labelIndex, index);
620    WorkSpace *workSpace = GetWorkSpace(labelIndex);
621    PARAM_CHECK(workSpace != NULL, return PARAM_CODE_NOT_FOUND, "Invalid workSpace for handle %x", handle);
622    ParamNode *entry = NULL;
623    if (PARAM_IS_ALIGNED(index)) {
624        entry = (ParamNode *)GetTrieNode(workSpace, index);
625    }
626    if (entry == NULL) {
627        return PARAM_CODE_NOT_FOUND;
628    }
629    PARAM_CHECK(length > entry->keyLength, return -1, "Invalid param size %u %u", entry->keyLength, length);
630    int ret = PARAM_MEMCPY(name, length, entry->data, entry->keyLength);
631    PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_PARAM, "Failed to copy name");
632    name[entry->keyLength] = '\0';
633    return 0;
634}
635
636INIT_LOCAL_API int CheckParamName(const char *name, int info)
637{
638    PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
639    size_t nameLen = strlen(name);
640    if (nameLen >= PARAM_NAME_LEN_MAX) {
641        return PARAM_CODE_INVALID_NAME;
642    }
643    if (strcmp(name, "#") == 0) {
644        return 0;
645    }
646
647    if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) {
648        PARAM_LOGE("CheckParamName %s %d", name, info);
649        return PARAM_CODE_INVALID_NAME;
650    }
651
652    /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
653    /* Don't allow ".." to appear in a param name */
654    for (size_t i = 0; i < nameLen; i++) {
655        if (name[i] == '.') {
656            if (name[i - 1] == '.') {
657                return PARAM_CODE_INVALID_NAME;
658            }
659            continue;
660        }
661        if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') {
662            continue;
663        }
664        if (isalnum(name[i])) {
665            continue;
666        }
667        return PARAM_CODE_INVALID_NAME;
668    }
669    return 0;
670}
671
672static int CheckParamPermission_(WorkSpace **workspace, ParamTrieNode **node,
673    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
674{
675    ParamWorkSpace *paramSpace = GetParamWorkSpace();
676    PARAM_CHECK(srcLabel != NULL, return DAC_RESULT_FORBIDED, "The srcLabel is null");
677    WorkSpace *dacSpace = GetWorkSpace(WORKSPACE_INDEX_DAC);
678    PARAM_CHECK(paramSpace->checkParamPermission != NULL, return DAC_RESULT_FORBIDED, "Invalid check permission");
679    ParamLabelIndex labelIndex = {0};
680    // search node from dac space, and get selinux label index
681    *node = FindTrieNode(dacSpace, name, strlen(name), &labelIndex.dacLabelIndex);
682    labelIndex.workspace = GetWorkSpaceByName(name);
683    PARAM_CHECK(labelIndex.workspace != NULL, return DAC_RESULT_FORBIDED, "Invalid workSpace for %s", name);
684    labelIndex.selinuxLabelIndex = labelIndex.workspace->spaceIndex;
685
686    int ret = paramSpace->checkParamPermission(&labelIndex, srcLabel, name, mode);
687    PARAM_CHECK(ret == 0, return ret,
688        "Forbid to access %s label %u %u", name, labelIndex.dacLabelIndex, labelIndex.selinuxLabelIndex);
689    *workspace = labelIndex.workspace;
690    return ret;
691}
692
693INIT_LOCAL_API int CheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
694{
695    ParamTrieNode *entry = NULL;
696    WorkSpace *workspace = NULL;
697    return CheckParamPermission_(&workspace, &entry, srcLabel, name, mode);
698}
699
700STATIC_INLINE ParamTrieNode *GetTrieNodeByHandle(ParamHandle handle)
701{
702    PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return NULL);
703    uint32_t labelIndex = 0;
704    uint32_t index = 0;
705    PARAM_GET_HANDLE_INFO(handle, labelIndex, index);
706    WorkSpace *workSpace = GetWorkSpace(labelIndex);
707    PARAM_CHECK(workSpace != NULL, return NULL, "Invalid workSpace for handle %x", handle);
708    if (PARAM_IS_ALIGNED(index)) {
709        return (ParamTrieNode *)GetTrieNode(workSpace, index);
710    }
711    return NULL;
712}
713
714STATIC_INLINE int ReadParamValue(ParamNode *entry, char *value, uint32_t *length)
715{
716    if (entry == NULL) {
717        return PARAM_CODE_NOT_FOUND;
718    }
719    if (value == NULL) {
720        *length = entry->valueLength + 1;
721        return 0;
722    }
723    PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_VALUE,
724        "Invalid value len %u %u", *length, entry->valueLength);
725    uint32_t commitId = ReadCommitId(entry);
726    return ReadParamValue_(entry, &commitId, value, length);
727}
728
729int SystemReadParam(const char *name, char *value, uint32_t *len)
730{
731    PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return PARAM_WORKSPACE_NOT_INIT,
732        "SystemReadParam failed! name is:%s, errNum is:%d!", name, PARAM_WORKSPACE_NOT_INIT);
733    PARAM_CHECK(name != NULL && len != NULL, return PARAM_CODE_ERROR,
734        "SystemReadParam failed! name is:%s, errNum is:%d!", name, PARAM_CODE_ERROR);
735    ParamTrieNode *node = NULL;
736    WorkSpace *workspace = NULL;
737    int ret = CheckParamPermission_(&workspace, &node, GetParamSecurityLabel(), name, DAC_READ);
738    if (ret != 0) {
739        PARAM_LOGE("SystemReadParam failed! name is:%s, errNum is:%d!", name, ret);
740        return ret;
741    }
742#ifdef PARAM_SUPPORT_SELINUX
743    // search from real workspace
744    node = FindTrieNode(workspace, name, strlen(name), NULL);
745#endif
746    if (node == NULL) {
747        return PARAM_CODE_NOT_FOUND;
748    }
749    ret =  ReadParamValue((ParamNode *)GetTrieNode(workspace, node->dataIndex), value, len);
750    if (ret != 0) {
751        PARAM_LOGE("SystemReadParam failed! name is:%s, errNum is:%d!", name, ret);
752    }
753    return ret;
754}
755
756int SystemFindParameter(const char *name, ParamHandle *handle)
757{
758    PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return PARAM_WORKSPACE_NOT_INIT, "Param workspace has not init.");
759    PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null");
760    *handle = -1;
761    ParamTrieNode *entry = NULL;
762    WorkSpace *workspace = NULL;
763    int ret = CheckParamPermission_(&workspace, &entry, GetParamSecurityLabel(), name, DAC_READ);
764    PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
765#ifdef PARAM_SUPPORT_SELINUX
766    // search from real workspace
767    entry = FindTrieNode(workspace, name, strlen(name), NULL);
768#endif
769    if (entry != NULL && entry->dataIndex != 0) {
770        *handle = PARAM_HANDLE(workspace, entry->dataIndex);
771        return 0;
772    } else if (entry != NULL) {
773        return PARAM_CODE_NODE_EXIST;
774    }
775    return PARAM_CODE_NOT_FOUND;
776}
777
778int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId)
779{
780    PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
781    PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
782    PARAM_CHECK(handle != 0 && commitId != NULL, return -1, "The handle is null");
783    ParamNode *entry = (ParamNode *)GetTrieNodeByHandle(handle);
784    if (entry == NULL) {
785        return PARAM_CODE_NOT_FOUND;
786    }
787    *commitId = ReadCommitId(entry);
788    return 0;
789}
790
791long long GetSystemCommitId(void)
792{
793    PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
794    WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
795    if (space == NULL || space->area == NULL) {
796        return 0;
797    }
798    return ATOMIC_UINT64_LOAD_EXPLICIT(&space->area->commitId, MEMORY_ORDER_ACQUIRE);
799}
800
801int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len)
802{
803    PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
804    PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
805    PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null");
806    return ReadParamValue((ParamNode *)GetTrieNodeByHandle(handle), value, len);
807}
808
809INIT_LOCAL_API int CheckIfUidInGroup(const gid_t groupId, const char *groupCheckName)
810{
811    PARAM_CHECK(groupCheckName != NULL, return -1, "Invalid groupCheckName");
812    struct group *groupName = getgrnam(groupCheckName);
813    PARAM_CHECK(groupName != NULL, return -1, "Not find %s group", groupCheckName);
814    char  **gr_mem = groupName->gr_mem;
815    PARAM_CHECK(gr_mem != NULL, return -1, "No member in %s", groupCheckName);
816    for (int i = 0; gr_mem[i] != NULL; ++i) {
817        struct group *userGroup = getgrnam(gr_mem[i]);
818        if (userGroup != NULL) {
819            if (groupId == userGroup->gr_gid) {
820                return 0;
821            }
822        }
823    }
824    PARAM_LOGE("Forbid to access, groupId %u not in %s", groupId, groupCheckName);
825    return PARAM_CODE_PERMISSION_DENIED;
826}
827