1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci#include "param_base.h"
16d9f0492fSopenharmony_ci
17d9f0492fSopenharmony_ci#include <ctype.h>
18d9f0492fSopenharmony_ci#include <errno.h>
19d9f0492fSopenharmony_ci#include <limits.h>
20d9f0492fSopenharmony_ci
21d9f0492fSopenharmony_ci#include "init_param.h"
22d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST
23d9f0492fSopenharmony_ci#include "param_include.h"
24d9f0492fSopenharmony_ci#endif
25d9f0492fSopenharmony_ci#include "param_manager.h"
26d9f0492fSopenharmony_ci#include "param_security.h"
27d9f0492fSopenharmony_ci#include "param_trie.h"
28d9f0492fSopenharmony_ci
29d9f0492fSopenharmony_ci#define PUBLIC_APP_BEGIN_UID 10000
30d9f0492fSopenharmony_ci
31d9f0492fSopenharmony_cistatic ParamWorkSpace g_paramWorkSpace = {0};
32d9f0492fSopenharmony_ci
33d9f0492fSopenharmony_cistatic int CheckParamPermission_(const ParamLabelIndex *labelIndex,
34d9f0492fSopenharmony_ci    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode);
35d9f0492fSopenharmony_ciSTATIC_INLINE int CheckAndExtendSpace(ParamWorkSpace *workSpace, const char *name, uint32_t labelIndex);
36d9f0492fSopenharmony_ciSTATIC_INLINE ParamTrieNode *BaseFindTrieNode(WorkSpace *workSpace,
37d9f0492fSopenharmony_ci    const char *key, uint32_t keyLen, uint32_t *matchLabel);
38d9f0492fSopenharmony_ciSTATIC_INLINE const char *CachedParameterCheck(CachedParameter *param, int *changed);
39d9f0492fSopenharmony_ci
40d9f0492fSopenharmony_cistatic int InitParamSecurity(ParamWorkSpace *workSpace,
41d9f0492fSopenharmony_ci    RegisterSecurityOpsPtr registerOps, ParamSecurityType type, int isInit, int op)
42d9f0492fSopenharmony_ci{
43d9f0492fSopenharmony_ci    PARAM_CHECK(workSpace != NULL && type < PARAM_SECURITY_MAX, return -1, "Invalid param");
44d9f0492fSopenharmony_ci    registerOps(&workSpace->paramSecurityOps[type], isInit);
45d9f0492fSopenharmony_ci    PARAM_CHECK(workSpace->paramSecurityOps[type].securityInitLabel != NULL,
46d9f0492fSopenharmony_ci        return -1, "Invalid securityInitLabel");
47d9f0492fSopenharmony_ci    int ret = workSpace->paramSecurityOps[type].securityInitLabel(&workSpace->securityLabel, isInit);
48d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init security");
49d9f0492fSopenharmony_ci
50d9f0492fSopenharmony_ci    ParamSecurityOps *paramSecurityOps = GetParamSecurityOps(type);
51d9f0492fSopenharmony_ci    PARAM_CHECK(paramSecurityOps != NULL, return -1, "Invalid paramSecurityOps");
52d9f0492fSopenharmony_ci    PARAM_CHECK(paramSecurityOps->securityFreeLabel != NULL, return -1, "Invalid securityFreeLabel");
53d9f0492fSopenharmony_ci    PARAM_CHECK(paramSecurityOps->securityCheckFilePermission != NULL, return -1, "Invalid securityCheck");
54d9f0492fSopenharmony_ci    if (isInit == LABEL_INIT_FOR_INIT) {
55d9f0492fSopenharmony_ci        PARAM_CHECK(paramSecurityOps->securityGetLabel != NULL, return -1, "Invalid securityGetLabel");
56d9f0492fSopenharmony_ci    }
57d9f0492fSopenharmony_ci    ret = paramSecurityOps->securityCheckFilePermission(&workSpace->securityLabel, PARAM_STORAGE_PATH, op);
58d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "No permission to read file %s", PARAM_STORAGE_PATH);
59d9f0492fSopenharmony_ci    PARAM_LOGV("Init parameter %s success", paramSecurityOps->name);
60d9f0492fSopenharmony_ci    return 0;
61d9f0492fSopenharmony_ci}
62d9f0492fSopenharmony_ci
63d9f0492fSopenharmony_ciINIT_LOCAL_API int RegisterSecurityOps(int onlyRead)
64d9f0492fSopenharmony_ci{
65d9f0492fSopenharmony_ci    int isInit = 0;
66d9f0492fSopenharmony_ci    int op = DAC_READ;
67d9f0492fSopenharmony_ci    if (onlyRead == 0) {
68d9f0492fSopenharmony_ci        isInit = LABEL_INIT_FOR_INIT;
69d9f0492fSopenharmony_ci        op = DAC_WRITE;
70d9f0492fSopenharmony_ci    }
71d9f0492fSopenharmony_ci    int ret = InitParamSecurity(&g_paramWorkSpace, RegisterSecurityDacOps, PARAM_SECURITY_DAC, isInit, op);
72d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
73d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
74d9f0492fSopenharmony_ci    ret = InitParamSecurity(&g_paramWorkSpace, RegisterSecuritySelinuxOps, PARAM_SECURITY_SELINUX, isInit, op);
75d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
76d9f0492fSopenharmony_ci#endif
77d9f0492fSopenharmony_ci    return ret;
78d9f0492fSopenharmony_ci}
79d9f0492fSopenharmony_ci
80d9f0492fSopenharmony_cistatic int CheckNeedInit(int onlyRead, const PARAM_WORKSPACE_OPS *ops)
81d9f0492fSopenharmony_ci{
82d9f0492fSopenharmony_ci    if (ops != NULL) {
83d9f0492fSopenharmony_ci        g_paramWorkSpace.ops.updaterMode = ops->updaterMode;
84d9f0492fSopenharmony_ci        if (ops->getServiceGroupIdByPid != NULL) {
85d9f0492fSopenharmony_ci            g_paramWorkSpace.ops.getServiceGroupIdByPid = ops->getServiceGroupIdByPid;
86d9f0492fSopenharmony_ci        }
87d9f0492fSopenharmony_ci        if (ops->logFunc != NULL) {
88d9f0492fSopenharmony_ci            if (onlyRead == 0) {
89d9f0492fSopenharmony_ci                g_paramWorkSpace.ops.logFunc = ops->logFunc;
90d9f0492fSopenharmony_ci            } else if (g_paramWorkSpace.ops.logFunc == NULL) {
91d9f0492fSopenharmony_ci                g_paramWorkSpace.ops.logFunc = ops->logFunc;
92d9f0492fSopenharmony_ci            }
93d9f0492fSopenharmony_ci        }
94d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
95d9f0492fSopenharmony_ci        g_paramWorkSpace.ops.setfilecon = ops->setfilecon;
96d9f0492fSopenharmony_ci#endif
97d9f0492fSopenharmony_ci    }
98d9f0492fSopenharmony_ci    if (PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) {
99d9f0492fSopenharmony_ci        PARAM_LOGV("Param workspace has been init");
100d9f0492fSopenharmony_ci        if (PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_FOR_INIT)) {
101d9f0492fSopenharmony_ci            return 0; // init has been init workspace, do not init
102d9f0492fSopenharmony_ci        }
103d9f0492fSopenharmony_ci        if (onlyRead == 0) { // init not init workspace, do init it
104d9f0492fSopenharmony_ci            CloseParamWorkSpace();
105d9f0492fSopenharmony_ci            return 1;
106d9f0492fSopenharmony_ci        }
107d9f0492fSopenharmony_ci        return 0;
108d9f0492fSopenharmony_ci    }
109d9f0492fSopenharmony_ci    if (onlyRead == 0) {
110d9f0492fSopenharmony_ci        return 1;
111d9f0492fSopenharmony_ci    }
112d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST
113d9f0492fSopenharmony_ci    // for ut, do not init workspace
114d9f0492fSopenharmony_ci    char path[PATH_MAX] = { 0 };
115d9f0492fSopenharmony_ci    (void)readlink("/proc/self/exe", path, sizeof(path) - 1);
116d9f0492fSopenharmony_ci    char *name = strstr(path, "/init_unittest");
117d9f0492fSopenharmony_ci    if (name != NULL) {
118d9f0492fSopenharmony_ci        PARAM_LOGW("Can not init client for init_test");
119d9f0492fSopenharmony_ci        return 0;
120d9f0492fSopenharmony_ci    }
121d9f0492fSopenharmony_ci#endif
122d9f0492fSopenharmony_ci    return 1;
123d9f0492fSopenharmony_ci}
124d9f0492fSopenharmony_ci
125d9f0492fSopenharmony_cistatic int AllocSpaceMemory(uint32_t maxLabel)
126d9f0492fSopenharmony_ci{
127d9f0492fSopenharmony_ci    WorkSpace *workSpace = GetWorkSpace(WORKSPACE_INDEX_SIZE);
128d9f0492fSopenharmony_ci    PARAM_CHECK(workSpace != NULL, return PARAM_CODE_ERROR, "Invalid dac workspace");
129d9f0492fSopenharmony_ci    if (workSpace->area->spaceSizeOffset != 0) {
130d9f0492fSopenharmony_ci        return 0;
131d9f0492fSopenharmony_ci    }
132d9f0492fSopenharmony_ci    ParamWorkSpace *paramSpace = GetParamWorkSpace();
133d9f0492fSopenharmony_ci    PARAM_CHECK(paramSpace != NULL, return -1, "Invalid workspace");
134d9f0492fSopenharmony_ci    uint32_t realLen = PARAM_ALIGN(sizeof(WorkSpaceSize) + sizeof(uint32_t) * maxLabel);
135d9f0492fSopenharmony_ci    PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
136d9f0492fSopenharmony_ci        "Failed to allocate currOffset %u, dataSize %u datalen %u",
137d9f0492fSopenharmony_ci        workSpace->area->currOffset, workSpace->area->dataSize, realLen);
138d9f0492fSopenharmony_ci    WorkSpaceSize *node = (WorkSpaceSize *)(workSpace->area->data + workSpace->area->currOffset);
139d9f0492fSopenharmony_ci    node->maxLabelIndex = maxLabel;
140d9f0492fSopenharmony_ci    node->spaceSize[WORKSPACE_INDEX_DAC] = PARAM_WORKSPACE_DAC;
141d9f0492fSopenharmony_ci    node->spaceSize[WORKSPACE_INDEX_BASE] = PARAM_WORKSPACE_MAX;
142d9f0492fSopenharmony_ci    for (uint32_t i = WORKSPACE_INDEX_BASE + 1; i < maxLabel; i++) {
143d9f0492fSopenharmony_ci        node->spaceSize[i] = PARAM_WORKSPACE_MIN;
144d9f0492fSopenharmony_ci        PARAM_LOGV("AllocSpaceMemory spaceSize index %u %u", i, node->spaceSize[i]);
145d9f0492fSopenharmony_ci        if (paramSpace->workSpace[i] != NULL) {
146d9f0492fSopenharmony_ci            paramSpace->workSpace[i]->spaceSize = PARAM_WORKSPACE_MIN;
147d9f0492fSopenharmony_ci        }
148d9f0492fSopenharmony_ci    }
149d9f0492fSopenharmony_ci    workSpace->area->spaceSizeOffset = workSpace->area->currOffset;
150d9f0492fSopenharmony_ci    workSpace->area->currOffset += realLen;
151d9f0492fSopenharmony_ci    return 0;
152d9f0492fSopenharmony_ci}
153d9f0492fSopenharmony_ci
154d9f0492fSopenharmony_cistatic int CreateWorkSpace(int onlyRead)
155d9f0492fSopenharmony_ci{
156d9f0492fSopenharmony_ci    int ret = 0;
157d9f0492fSopenharmony_ci    ParamWorkSpace *paramSpace = GetParamWorkSpace();
158d9f0492fSopenharmony_ci    PARAM_CHECK(paramSpace != NULL, return -1, "Invalid workspace");
159d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
160d9f0492fSopenharmony_ci    ret = AddWorkSpace(WORKSPACE_NAME_DAC, WORKSPACE_INDEX_DAC, 0, PARAM_WORKSPACE_DAC);
161d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to add dac workspace");
162d9f0492fSopenharmony_ci    ret = AddWorkSpace(WORKSPACE_NAME_DEF_SELINUX, WORKSPACE_INDEX_BASE, onlyRead, PARAM_WORKSPACE_MAX);
163d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to add default workspace");
164d9f0492fSopenharmony_ci
165d9f0492fSopenharmony_ci    // open dac workspace
166d9f0492fSopenharmony_ci    ret = OpenWorkSpace(WORKSPACE_INDEX_DAC, onlyRead);
167d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to open dac workspace");
168d9f0492fSopenharmony_ci
169d9f0492fSopenharmony_ci    // for other workspace
170d9f0492fSopenharmony_ci    ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX);
171d9f0492fSopenharmony_ci    if (ops != NULL && ops->securityGetLabel != NULL) {
172d9f0492fSopenharmony_ci        ret = ops->securityGetLabel("create");
173d9f0492fSopenharmony_ci    }
174d9f0492fSopenharmony_ci    paramSpace->maxLabelIndex++;
175d9f0492fSopenharmony_ci#else
176d9f0492fSopenharmony_ci    ret = AddWorkSpace(WORKSPACE_NAME_NORMAL, WORKSPACE_INDEX_DAC, onlyRead, PARAM_WORKSPACE_MAX);
177d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to add dac workspace");
178d9f0492fSopenharmony_ci    ret = OpenWorkSpace(WORKSPACE_INDEX_DAC, onlyRead);
179d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to open dac workspace");
180d9f0492fSopenharmony_ci    paramSpace->maxLabelIndex = 1;
181d9f0492fSopenharmony_ci#endif
182d9f0492fSopenharmony_ci    return ret;
183d9f0492fSopenharmony_ci}
184d9f0492fSopenharmony_ci
185d9f0492fSopenharmony_ciINIT_INNER_API int InitParamWorkSpace(int onlyRead, const PARAM_WORKSPACE_OPS *ops)
186d9f0492fSopenharmony_ci{
187d9f0492fSopenharmony_ci    PARAM_ONLY_CHECK(CheckNeedInit(onlyRead, ops) != 0, return 0);
188d9f0492fSopenharmony_ci
189d9f0492fSopenharmony_ci    paramMutexEnvInit();
190d9f0492fSopenharmony_ci    if (!PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) {
191d9f0492fSopenharmony_ci        g_paramWorkSpace.maxSpaceCount = PARAM_DEF_SELINUX_LABEL;
192d9f0492fSopenharmony_ci        g_paramWorkSpace.workSpace = (WorkSpace **)calloc(g_paramWorkSpace.maxSpaceCount, sizeof(WorkSpace *));
193d9f0492fSopenharmony_ci        PARAM_CHECK(g_paramWorkSpace.workSpace != NULL, return -1, "Failed to alloc memory for workSpace");
194d9f0492fSopenharmony_ci    }
195d9f0492fSopenharmony_ci    PARAM_SET_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT);
196d9f0492fSopenharmony_ci
197d9f0492fSopenharmony_ci    int ret = RegisterSecurityOps(onlyRead);
198d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
199d9f0492fSopenharmony_ci    g_paramWorkSpace.checkParamPermission = CheckParamPermission_;
200d9f0492fSopenharmony_ci    ret = CreateWorkSpace(onlyRead);
201d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Failed to create workspace");
202d9f0492fSopenharmony_ci
203d9f0492fSopenharmony_ci    if (onlyRead == 0) {
204d9f0492fSopenharmony_ci        PARAM_LOGI("Max selinux label %u %u", g_paramWorkSpace.maxSpaceCount, g_paramWorkSpace.maxLabelIndex);
205d9f0492fSopenharmony_ci        // alloc space size memory from dac
206d9f0492fSopenharmony_ci        ret = AllocSpaceMemory(g_paramWorkSpace.maxLabelIndex);
207d9f0492fSopenharmony_ci        PARAM_CHECK(ret == 0, return -1, "Failed to alloc space size");
208d9f0492fSopenharmony_ci
209d9f0492fSopenharmony_ci        // add default dac policy
210d9f0492fSopenharmony_ci        ParamAuditData auditData = {0};
211d9f0492fSopenharmony_ci        auditData.name = "#";
212d9f0492fSopenharmony_ci        auditData.dacData.gid = DAC_DEFAULT_GROUP;
213d9f0492fSopenharmony_ci        auditData.dacData.uid = DAC_DEFAULT_USER;
214d9f0492fSopenharmony_ci        auditData.dacData.mode = DAC_DEFAULT_MODE; // 0774 default mode
215d9f0492fSopenharmony_ci        auditData.dacData.paramType = PARAM_TYPE_STRING;
216d9f0492fSopenharmony_ci        auditData.memberNum = 1;
217d9f0492fSopenharmony_ci        auditData.members[0] = DAC_DEFAULT_GROUP;
218d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
219d9f0492fSopenharmony_ci        auditData.selinuxIndex = INVALID_SELINUX_INDEX;
220d9f0492fSopenharmony_ci#endif
221d9f0492fSopenharmony_ci        ret = AddSecurityLabel(&auditData);
222d9f0492fSopenharmony_ci        PARAM_CHECK(ret == 0, return ret, "Failed to add default dac label");
223d9f0492fSopenharmony_ci        PARAM_SET_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_FOR_INIT);
224d9f0492fSopenharmony_ci    }
225d9f0492fSopenharmony_ci    return ret;
226d9f0492fSopenharmony_ci}
227d9f0492fSopenharmony_ci
228d9f0492fSopenharmony_ciINIT_LOCAL_API void CloseParamWorkSpace(void)
229d9f0492fSopenharmony_ci{
230d9f0492fSopenharmony_ci    PARAM_LOGI("CloseParamWorkSpace %x", g_paramWorkSpace.flags);
231d9f0492fSopenharmony_ci    if (!PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) {
232d9f0492fSopenharmony_ci        return;
233d9f0492fSopenharmony_ci    }
234d9f0492fSopenharmony_ci    for (uint32_t i = 0; i < g_paramWorkSpace.maxSpaceCount; i++) {
235d9f0492fSopenharmony_ci        if (g_paramWorkSpace.workSpace[i] != NULL) {
236d9f0492fSopenharmony_ci            CloseWorkSpace(g_paramWorkSpace.workSpace[i]);
237d9f0492fSopenharmony_ci            free(g_paramWorkSpace.workSpace[i]);
238d9f0492fSopenharmony_ci        }
239d9f0492fSopenharmony_ci        g_paramWorkSpace.workSpace[i] = NULL;
240d9f0492fSopenharmony_ci    }
241d9f0492fSopenharmony_ci    free(g_paramWorkSpace.workSpace);
242d9f0492fSopenharmony_ci    g_paramWorkSpace.workSpace = NULL;
243d9f0492fSopenharmony_ci    for (int i = 0; i < PARAM_SECURITY_MAX; i++) {
244d9f0492fSopenharmony_ci        if (g_paramWorkSpace.paramSecurityOps[i].securityFreeLabel != NULL) {
245d9f0492fSopenharmony_ci            g_paramWorkSpace.paramSecurityOps[i].securityFreeLabel(&g_paramWorkSpace.securityLabel);
246d9f0492fSopenharmony_ci        }
247d9f0492fSopenharmony_ci    }
248d9f0492fSopenharmony_ci    g_paramWorkSpace.flags = 0;
249d9f0492fSopenharmony_ci}
250d9f0492fSopenharmony_ci
251d9f0492fSopenharmony_ciINIT_LOCAL_API void ParamWorBaseLog(InitLogLevel logLevel, uint32_t domain, const char *tag, const char *fmt, ...)
252d9f0492fSopenharmony_ci{
253d9f0492fSopenharmony_ci    if (g_paramWorkSpace.ops.logFunc != NULL) {
254d9f0492fSopenharmony_ci        va_list vargs;
255d9f0492fSopenharmony_ci        va_start(vargs, fmt);
256d9f0492fSopenharmony_ci        g_paramWorkSpace.ops.logFunc(logLevel, domain, tag, fmt, vargs);
257d9f0492fSopenharmony_ci        va_end(vargs);
258d9f0492fSopenharmony_ci    }
259d9f0492fSopenharmony_ci}
260d9f0492fSopenharmony_ci
261d9f0492fSopenharmony_ciINIT_INNER_API ParamWorkSpace *GetParamWorkSpace(void)
262d9f0492fSopenharmony_ci{
263d9f0492fSopenharmony_ci    return &g_paramWorkSpace;
264d9f0492fSopenharmony_ci}
265d9f0492fSopenharmony_ci
266d9f0492fSopenharmony_civoid InitParameterClient(void)
267d9f0492fSopenharmony_ci{
268d9f0492fSopenharmony_ci    PARAM_WORKSPACE_OPS ops = {0};
269d9f0492fSopenharmony_ci    ops.updaterMode = 0;
270d9f0492fSopenharmony_ci    InitParamWorkSpace(1, &ops);
271d9f0492fSopenharmony_ci}
272d9f0492fSopenharmony_ci
273d9f0492fSopenharmony_ciINIT_LOCAL_API int AddWorkSpace(const char *name, uint32_t labelIndex, int onlyRead, uint32_t spaceSize)
274d9f0492fSopenharmony_ci{
275d9f0492fSopenharmony_ci    ParamWorkSpace *paramSpace = GetParamWorkSpace();
276d9f0492fSopenharmony_ci    PARAM_CHECK(paramSpace != NULL, return -1, "Invalid workspace");
277d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
278d9f0492fSopenharmony_ci    const char *realName = name;
279d9f0492fSopenharmony_ci#else
280d9f0492fSopenharmony_ci    const char *realName = WORKSPACE_NAME_NORMAL;
281d9f0492fSopenharmony_ci    labelIndex = 0;
282d9f0492fSopenharmony_ci#endif
283d9f0492fSopenharmony_ci    int ret = CheckAndExtendSpace(paramSpace, name, labelIndex);
284d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return -1, "Not enough memory for %s", realName);
285d9f0492fSopenharmony_ci    if (paramSpace->workSpace[labelIndex] != NULL) {
286d9f0492fSopenharmony_ci        return 0;
287d9f0492fSopenharmony_ci    }
288d9f0492fSopenharmony_ci    const size_t size = strlen(realName) + 1;
289d9f0492fSopenharmony_ci    WorkSpace *workSpace = (WorkSpace *)malloc(sizeof(WorkSpace) + size);
290d9f0492fSopenharmony_ci    PARAM_CHECK(workSpace != NULL, return -1, "Failed to create workspace for %s", realName);
291d9f0492fSopenharmony_ci    workSpace->flags = 0;
292d9f0492fSopenharmony_ci    workSpace->spaceSize = spaceSize;
293d9f0492fSopenharmony_ci    workSpace->area = NULL;
294d9f0492fSopenharmony_ci    workSpace->spaceIndex = labelIndex;
295d9f0492fSopenharmony_ci    ATOMIC_INIT(&workSpace->rwSpaceLock, 0);
296d9f0492fSopenharmony_ci    PARAMSPACE_AREA_INIT_LOCK(workSpace);
297d9f0492fSopenharmony_ci    ret = PARAM_STRCPY(workSpace->fileName, size, realName);
298d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, free(workSpace);
299d9f0492fSopenharmony_ci        return -1, "Failed to copy file name %s", realName);
300d9f0492fSopenharmony_ci    paramSpace->workSpace[labelIndex] = workSpace;
301d9f0492fSopenharmony_ci    PARAM_LOGV("AddWorkSpace %s index %d onlyRead %s", paramSpace->workSpace[labelIndex]->fileName,
302d9f0492fSopenharmony_ci        paramSpace->workSpace[labelIndex]->spaceIndex, onlyRead ? "true" : "false");
303d9f0492fSopenharmony_ci
304d9f0492fSopenharmony_ci    if (spaceSize != 0) {
305d9f0492fSopenharmony_ci        return ret;
306d9f0492fSopenharmony_ci    }
307d9f0492fSopenharmony_ci    // get size
308d9f0492fSopenharmony_ci    WorkSpaceSize *workSpaceSize = GetWorkSpaceSize(GetWorkSpace(WORKSPACE_INDEX_SIZE));
309d9f0492fSopenharmony_ci    if (workSpaceSize != NULL) {
310d9f0492fSopenharmony_ci        paramSpace->workSpace[labelIndex]->spaceSize = workSpaceSize->spaceSize[labelIndex];
311d9f0492fSopenharmony_ci    }
312d9f0492fSopenharmony_ci    return ret;
313d9f0492fSopenharmony_ci}
314d9f0492fSopenharmony_ci
315d9f0492fSopenharmony_ciSTATIC_INLINE int CheckAndExtendSpace(ParamWorkSpace *paramSpace, const char *name, uint32_t labelIndex)
316d9f0492fSopenharmony_ci{
317d9f0492fSopenharmony_ci    if (paramSpace->maxSpaceCount > labelIndex) {
318d9f0492fSopenharmony_ci        return 0;
319d9f0492fSopenharmony_ci    }
320d9f0492fSopenharmony_ci    if (labelIndex >= PARAM_MAX_SELINUX_LABEL) {
321d9f0492fSopenharmony_ci        PARAM_LOGE("Not enough memory for label index %u", labelIndex);
322d9f0492fSopenharmony_ci        return -1;
323d9f0492fSopenharmony_ci    }
324d9f0492fSopenharmony_ci    PARAM_LOGW("Not enough memory for label index %u need to extend memory %u", labelIndex, paramSpace->maxSpaceCount);
325d9f0492fSopenharmony_ci    WorkSpace **space = (WorkSpace **)calloc(sizeof(WorkSpace *),
326d9f0492fSopenharmony_ci        paramSpace->maxSpaceCount + PARAM_DEF_SELINUX_LABEL);
327d9f0492fSopenharmony_ci    PARAM_CHECK(space != NULL, return -1, "Failed to realloc memory for %s", name);
328d9f0492fSopenharmony_ci    int ret = PARAM_MEMCPY(space, sizeof(WorkSpace *) * paramSpace->maxSpaceCount,
329d9f0492fSopenharmony_ci        paramSpace->workSpace, sizeof(WorkSpace *) * paramSpace->maxSpaceCount);
330d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, free(space);
331d9f0492fSopenharmony_ci        return -1, "Failed to copy memory for %s", name);
332d9f0492fSopenharmony_ci    paramSpace->maxSpaceCount += PARAM_DEF_SELINUX_LABEL;
333d9f0492fSopenharmony_ci    free(paramSpace->workSpace);
334d9f0492fSopenharmony_ci    paramSpace->workSpace = space;
335d9f0492fSopenharmony_ci    return 0;
336d9f0492fSopenharmony_ci}
337d9f0492fSopenharmony_ci
338d9f0492fSopenharmony_ciINIT_LOCAL_API int OpenWorkSpace(uint32_t index, int readOnly)
339d9f0492fSopenharmony_ci{
340d9f0492fSopenharmony_ci    ParamWorkSpace *paramSpace = GetParamWorkSpace();
341d9f0492fSopenharmony_ci    PARAM_CHECK(paramSpace != NULL && paramSpace->workSpace != NULL, return -1, "Invalid workspace index %u", index);
342d9f0492fSopenharmony_ci    WorkSpace *workSpace = NULL;
343d9f0492fSopenharmony_ci    PARAM_ONLY_CHECK(index >= paramSpace->maxSpaceCount, workSpace = paramSpace->workSpace[index]);
344d9f0492fSopenharmony_ci    PARAM_CHECK(workSpace != NULL, return 0, "Invalid index %d", index);
345d9f0492fSopenharmony_ci    int ret = 0;
346d9f0492fSopenharmony_ci    uint32_t rwSpaceLock = ATOMIC_LOAD_EXPLICIT(&workSpace->rwSpaceLock, MEMORY_ORDER_ACQUIRE);
347d9f0492fSopenharmony_ci    while (rwSpaceLock & WORKSPACE_STATUS_IN_PROCESS) {
348d9f0492fSopenharmony_ci        futex_wait_private(&workSpace->rwSpaceLock, rwSpaceLock);
349d9f0492fSopenharmony_ci        rwSpaceLock = ATOMIC_LOAD_EXPLICIT(&workSpace->rwSpaceLock, MEMORY_ORDER_ACQUIRE);
350d9f0492fSopenharmony_ci    }
351d9f0492fSopenharmony_ci
352d9f0492fSopenharmony_ci    ATOMIC_STORE_EXPLICIT(&workSpace->rwSpaceLock, rwSpaceLock | WORKSPACE_STATUS_IN_PROCESS, MEMORY_ORDER_RELEASE);
353d9f0492fSopenharmony_ci    if (workSpace->area == NULL) {
354d9f0492fSopenharmony_ci        ret = InitWorkSpace(workSpace, readOnly, workSpace->spaceSize);
355d9f0492fSopenharmony_ci        if (ret != 0) {
356d9f0492fSopenharmony_ci            PARAM_LOGE("Forbid to open workspace for %s error %d", workSpace->fileName, errno);
357d9f0492fSopenharmony_ci        }
358d9f0492fSopenharmony_ci#ifndef PARAM_SUPPORT_SELINUX
359d9f0492fSopenharmony_ci    }
360d9f0492fSopenharmony_ci    ATOMIC_STORE_EXPLICIT(&workSpace->rwSpaceLock, rwSpaceLock & ~WORKSPACE_STATUS_IN_PROCESS, MEMORY_ORDER_RELEASE);
361d9f0492fSopenharmony_ci#else
362d9f0492fSopenharmony_ci    } else if (readOnly) {
363d9f0492fSopenharmony_ci        if ((rwSpaceLock & WORKSPACE_STATUS_VALID) == WORKSPACE_STATUS_VALID) {
364d9f0492fSopenharmony_ci            ret = 0;
365d9f0492fSopenharmony_ci        } else if ((paramSpace->flags & WORKSPACE_FLAGS_NEED_ACCESS) == WORKSPACE_FLAGS_NEED_ACCESS) {
366d9f0492fSopenharmony_ci            char buffer[FILENAME_LEN_MAX] = {0};
367d9f0492fSopenharmony_ci            int size = PARAM_SPRINTF(buffer, sizeof(buffer), "%s/%s", PARAM_STORAGE_PATH, workSpace->fileName);
368d9f0492fSopenharmony_ci            if (size > 0 && access(buffer, R_OK) == 0) {
369d9f0492fSopenharmony_ci                PARAM_LOGW("Open workspace %s access ok ", workSpace->fileName);
370d9f0492fSopenharmony_ci                rwSpaceLock |= WORKSPACE_STATUS_VALID;
371d9f0492fSopenharmony_ci                ret = 0;
372d9f0492fSopenharmony_ci            } else {
373d9f0492fSopenharmony_ci                ret = -1;
374d9f0492fSopenharmony_ci                PARAM_LOGE("Forbid to open workspace for %s error %d", workSpace->fileName, errno);
375d9f0492fSopenharmony_ci                rwSpaceLock &= ~WORKSPACE_STATUS_VALID;
376d9f0492fSopenharmony_ci            }
377d9f0492fSopenharmony_ci        }
378d9f0492fSopenharmony_ci    }
379d9f0492fSopenharmony_ci    ATOMIC_STORE_EXPLICIT(&workSpace->rwSpaceLock, rwSpaceLock & ~WORKSPACE_STATUS_IN_PROCESS, MEMORY_ORDER_RELEASE);
380d9f0492fSopenharmony_ci    futex_wake_private(&workSpace->rwSpaceLock, INT_MAX);
381d9f0492fSopenharmony_ci#endif
382d9f0492fSopenharmony_ci    return ret;
383d9f0492fSopenharmony_ci}
384d9f0492fSopenharmony_ci
385d9f0492fSopenharmony_ciSTATIC_INLINE int ReadParamWithCheck(WorkSpace **workspace, const char *name, uint32_t op, ParamTrieNode **node)
386d9f0492fSopenharmony_ci{
387d9f0492fSopenharmony_ci    ParamLabelIndex labelIndex = {0};
388d9f0492fSopenharmony_ci    WorkSpace *dacSpace = g_paramWorkSpace.workSpace[0];
389d9f0492fSopenharmony_ci    PARAM_CHECK(dacSpace != NULL && dacSpace->area != NULL,
390d9f0492fSopenharmony_ci        return DAC_RESULT_FORBIDED, "Invalid workSpace for %s", name);
391d9f0492fSopenharmony_ci    *node = BaseFindTrieNode(dacSpace, name, strlen(name), &labelIndex.dacLabelIndex);
392d9f0492fSopenharmony_ci    labelIndex.workspace = GetWorkSpaceByName(name);
393d9f0492fSopenharmony_ci    PARAM_CHECK(labelIndex.workspace != NULL, return DAC_RESULT_FORBIDED, "Invalid workSpace for %s", name);
394d9f0492fSopenharmony_ci    labelIndex.selinuxLabelIndex = labelIndex.workspace->spaceIndex;
395d9f0492fSopenharmony_ci
396d9f0492fSopenharmony_ci    int ret = CheckParamPermission_(&labelIndex, &g_paramWorkSpace.securityLabel, name, op);
397d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return ret, "Forbid to read parameter %s", name);
398d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
399d9f0492fSopenharmony_ci    // search from real workspace
400d9f0492fSopenharmony_ci    *node = BaseFindTrieNode(labelIndex.workspace, name, strlen(name), NULL);
401d9f0492fSopenharmony_ci#endif
402d9f0492fSopenharmony_ci    *workspace = labelIndex.workspace;
403d9f0492fSopenharmony_ci    return ret;
404d9f0492fSopenharmony_ci}
405d9f0492fSopenharmony_ci
406d9f0492fSopenharmony_cistatic int CheckUserInGroup(WorkSpace *space, const ParamSecurityNode *node, uid_t uid)
407d9f0492fSopenharmony_ci{
408d9f0492fSopenharmony_ci    for (uint32_t i = 0; i < node->memberNum; i++) {
409d9f0492fSopenharmony_ci        if (node->members[i] == uid) {
410d9f0492fSopenharmony_ci            return 0;
411d9f0492fSopenharmony_ci        }
412d9f0492fSopenharmony_ci    }
413d9f0492fSopenharmony_ci    return -1;
414d9f0492fSopenharmony_ci}
415d9f0492fSopenharmony_ci
416d9f0492fSopenharmony_ciSTATIC_INLINE int DacCheckGroupPermission(const ParamSecurityLabel *srcLabel, uint32_t mode, ParamSecurityNode *node)
417d9f0492fSopenharmony_ci{
418d9f0492fSopenharmony_ci    uint32_t localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
419d9f0492fSopenharmony_ci    if (srcLabel->cred.gid == node->gid) {
420d9f0492fSopenharmony_ci        if ((node->mode & localMode) != 0) {
421d9f0492fSopenharmony_ci            return DAC_RESULT_PERMISSION;
422d9f0492fSopenharmony_ci        }
423d9f0492fSopenharmony_ci    }
424d9f0492fSopenharmony_ci    if (mode != DAC_WRITE || g_paramWorkSpace.ops.getServiceGroupIdByPid == NULL) {
425d9f0492fSopenharmony_ci        return DAC_RESULT_FORBIDED;
426d9f0492fSopenharmony_ci    }
427d9f0492fSopenharmony_ci    gid_t gids[64] = { 0 }; // max gid number
428d9f0492fSopenharmony_ci    const uint32_t gidNumber = (uint32_t)g_paramWorkSpace.ops.getServiceGroupIdByPid(
429d9f0492fSopenharmony_ci        srcLabel->cred.pid, gids, sizeof(gids) / sizeof(gids[0]));
430d9f0492fSopenharmony_ci    for (uint32_t index = 0; index < gidNumber; index++) {
431d9f0492fSopenharmony_ci        PARAM_LOGV("DacCheckGroupPermission gid %u", gids[index]);
432d9f0492fSopenharmony_ci        if (gids[index] != node->gid) {
433d9f0492fSopenharmony_ci            continue;
434d9f0492fSopenharmony_ci        }
435d9f0492fSopenharmony_ci        if ((node->mode & localMode) != 0) {
436d9f0492fSopenharmony_ci            return DAC_RESULT_PERMISSION;
437d9f0492fSopenharmony_ci        }
438d9f0492fSopenharmony_ci    }
439d9f0492fSopenharmony_ci    return DAC_RESULT_FORBIDED;
440d9f0492fSopenharmony_ci}
441d9f0492fSopenharmony_ci
442d9f0492fSopenharmony_ciSTATIC_INLINE int DacCheckParamPermission(const ParamLabelIndex *labelIndex,
443d9f0492fSopenharmony_ci    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
444d9f0492fSopenharmony_ci{
445d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST
446d9f0492fSopenharmony_ci    if (srcLabel->cred.uid == 0) {
447d9f0492fSopenharmony_ci        return DAC_RESULT_PERMISSION;
448d9f0492fSopenharmony_ci    }
449d9f0492fSopenharmony_ci#endif
450d9f0492fSopenharmony_ci    // get dac label
451d9f0492fSopenharmony_ci    WorkSpace *space = g_paramWorkSpace.workSpace[WORKSPACE_INDEX_DAC];
452d9f0492fSopenharmony_ci    ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex->dacLabelIndex);
453d9f0492fSopenharmony_ci    PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %u selinuxLabelIndex %u for %s",
454d9f0492fSopenharmony_ci        labelIndex->dacLabelIndex, labelIndex->selinuxLabelIndex, name);
455d9f0492fSopenharmony_ci    /**
456d9f0492fSopenharmony_ci     * DAC group
457d9f0492fSopenharmony_ci     * user:group:read|write|watch
458d9f0492fSopenharmony_ci     */
459d9f0492fSopenharmony_ci    uint32_t localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_OTHER_START;
460d9f0492fSopenharmony_ci    // 1, check other
461d9f0492fSopenharmony_ci    if ((node->mode & localMode) != 0) {
462d9f0492fSopenharmony_ci        return DAC_RESULT_PERMISSION;
463d9f0492fSopenharmony_ci    }
464d9f0492fSopenharmony_ci    // 2, check uid
465d9f0492fSopenharmony_ci    if (srcLabel->cred.uid == node->uid) {
466d9f0492fSopenharmony_ci        localMode = mode & (DAC_READ | DAC_WRITE | DAC_WATCH);
467d9f0492fSopenharmony_ci        if ((node->mode & localMode) != 0) {
468d9f0492fSopenharmony_ci            return DAC_RESULT_PERMISSION;
469d9f0492fSopenharmony_ci        }
470d9f0492fSopenharmony_ci    }
471d9f0492fSopenharmony_ci    // 3, check gid
472d9f0492fSopenharmony_ci    if (DacCheckGroupPermission(srcLabel, mode, node) == DAC_RESULT_PERMISSION) {
473d9f0492fSopenharmony_ci        return DAC_RESULT_PERMISSION;
474d9f0492fSopenharmony_ci    }
475d9f0492fSopenharmony_ci    // 4, check user in group
476d9f0492fSopenharmony_ci    if (CheckUserInGroup(space, node, srcLabel->cred.uid) == 0) {
477d9f0492fSopenharmony_ci        localMode = (mode & (DAC_READ | DAC_WRITE | DAC_WATCH)) >> DAC_GROUP_START;
478d9f0492fSopenharmony_ci        if ((node->mode & localMode) != 0) {
479d9f0492fSopenharmony_ci            return DAC_RESULT_PERMISSION;
480d9f0492fSopenharmony_ci        }
481d9f0492fSopenharmony_ci    }
482d9f0492fSopenharmony_ci    // forbid
483d9f0492fSopenharmony_ci    PARAM_LOGW("Param '%s' label gid:%d uid:%d mode 0%x", name, srcLabel->cred.gid, srcLabel->cred.uid, mode);
484d9f0492fSopenharmony_ci    PARAM_LOGW("Cfg label %u gid:%d uid:%d mode 0%x ", labelIndex->dacLabelIndex, node->gid, node->uid, node->mode);
485d9f0492fSopenharmony_ci
486d9f0492fSopenharmony_ci    int ret = DAC_RESULT_FORBIDED;
487d9f0492fSopenharmony_ci#ifndef __MUSL__
488d9f0492fSopenharmony_ci#ifndef STARTUP_INIT_TEST
489d9f0492fSopenharmony_ci    ret = DAC_RESULT_PERMISSION;
490d9f0492fSopenharmony_ci#endif
491d9f0492fSopenharmony_ci#endif
492d9f0492fSopenharmony_ci    return ret;
493d9f0492fSopenharmony_ci}
494d9f0492fSopenharmony_ci
495d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
496d9f0492fSopenharmony_ciSTATIC_INLINE const char *GetSelinuxContent(const char *name)
497d9f0492fSopenharmony_ci{
498d9f0492fSopenharmony_ci    SelinuxSpace *selinuxSpace = &g_paramWorkSpace.selinuxSpace;
499d9f0492fSopenharmony_ci    const char *content = WORKSPACE_NAME_DEF_SELINUX;
500d9f0492fSopenharmony_ci    if (selinuxSpace->getParamLabel != NULL) {
501d9f0492fSopenharmony_ci        content = selinuxSpace->getParamLabel(name);
502d9f0492fSopenharmony_ci    }
503d9f0492fSopenharmony_ci    return content;
504d9f0492fSopenharmony_ci}
505d9f0492fSopenharmony_ci
506d9f0492fSopenharmony_ciSTATIC_INLINE int SelinuxCheckParamPermission(const ParamLabelIndex *labelIndex,
507d9f0492fSopenharmony_ci    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
508d9f0492fSopenharmony_ci{
509d9f0492fSopenharmony_ci    SelinuxSpace *selinuxSpace = &g_paramWorkSpace.selinuxSpace;
510d9f0492fSopenharmony_ci    int ret = SELINUX_RESULT_FORBIDED;
511d9f0492fSopenharmony_ci    if (mode == DAC_WRITE) {
512d9f0492fSopenharmony_ci        PARAM_CHECK(selinuxSpace->setParamCheck != NULL, return ret, "Invalid setParamCheck");
513d9f0492fSopenharmony_ci        // check
514d9f0492fSopenharmony_ci        SrcInfo info;
515d9f0492fSopenharmony_ci        info.uc.pid = srcLabel->cred.pid;
516d9f0492fSopenharmony_ci        info.uc.uid = srcLabel->cred.uid;
517d9f0492fSopenharmony_ci        info.uc.gid = srcLabel->cred.gid;
518d9f0492fSopenharmony_ci        info.sockFd = srcLabel->sockFd;
519d9f0492fSopenharmony_ci        const char *context = GetSelinuxContent(name);
520d9f0492fSopenharmony_ci        ret = selinuxSpace->setParamCheck(name, context, &info);
521d9f0492fSopenharmony_ci    } else {
522d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST
523d9f0492fSopenharmony_ci        return selinuxSpace->readParamCheck(name);
524d9f0492fSopenharmony_ci#endif
525d9f0492fSopenharmony_ci        ret = OpenWorkSpace(labelIndex->selinuxLabelIndex, 1);
526d9f0492fSopenharmony_ci    }
527d9f0492fSopenharmony_ci    if (ret != 0) {
528d9f0492fSopenharmony_ci        ret = SELINUX_RESULT_FORBIDED;
529d9f0492fSopenharmony_ci        PARAM_LOGE("Selinux check name %s in %s info [%d %d %d] failed!",
530d9f0492fSopenharmony_ci            name, GetSelinuxContent(name), srcLabel->cred.pid, srcLabel->cred.uid, srcLabel->cred.gid);
531d9f0492fSopenharmony_ci    }
532d9f0492fSopenharmony_ci    return ret;
533d9f0492fSopenharmony_ci}
534d9f0492fSopenharmony_ci#endif
535d9f0492fSopenharmony_ci
536d9f0492fSopenharmony_ci#if defined(STARTUP_INIT_TEST) || defined(__LITEOS_A__) || defined(__LITEOS_M__)
537d9f0492fSopenharmony_cistatic int CheckParamPermission_(const ParamLabelIndex *labelIndex,
538d9f0492fSopenharmony_ci    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
539d9f0492fSopenharmony_ci{
540d9f0492fSopenharmony_ci    // for root, all permission, but for appspawn must to check
541d9f0492fSopenharmony_ci    if (srcLabel->cred.uid == 0 && srcLabel->cred.pid == 1) {
542d9f0492fSopenharmony_ci        return DAC_RESULT_PERMISSION;
543d9f0492fSopenharmony_ci    }
544d9f0492fSopenharmony_ci    int ret = DAC_RESULT_PERMISSION;
545d9f0492fSopenharmony_ci    for (int i = 0; i < PARAM_SECURITY_MAX; i++) {
546d9f0492fSopenharmony_ci        if (PARAM_TEST_FLAG(g_paramWorkSpace.securityLabel.flags[i], LABEL_ALL_PERMISSION)) {
547d9f0492fSopenharmony_ci            continue;
548d9f0492fSopenharmony_ci        }
549d9f0492fSopenharmony_ci        ParamSecurityOps *ops = &g_paramWorkSpace.paramSecurityOps[i];
550d9f0492fSopenharmony_ci        if (ops->securityCheckParamPermission == NULL) {
551d9f0492fSopenharmony_ci            continue;
552d9f0492fSopenharmony_ci        }
553d9f0492fSopenharmony_ci        ret = ops->securityCheckParamPermission(labelIndex, srcLabel, name, mode);
554d9f0492fSopenharmony_ci        if (ret == DAC_RESULT_FORBIDED) {
555d9f0492fSopenharmony_ci            PARAM_LOGW("CheckParamPermission %s %s FORBID", ops->name, name);
556d9f0492fSopenharmony_ci            break;
557d9f0492fSopenharmony_ci        }
558d9f0492fSopenharmony_ci    }
559d9f0492fSopenharmony_ci    return ret;
560d9f0492fSopenharmony_ci}
561d9f0492fSopenharmony_ci#else
562d9f0492fSopenharmony_cistatic int CheckParamPermission_(const ParamLabelIndex *labelIndex,
563d9f0492fSopenharmony_ci    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
564d9f0492fSopenharmony_ci{
565d9f0492fSopenharmony_ci    // only for root and write, all permission, but for appspawn must to check
566d9f0492fSopenharmony_ci    // for clod start in new namespace, pid==1 and uid==root
567d9f0492fSopenharmony_ci    if (srcLabel->cred.uid == 0 && srcLabel->cred.pid == 1 && mode == DAC_WRITE) {
568d9f0492fSopenharmony_ci        return DAC_RESULT_PERMISSION;
569d9f0492fSopenharmony_ci    }
570d9f0492fSopenharmony_ci    int ret = 0;
571d9f0492fSopenharmony_ci    if (srcLabel->cred.uid < PUBLIC_APP_BEGIN_UID) {
572d9f0492fSopenharmony_ci        ret = DacCheckParamPermission(labelIndex, srcLabel, name, mode);
573d9f0492fSopenharmony_ci    }
574d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX
575d9f0492fSopenharmony_ci    if (ret == DAC_RESULT_PERMISSION) {
576d9f0492fSopenharmony_ci        ret = SelinuxCheckParamPermission(labelIndex, srcLabel, name, mode);
577d9f0492fSopenharmony_ci    }
578d9f0492fSopenharmony_ci#endif
579d9f0492fSopenharmony_ci    return ret;
580d9f0492fSopenharmony_ci}
581d9f0492fSopenharmony_ci#endif
582d9f0492fSopenharmony_ci
583d9f0492fSopenharmony_ciSTATIC_INLINE ParamTrieNode *BaseFindTrieNode(WorkSpace *workSpace,
584d9f0492fSopenharmony_ci    const char *key, uint32_t keyLen, uint32_t *matchLabel)
585d9f0492fSopenharmony_ci{
586d9f0492fSopenharmony_ci    PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid key ");
587d9f0492fSopenharmony_ci    uint32_t tmpMatchLen = 0;
588d9f0492fSopenharmony_ci    ParamTrieNode *node = FindTrieNode_(workSpace, key, keyLen, &tmpMatchLen);
589d9f0492fSopenharmony_ci    if (matchLabel != NULL) {
590d9f0492fSopenharmony_ci        *matchLabel = tmpMatchLen;
591d9f0492fSopenharmony_ci    }
592d9f0492fSopenharmony_ci    if (node != NULL && node->dataIndex != 0) {
593d9f0492fSopenharmony_ci        ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
594d9f0492fSopenharmony_ci        if (entry != NULL && entry->keyLength == keyLen) {
595d9f0492fSopenharmony_ci            return node;
596d9f0492fSopenharmony_ci        }
597d9f0492fSopenharmony_ci        return NULL;
598d9f0492fSopenharmony_ci    }
599d9f0492fSopenharmony_ci    return node;
600d9f0492fSopenharmony_ci}
601d9f0492fSopenharmony_ci
602d9f0492fSopenharmony_ciCachedHandle CachedParameterCreate(const char *name, const char *defValue)
603d9f0492fSopenharmony_ci{
604d9f0492fSopenharmony_ci    if (name == NULL || defValue == NULL) {
605d9f0492fSopenharmony_ci        return NULL;
606d9f0492fSopenharmony_ci    }
607d9f0492fSopenharmony_ci    PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return NULL, "Invalid param workspace");
608d9f0492fSopenharmony_ci    uint32_t nameLen = strlen(name);
609d9f0492fSopenharmony_ci    PARAM_CHECK(nameLen < PARAM_NAME_LEN_MAX, return NULL, "Invalid name %s", name);
610d9f0492fSopenharmony_ci    uint32_t valueLen = strlen(defValue);
611d9f0492fSopenharmony_ci    if (IS_READY_ONLY(name)) {
612d9f0492fSopenharmony_ci        PARAM_CHECK(valueLen < PARAM_CONST_VALUE_LEN_MAX, return NULL, "Illegal param value %s", defValue);
613d9f0492fSopenharmony_ci    } else {
614d9f0492fSopenharmony_ci        PARAM_CHECK(valueLen < PARAM_VALUE_LEN_MAX, return NULL, "Illegal param value %s length", defValue);
615d9f0492fSopenharmony_ci    }
616d9f0492fSopenharmony_ci
617d9f0492fSopenharmony_ci    ParamTrieNode *node = NULL;
618d9f0492fSopenharmony_ci    WorkSpace *workspace = NULL;
619d9f0492fSopenharmony_ci    int ret = ReadParamWithCheck(&workspace, name, DAC_READ, &node);
620d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return NULL, "Forbid to access parameter %s", name);
621d9f0492fSopenharmony_ci    PARAM_CHECK(workspace != NULL && workspace->area != NULL, return NULL, "Forbid to access parameter %s", name);
622d9f0492fSopenharmony_ci
623d9f0492fSopenharmony_ci    CachedParameter *param = (CachedParameter *)malloc(
624d9f0492fSopenharmony_ci        sizeof(CachedParameter) + PARAM_ALIGN(nameLen) + 1 + PARAM_VALUE_LEN_MAX);
625d9f0492fSopenharmony_ci    PARAM_CHECK(param != NULL, return NULL, "Failed to create CachedParameter for %s", name);
626d9f0492fSopenharmony_ci    ret = PARAM_STRCPY(param->data, nameLen + 1, name);
627d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, free(param);
628d9f0492fSopenharmony_ci        return NULL, "Failed to copy name %s", name);
629d9f0492fSopenharmony_ci    param->cachedParameterCheck = CachedParameterCheck;
630d9f0492fSopenharmony_ci    param->workspace = workspace;
631d9f0492fSopenharmony_ci    param->nameLen = nameLen;
632d9f0492fSopenharmony_ci    param->paramValue = &param->data[PARAM_ALIGN(nameLen) + 1];
633d9f0492fSopenharmony_ci    param->bufferLen = PARAM_VALUE_LEN_MAX;
634d9f0492fSopenharmony_ci    param->dataCommitId = (uint32_t)-1;
635d9f0492fSopenharmony_ci    if (node != NULL && node->dataIndex != 0) {
636d9f0492fSopenharmony_ci        param->dataIndex = node->dataIndex;
637d9f0492fSopenharmony_ci        ParamNode *entry = (ParamNode *)GetTrieNode(workspace, node->dataIndex);
638d9f0492fSopenharmony_ci        PARAM_CHECK(entry != NULL, free(param);
639d9f0492fSopenharmony_ci            return NULL, "Failed to get trie node %s", name);
640d9f0492fSopenharmony_ci        uint32_t length = param->bufferLen;
641d9f0492fSopenharmony_ci        param->dataCommitId = ReadCommitId(entry);
642d9f0492fSopenharmony_ci        ret = ReadParamValue_(entry, &param->dataCommitId, param->paramValue, &length);
643d9f0492fSopenharmony_ci        PARAM_CHECK(ret == 0, free(param);
644d9f0492fSopenharmony_ci            return NULL, "Failed to read parameter value %s", name);
645d9f0492fSopenharmony_ci    } else {
646d9f0492fSopenharmony_ci        param->dataIndex = 0;
647d9f0492fSopenharmony_ci        ret = PARAM_STRCPY(param->paramValue, param->bufferLen, defValue);
648d9f0492fSopenharmony_ci        PARAM_CHECK(ret == 0, free(param);
649d9f0492fSopenharmony_ci            return NULL, "Failed to copy name %s", name);
650d9f0492fSopenharmony_ci    }
651d9f0492fSopenharmony_ci    param->spaceCommitId = ATOMIC_UINT64_LOAD_EXPLICIT(&workspace->area->commitId, MEMORY_ORDER_ACQUIRE);
652d9f0492fSopenharmony_ci    PARAM_LOGV("CachedParameterCreate %u %u %lld \n", param->dataIndex, param->dataCommitId, param->spaceCommitId);
653d9f0492fSopenharmony_ci    return (CachedHandle)param;
654d9f0492fSopenharmony_ci}
655d9f0492fSopenharmony_ci
656d9f0492fSopenharmony_ciSTATIC_INLINE const char *CachedParameterCheck(CachedParameter *param, int *changed)
657d9f0492fSopenharmony_ci{
658d9f0492fSopenharmony_ci    *changed = 0;
659d9f0492fSopenharmony_ci    if (param->dataIndex == 0) {
660d9f0492fSopenharmony_ci        ParamTrieNode *node = BaseFindTrieNode(param->workspace, param->data, param->nameLen, NULL);
661d9f0492fSopenharmony_ci        if (node != NULL) {
662d9f0492fSopenharmony_ci            param->dataIndex = node->dataIndex;
663d9f0492fSopenharmony_ci        } else {
664d9f0492fSopenharmony_ci            return param->paramValue;
665d9f0492fSopenharmony_ci        }
666d9f0492fSopenharmony_ci    }
667d9f0492fSopenharmony_ci    ParamNode *entry = (ParamNode *)GetTrieNode(param->workspace, param->dataIndex);
668d9f0492fSopenharmony_ci    PARAM_CHECK(entry != NULL, return param->paramValue, "Failed to get trie node %s", param->data);
669d9f0492fSopenharmony_ci    uint32_t dataCommitId = ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_ACQUIRE);
670d9f0492fSopenharmony_ci    dataCommitId &= PARAM_FLAGS_COMMITID;
671d9f0492fSopenharmony_ci    if (param->dataCommitId == dataCommitId) {
672d9f0492fSopenharmony_ci        return param->paramValue;
673d9f0492fSopenharmony_ci    }
674d9f0492fSopenharmony_ci    uint32_t length = param->bufferLen;
675d9f0492fSopenharmony_ci    param->dataCommitId = dataCommitId;
676d9f0492fSopenharmony_ci    int ret = ReadParamValue_(entry, &param->dataCommitId, param->paramValue, &length);
677d9f0492fSopenharmony_ci    PARAM_CHECK(ret == 0, return NULL, "Failed to copy value %s", param->data);
678d9f0492fSopenharmony_ci    PARAM_LOGV("CachedParameterCheck %u", param->dataCommitId);
679d9f0492fSopenharmony_ci    *changed = 1;
680d9f0492fSopenharmony_ci    return param->paramValue;
681d9f0492fSopenharmony_ci}
682d9f0492fSopenharmony_ci
683d9f0492fSopenharmony_civoid CachedParameterDestroy(CachedHandle handle)
684d9f0492fSopenharmony_ci{
685d9f0492fSopenharmony_ci    if (handle != NULL) {
686d9f0492fSopenharmony_ci        free(handle);
687d9f0492fSopenharmony_ci    }
688d9f0492fSopenharmony_ci}
689