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 = ¶m->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, ¶m->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, ¶m->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