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