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