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 31static ParamWorkSpace g_paramWorkSpace = {0}; 32 33static int CheckParamPermission_(const ParamLabelIndex *labelIndex, 34 const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode); 35STATIC_INLINE int CheckAndExtendSpace(ParamWorkSpace *workSpace, const char *name, uint32_t labelIndex); 36STATIC_INLINE ParamTrieNode *BaseFindTrieNode(WorkSpace *workSpace, 37 const char *key, uint32_t keyLen, uint32_t *matchLabel); 38STATIC_INLINE const char *CachedParameterCheck(CachedParameter *param, int *changed); 39 40static 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 63INIT_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 80static 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 125static 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 154static 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 185INIT_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 228INIT_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 251INIT_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 261INIT_INNER_API ParamWorkSpace *GetParamWorkSpace(void) 262{ 263 return &g_paramWorkSpace; 264} 265 266void InitParameterClient(void) 267{ 268 PARAM_WORKSPACE_OPS ops = {0}; 269 ops.updaterMode = 0; 270 InitParamWorkSpace(1, &ops); 271} 272 273INIT_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 315STATIC_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 338INIT_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 385STATIC_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 406static 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 416STATIC_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 442STATIC_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 496STATIC_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 506STATIC_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__) 537static 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 562static 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 583STATIC_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 602CachedHandle 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 656STATIC_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 683void CachedParameterDestroy(CachedHandle handle) 684{ 685 if (handle != NULL) { 686 free(handle); 687 } 688} 689