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