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 16#include "param_manager.h" 17 18#include <ctype.h> 19#include <inttypes.h> 20#include <limits.h> 21 22#include "init_cmds.h" 23#include "init_hook.h" 24#include "param_base.h" 25#include "param_trie.h" 26#include "param_utils.h" 27#include "securec.h" 28static DUMP_PRINTF g_printf = printf; 29 30static int ReadParamName(ParamHandle handle, char *name, uint32_t length); 31 32ParamNode *SystemCheckMatchParamWait(const char *name, const char *value) 33{ 34 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 35 PARAM_CHECK(paramSpace != NULL, return NULL, "Invalid paramSpace"); 36 PARAM_WORKSPACE_CHECK(paramSpace, return NULL, "Invalid space"); 37 38 WorkSpace *workspace = GetWorkSpaceByName(name); 39 PARAM_CHECK(workspace != NULL, return NULL, "Failed to get workspace %s", name); 40 PARAM_LOGV("SystemCheckMatchParamWait name %s", name); 41 uint32_t nameLength = strlen(name); 42 ParamTrieNode *node = FindTrieNode(workspace, name, nameLength, NULL); 43 if (node == NULL || node->dataIndex == 0) { 44 return NULL; 45 } 46 ParamNode *param = (ParamNode *)GetTrieNode(workspace, node->dataIndex); 47 if (param == NULL) { 48 return NULL; 49 } 50 if ((param->keyLength != nameLength) || (strncmp(param->data, name, nameLength) != 0)) { // compare name 51 return NULL; 52 } 53 ATOMIC_SYNC_OR_AND_FETCH(¶m->commitId, PARAM_FLAGS_WAITED, MEMORY_ORDER_RELEASE); 54 if ((strncmp(value, "*", 1) == 0) || (strcmp(param->data + nameLength + 1, value) == 0)) { // compare value 55 return param; 56 } 57 char *tmp = strstr(value, "*"); 58 if (tmp != NULL && (strncmp(param->data + nameLength + 1, value, tmp - value) == 0)) { 59 return param; 60 } 61 return NULL; 62} 63 64static int ProcessParamTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, const void *cookie) 65{ 66 ParamTraversalContext *context = (ParamTraversalContext *)cookie; 67 ParamTrieNode *current = (ParamTrieNode *)node; 68 if (current == NULL) { 69 return 0; 70 } 71 if (current->dataIndex == 0) { 72 return 0; 73 } 74 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex); 75 if (entry == NULL) { 76 return 0; 77 } 78 if ((strcmp("#", context->prefix) != 0) && (strncmp(entry->data, context->prefix, strlen(context->prefix)) != 0)) { 79 return 0; 80 } 81 uint32_t index = PARAM_HANDLE(workSpace, current->dataIndex); 82 context->traversalParamPtr(index, context->context); 83 return 0; 84} 85 86int SystemTraversalParameter(const char *prefix, TraversalParamPtr traversalParameter, void *cookie) 87{ 88 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 89 PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace"); 90 PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space"); 91 PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null"); 92 93#ifdef PARAM_SUPPORT_SELINUX // load security label 94 ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX); 95 if (ops != NULL && ops->securityGetLabel != NULL) { 96 ops->securityGetLabel("open"); 97 } 98#endif 99 ParamTraversalContext context = {traversalParameter, cookie, "#"}; 100 if (!(prefix == NULL || strlen(prefix) == 0)) { 101 int ret = CheckParamPermission(GetParamSecurityLabel(), prefix, DAC_READ); 102 PARAM_CHECK(ret == 0, return ret, "Forbid to traversal parameters %s", prefix); 103 context.prefix = (char *)prefix; 104 } 105 106 WorkSpace *workSpace = GetNextWorkSpace(NULL); 107 if (workSpace != NULL && strcmp(workSpace->fileName, WORKSPACE_NAME_DAC) == 0) { 108 workSpace = GetNextWorkSpace(workSpace); 109 } 110 while (workSpace != NULL) { 111 WorkSpace *next = GetNextWorkSpace(workSpace); 112 ParamTrieNode *root = NULL; 113 if (prefix != NULL && strlen(prefix) != 0) { 114 root = FindTrieNode(workSpace, prefix, strlen(prefix), NULL); 115 } 116 PARAMSPACE_AREA_RD_LOCK(workSpace); 117 TraversalTrieNode(workSpace, root, ProcessParamTraversal, (const void *)&context); 118 PARAMSPACE_AREA_RW_UNLOCK(workSpace); 119 workSpace = next; 120 } 121 return 0; 122} 123 124static int DumpTrieDataNodeTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, const void *cookie) 125{ 126 int verbose = *(int *)cookie; 127 ParamTrieNode *current = (ParamTrieNode *)node; 128 if (current == NULL) { 129 return 0; 130 } 131 if (verbose) { 132 PARAM_DUMP("\tTrie node info [%u,%u,%u] data: %u label: %u key length:%u \n\t key: %s \n", 133 current->left, current->right, current->child, 134 current->dataIndex, current->labelIndex, current->length, current->key); 135 } 136 if (current->dataIndex != 0) { 137 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex); 138 if (entry != NULL) { 139 PARAM_DUMP("\tparameter length info [%d] [%u, %u] \n\t param: %s \n", 140 entry->commitId, entry->keyLength, entry->valueLength, entry->data); 141 } 142 } 143 if (current->labelIndex == 0) { 144 return 0; 145 } 146 ParamSecurityNode *label = (ParamSecurityNode *)GetTrieNode(workSpace, current->labelIndex); 147 if (label == NULL) { 148 return 0; 149 } 150 PARAM_DUMP("\tparameter label dac %u %u 0%o \n", label->uid, label->gid, label->mode); 151 PARAM_DUMP("\tparameter label dac member [%u] ", label->memberNum); 152 for (uint32_t i = 0; i < label->memberNum; i++) { 153 PARAM_DUMP(" %u", label->members[i]); 154 } 155 if (label->memberNum > 0) { 156 PARAM_DUMP("\n"); 157 } 158 return 0; 159} 160 161static void HashNodeTraverseForDump(WorkSpace *workSpace, int verbose) 162{ 163 PARAM_DUMP(" map file: %s \n", workSpace->fileName); 164 PARAM_DUMP(" space index : %d \n", workSpace->spaceIndex); 165 PARAM_DUMP(" space size : %d \n", workSpace->spaceSize); 166 if (workSpace->area != NULL) { 167 PARAM_DUMP(" total size: %u \n", workSpace->area->dataSize); 168 PARAM_DUMP(" first offset: %u \n", workSpace->area->firstNode); 169 PARAM_DUMP(" current offset: %u \n", workSpace->area->currOffset); 170 PARAM_DUMP(" total node: %u \n", workSpace->area->trieNodeCount); 171 PARAM_DUMP(" total param node: %u \n", workSpace->area->paramNodeCount); 172 PARAM_DUMP(" total security node: %u\n", workSpace->area->securityNodeCount); 173 if (verbose) { 174 PARAM_DUMP(" commitId : %" PRId64 "\n", workSpace->area->commitId); 175 PARAM_DUMP(" commitPersistId : %" PRId64 "\n", workSpace->area->commitPersistId); 176 } 177 } 178 PARAM_DUMP(" node info: \n"); 179 PARAMSPACE_AREA_RD_LOCK(workSpace); 180 TraversalTrieNode(workSpace, NULL, DumpTrieDataNodeTraversal, (const void *)&verbose); 181 PARAMSPACE_AREA_RW_UNLOCK(workSpace); 182} 183 184void SystemDumpParameters(int verbose, int index, int (*dump)(const char *fmt, ...)) 185{ 186 if (dump != NULL) { 187 g_printf = dump; 188 } else { 189 g_printf = printf; 190 } 191 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 192 PARAM_CHECK(paramSpace != NULL, return, "Invalid paramSpace"); 193 PARAM_WORKSPACE_CHECK(paramSpace, return, "Invalid space"); 194 // check default dac 195 int ret = CheckParamPermission(GetParamSecurityLabel(), "#", DAC_READ); 196 PARAM_CHECK(ret == 0, return, "Forbid to dump parameters "); 197#ifdef PARAM_SUPPORT_SELINUX // load security label 198 ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX); 199 if (ops != NULL && ops->securityGetLabel != NULL) { 200 ops->securityGetLabel("open"); 201 } 202#endif 203 PARAM_DUMP("Dump all parameters begin ...\n"); 204 if (verbose) { 205 PARAM_DUMP("Local security information\n"); 206 PARAM_DUMP("pid: %d uid: %u gid: %u \n", 207 paramSpace->securityLabel.cred.pid, 208 paramSpace->securityLabel.cred.uid, 209 paramSpace->securityLabel.cred.gid); 210 } 211 if (index > 0) { 212 WorkSpace *workSpace = GetWorkSpace(index); 213 if (workSpace != NULL) { 214 HashNodeTraverseForDump(workSpace, verbose); 215 } 216 return; 217 } 218 // show workspace size 219 WorkSpaceSize *spaceSize = GetWorkSpaceSize(GetWorkSpace(WORKSPACE_INDEX_SIZE)); 220 if (spaceSize != NULL) { 221 PARAM_DUMP("Max label index : %u\n", spaceSize->maxLabelIndex); 222 for (uint32_t i = 0; i < spaceSize->maxLabelIndex; i++) { 223 if (spaceSize->spaceSize[i] == PARAM_WORKSPACE_MIN) { 224 continue; 225 } 226 PARAM_DUMP("\t workspace %u size : %u\n", i, spaceSize->spaceSize[i]); 227 } 228 } 229 230 WorkSpace *workSpace = GetNextWorkSpace(NULL); 231 while (workSpace != NULL) { 232 WorkSpace *next = GetNextWorkSpace(workSpace); 233 HashNodeTraverseForDump(workSpace, verbose); 234 workSpace = next; 235 } 236 PARAM_DUMP("Dump all parameters finish\n"); 237} 238 239INIT_LOCAL_API int SysCheckParamExist(const char *name) 240{ 241 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 242 PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace"); 243 PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space"); 244 PARAM_CHECK(name != NULL, return -1, "The name or handle is null"); 245 246#ifdef PARAM_SUPPORT_SELINUX // load security label 247 ParamSecurityOps *ops = GetParamSecurityOps(PARAM_SECURITY_SELINUX); 248 if (ops != NULL && ops->securityGetLabel != NULL) { 249 ops->securityGetLabel("open"); 250 } 251#endif 252 WorkSpace *workSpace = GetNextWorkSpace(NULL); 253 while (workSpace != NULL) { 254 PARAM_LOGV("SysCheckParamExist name %s in space %s", name, workSpace->fileName); 255 WorkSpace *next = GetNextWorkSpace(workSpace); 256 ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL); 257 if (node != NULL && node->dataIndex != 0) { 258 return 0; 259 } else if (node != NULL) { 260 return PARAM_CODE_NODE_EXIST; 261 } 262 workSpace = next; 263 } 264 return PARAM_CODE_NOT_FOUND; 265} 266 267INIT_INNER_API int GetParamSecurityAuditData(const char *name, int type, ParamAuditData *auditData) 268{ 269 UNUSED(type); 270 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 271 PARAM_CHECK(paramSpace != NULL, return -1, "Invalid paramSpace"); 272 PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Invalid space"); 273 uint32_t labelIndex = 0; 274 // get from dac 275 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC); 276 PARAM_CHECK(space != NULL, return -1, "Invalid workSpace"); 277 FindTrieNode(space, name, strlen(name), &labelIndex); 278 ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, labelIndex); 279 PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex); 280 281 auditData->name = name; 282 auditData->dacData.uid = node->uid; 283 auditData->dacData.gid = node->gid; 284 auditData->dacData.mode = node->mode; 285#ifdef PARAM_SUPPORT_SELINUX 286 const char *tmpName = (paramSpace->selinuxSpace.getParamLabel != NULL) ? 287 paramSpace->selinuxSpace.getParamLabel(name) : NULL; 288 if (tmpName != NULL) { 289 int ret = strcpy_s(auditData->label, sizeof(auditData->label), tmpName); 290 PARAM_CHECK(ret == 0, return 0, "Failed to copy label for %s", name); 291 } 292#endif 293 return 0; 294} 295 296static int CreateCtrlInfo(ServiceCtrlInfo **ctrlInfo, const char *cmd, uint32_t offset, 297 uint8_t ctrlParam, const char *format, ...) 298{ 299 *ctrlInfo = calloc(1, sizeof(ServiceCtrlInfo)); 300 PARAM_CHECK(*ctrlInfo != NULL, return -1, "Failed to alloc memory %s", cmd); 301 va_list vargs; 302 va_start(vargs, format); 303 int len = vsnprintf_s((*ctrlInfo)->realKey, 304 sizeof((*ctrlInfo)->realKey), sizeof((*ctrlInfo)->realKey) - 1, format, vargs); 305 va_end(vargs); 306 int ret = strcpy_s((*ctrlInfo)->cmdName, sizeof((*ctrlInfo)->cmdName), cmd); 307 (*ctrlInfo)->valueOffset = offset; 308 if (ret != 0 || len <= 0) { 309 free(*ctrlInfo); 310 *ctrlInfo = NULL; 311 return -1; 312 } 313 (*ctrlInfo)->ctrlParam = ctrlParam; 314 return 0; 315} 316 317static int GetServiceCtrlInfoForPowerCtrl(const char *name, const char *value, ServiceCtrlInfo **ctrlInfo) 318{ 319 size_t size = 0; 320 const ParamCmdInfo *powerCtrlArg = GetStartupPowerCtl(&size); 321 PARAM_CHECK(powerCtrlArg != NULL, return -1, "Invalid ctrlInfo for %s", name); 322 uint32_t valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen("reboot") + 1; 323 if (strcmp(value, "reboot") == 0) { 324 return CreateCtrlInfo(ctrlInfo, "reboot", valueOffset, 1, 325 "%s%s.%s", OHOS_SERVICE_CTRL_PREFIX, "reboot", value); 326 } 327 for (size_t i = 0; i < size; i++) { 328 PARAM_LOGV("Get power ctrl %s name %s value %s", powerCtrlArg[i].name, name, value); 329 if (strncmp(value, powerCtrlArg[i].name, strlen(powerCtrlArg[i].name)) == 0) { 330 valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen(powerCtrlArg[i].replace) + 1; 331 return CreateCtrlInfo(ctrlInfo, powerCtrlArg[i].cmd, valueOffset, 1, 332 "%s%s.%s", OHOS_SERVICE_CTRL_PREFIX, powerCtrlArg[i].replace, value); 333 } 334 } 335 // not found reboot, so reboot by normal 336 valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen("reboot") + 1; 337 return CreateCtrlInfo(ctrlInfo, "reboot.other", valueOffset, 1, "%s%s.%s", 338 OHOS_SERVICE_CTRL_PREFIX, "reboot", value); 339} 340 341INIT_LOCAL_API int GetServiceCtrlInfo(const char *name, const char *value, ServiceCtrlInfo **ctrlInfo) 342{ 343 PARAM_CHECK(ctrlInfo != NULL, return -1, "Invalid ctrlInfo %s", name); 344 *ctrlInfo = NULL; 345 size_t size = 0; 346 if (strcmp("ohos.startup.powerctrl", name) == 0) { 347 return GetServiceCtrlInfoForPowerCtrl(name, value, ctrlInfo); 348 } 349 if (strncmp("ohos.ctl.", name, strlen("ohos.ctl.")) == 0) { 350 const ParamCmdInfo *ctrlParam = GetServiceStartCtrl(&size); 351 PARAM_CHECK(ctrlParam != NULL, return -1, "Invalid ctrlInfo for %s", name); 352 for (size_t i = 0; i < size; i++) { 353 if (strcmp(name, ctrlParam[i].name) == 0) { 354 uint32_t valueOffset = strlen(OHOS_SERVICE_CTRL_PREFIX) + strlen(ctrlParam[i].replace) + 1; 355 return CreateCtrlInfo(ctrlInfo, ctrlParam[i].cmd, valueOffset, 1, 356 "%s%s.%s", OHOS_SERVICE_CTRL_PREFIX, ctrlParam[i].replace, value); 357 } 358 } 359 } 360 if (strncmp("ohos.servicectrl.", name, strlen("ohos.servicectrl.")) == 0) { 361 const ParamCmdInfo *installParam = GetServiceCtl(&size); 362 PARAM_CHECK(installParam != NULL, return -1, "Invalid ctrlInfo for %s", name); 363 for (size_t i = 0; i < size; i++) { 364 if (strncmp(name, installParam[i].name, strlen(installParam[i].name)) == 0) { 365 return CreateCtrlInfo(ctrlInfo, installParam[i].cmd, strlen(name) + 1, 1, "%s.%s", name, value); 366 } 367 } 368 } 369 const ParamCmdInfo *other = GetOtherSpecial(&size); 370 for (size_t i = 0; i < size; i++) { 371 if (strncmp(name, other[i].name, strlen(other[i].name)) == 0) { 372 return CreateCtrlInfo(ctrlInfo, other[i].cmd, strlen(other[i].replace), 0, "%s.%s", name, value); 373 } 374 } 375 return 0; 376} 377 378INIT_LOCAL_API int CheckParameterSet(const char *name, 379 const char *value, const ParamSecurityLabel *srcLabel, int *ctrlService) 380{ 381 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 382 PARAM_CHECK(paramSpace != NULL, return PARAM_WORKSPACE_NOT_INIT, "Invalid paramSpace"); 383 PARAM_WORKSPACE_CHECK(paramSpace, return PARAM_WORKSPACE_NOT_INIT, "Invalid space"); 384 PARAM_LOGV("CheckParameterSet name %s value: %s", name, value); 385 PARAM_CHECK(srcLabel != NULL && ctrlService != NULL, return -1, "Invalid param "); 386 int ret = CheckParamName(name, 0); 387 PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name); 388 ret = CheckParamValue(NULL, name, value, GetParamValueType(name)); 389 PARAM_CHECK(ret == 0, return ret, "Illegal param value %s", value); 390 *ctrlService = 0; 391 392 ServiceCtrlInfo *serviceInfo = NULL; 393 GetServiceCtrlInfo(name, value, &serviceInfo); 394 ret = CheckParamPermission(srcLabel, (serviceInfo == NULL) ? name : serviceInfo->realKey, DAC_WRITE); 395 if (ret == 0) { 396 if (serviceInfo == NULL) { 397 return 0; 398 } 399 if (serviceInfo->ctrlParam != 0) { // ctrl param 400 *ctrlService |= PARAM_CTRL_SERVICE; 401 } 402#if !(defined __LITEOS_A__ || defined __LITEOS_M__) 403 // do hook cmd 404 PARAM_LOGV("Check parameter settings realKey %s cmd: '%s' value: %s", 405 serviceInfo->realKey, serviceInfo->cmdName, (char *)serviceInfo->realKey + serviceInfo->valueOffset); 406 int cmdIndex = 0; 407 (void)GetMatchCmd(serviceInfo->cmdName, &cmdIndex); 408 DoCmdByIndex(cmdIndex, (char *)serviceInfo->realKey + serviceInfo->valueOffset, NULL); 409#endif 410 } 411 if (serviceInfo != NULL) { 412 free(serviceInfo); 413 } 414 return ret; 415} 416 417int SystemGetParameterName(ParamHandle handle, char *name, unsigned int len) 418{ 419 PARAM_CHECK(name != NULL && handle != 0, return -1, "The name is null"); 420 return ReadParamName(handle, name, len); 421} 422 423static int AddParam(WorkSpace *workSpace, ParamInfos paramInfos, uint32_t *dataIndex) 424{ 425 ParamTrieNode *node = AddTrieNode(workSpace, paramInfos.name, strlen(paramInfos.name)); 426 PARAM_CHECK(node != NULL, return PARAM_CODE_REACHED_MAX, 427 "Failed to add node name %s space %s", paramInfos.name, workSpace->fileName); 428 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex); 429 if (entry == NULL) { 430 uint32_t offset = AddParamNode(workSpace, paramInfos.type, paramInfos.name, 431 strlen(paramInfos.name), paramInfos.value, strlen(paramInfos.value), paramInfos.mode); 432 PARAM_CHECK(offset > 0, return PARAM_CODE_REACHED_MAX, 433 "Failed to allocate name %s space %s", paramInfos.name, workSpace->fileName); 434 SaveIndex(&node->dataIndex, offset); 435 ATOMIC_SYNC_ADD_AND_FETCH(&workSpace->area->commitId, 1, MEMORY_ORDER_RELEASE); 436#ifdef PARAM_SUPPORT_SELINUX 437 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC); 438 if (space != NULL && space != workSpace) { // dac commit is global commit 439 ATOMIC_SYNC_ADD_AND_FETCH(&space->area->commitId, 1, MEMORY_ORDER_RELEASE); 440 } 441#endif 442 } 443 if (dataIndex != NULL) { 444 *dataIndex = node->dataIndex; 445 } 446 PARAM_LOGV("AddParam name %s value: %s", paramInfos.name, paramInfos.value); 447 return 0; 448} 449 450static int UpdateParam(const WorkSpace *workSpace, uint32_t *dataIndex, const char *name, const char *value, int mode) 451{ 452 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, *dataIndex); 453 PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX, "Failed to update param value %s %u", name, *dataIndex); 454 PARAM_CHECK(entry->keyLength == strlen(name), return PARAM_CODE_INVALID_NAME, "Failed to check name len %s", name); 455 456 uint32_t valueLen = strlen(value); 457 uint32_t commitId = ATOMIC_LOAD_EXPLICIT(&entry->commitId, MEMORY_ORDER_RELAXED); 458 ATOMIC_STORE_EXPLICIT(&entry->commitId, commitId | PARAM_FLAGS_MODIFY, MEMORY_ORDER_RELAXED); 459 if (entry->valueLength < PARAM_VALUE_LEN_MAX && valueLen < PARAM_VALUE_LEN_MAX) { 460 int ret = PARAM_MEMCPY(entry->data + entry->keyLength + 1, PARAM_VALUE_LEN_MAX, value, valueLen + 1); 461 PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_VALUE, "Failed to copy value"); 462 entry->valueLength = valueLen; 463 } 464 465 uint32_t flags = commitId & ~PARAM_FLAGS_COMMITID; 466 uint32_t commitIdCount = (++commitId) & PARAM_FLAGS_COMMITID; 467 ATOMIC_STORE_EXPLICIT(&entry->commitId, flags | commitIdCount, MEMORY_ORDER_RELEASE); 468 ATOMIC_SYNC_ADD_AND_FETCH(&workSpace->area->commitId, 1, MEMORY_ORDER_RELEASE); 469#ifdef PARAM_SUPPORT_SELINUX 470 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC); 471 if (space != NULL && space != workSpace) { // dac commit is global commit 472 ATOMIC_SYNC_ADD_AND_FETCH(&space->area->commitId, 1, MEMORY_ORDER_RELEASE); 473 } 474#endif 475 PARAM_LOGV("UpdateParam name %s value: %s", name, value); 476 477 if (((unsigned int)mode & LOAD_PARAM_PERSIST) != 0) { 478 entry->commitId |= PARAM_FLAGS_PERSIST; 479 } 480 futex_wake(&entry->commitId, INT_MAX); 481 return 0; 482} 483 484INIT_LOCAL_API int WriteParam(const char *name, const char *value, uint32_t *dataIndex, int mode) 485{ 486 int flag = 0; 487 PARAM_LOGV("WriteParam %s", name); 488 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 489 PARAM_CHECK(paramSpace != NULL, return PARAM_WORKSPACE_NOT_INIT, "Invalid paramSpace"); 490 PARAM_WORKSPACE_CHECK(paramSpace, return PARAM_WORKSPACE_NOT_INIT, "Invalid space"); 491 PARAM_CHECK(value != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid name or value"); 492 WorkSpace *workSpace = GetWorkSpaceByName(name); 493 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace"); 494#ifdef PARAM_SUPPORT_SELINUX 495 if (strcmp(workSpace->fileName, WORKSPACE_NAME_DEF_SELINUX) == 0) { 496 flag = 1; 497 } 498#endif 499 ParamTrieNode *node = FindTrieNode(workSpace, name, strlen(name), NULL); 500 int ret = 0; 501 if (node != NULL && node->dataIndex != 0) { 502 if (dataIndex != NULL) { 503 *dataIndex = node->dataIndex; 504 } 505 if ((mode & LOAD_PARAM_ONLY_ADD) == LOAD_PARAM_ONLY_ADD) { 506 return PARAM_CODE_READ_ONLY; 507 } 508 ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex); 509 PARAM_CHECK(entry != NULL, return PARAM_CODE_REACHED_MAX, 510 "Failed to update param value %s %u", name, node->dataIndex); 511 // use save type to check value 512 ret = CheckParamValue(node, name, value, entry->type); 513 PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value); 514 PARAMSPACE_AREA_RW_LOCK(workSpace); 515 ret = UpdateParam(workSpace, &node->dataIndex, name, value, mode); 516 PARAMSPACE_AREA_RW_UNLOCK(workSpace); 517 } else { 518 uint8_t type = GetParamValueType(name); 519 ret = CheckParamValue(node, name, value, type); 520 PARAM_CHECK(ret == 0, return ret, "Invalid param value param: %s=%s", name, value); 521 PARAMSPACE_AREA_RW_LOCK(workSpace); 522 ParamInfos paramInfos = {type, mode, name, value}; 523 ret = AddParam((WorkSpace *)workSpace, paramInfos, dataIndex); 524 PARAMSPACE_AREA_RW_UNLOCK(workSpace); 525 } 526 if ((ret == PARAM_CODE_REACHED_MAX) && (flag == 1)) { 527 PARAM_LOGE("Add node %s to space %s failed! memory is not enough, system reboot!", name, workSpace->fileName); 528 return PARAM_DEFAULT_PARAM_MEMORY_NOT_ENOUGH; 529 } 530 return ret; 531} 532 533INIT_LOCAL_API WorkSpace *GetNextWorkSpace(WorkSpace *curr) 534{ 535 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 536 PARAM_CHECK(paramSpace != NULL, return NULL, "Invalid paramSpace"); 537 uint32_t i = (curr == NULL) ? 0 : (curr->spaceIndex + 1); 538 WorkSpace *workSpace = NULL; 539 for (; i < paramSpace->maxLabelIndex; ++i) { 540 workSpace = GetWorkSpace(i); 541 if (workSpace != NULL) { 542 return workSpace; 543 } 544 } 545 return NULL; 546} 547 548INIT_LOCAL_API uint8_t GetParamValueType(const char *name) 549{ 550 uint32_t labelIndex = 0; 551 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC); 552 if (space == NULL) { 553 return PARAM_TYPE_STRING; 554 } 555 (void)FindTrieNode(space, name, strlen(name), &labelIndex); 556 ParamSecurityNode *securityNode = (ParamSecurityNode *)GetTrieNode(space, labelIndex); 557 if (securityNode == NULL) { 558 return PARAM_TYPE_STRING; 559 } 560 return securityNode->type; 561} 562 563static int CheckParamValueType(const char *name, const char *value, uint8_t paramType) 564{ 565 (void)name; 566 if (paramType == PARAM_TYPE_INT) { 567 long long int temp1 = 0; 568 if (strlen(value) > 1 && value[0] == '-' && StringToLL(value, &temp1) != 0) { 569 PARAM_LOGE("Illegal param value %s for int", value); 570 return PARAM_CODE_INVALID_VALUE; 571 } 572 unsigned long long int temp2 = 0; 573 if (StringToULL(value, &temp2) != 0) { 574 PARAM_LOGE("Illegal param value %s for int", value); 575 return PARAM_CODE_INVALID_VALUE; 576 } 577 } else if (paramType == PARAM_TYPE_BOOL) { 578 static const char *validValue[] = { 579 "1", "0", "true", "false", "y", "yes", "on", "off", "n", "no" 580 }; 581 size_t i = 0; 582 for (; i < ARRAY_LENGTH(validValue); i++) { 583 if (strcasecmp(validValue[i], value) == 0) { 584 break; 585 } 586 } 587 if (i >= ARRAY_LENGTH(validValue)) { 588 PARAM_LOGE("Illegal param value %s for bool", value); 589 return PARAM_CODE_INVALID_VALUE; 590 } 591 } 592 return 0; 593} 594 595INIT_LOCAL_API int CheckParamValue(const ParamTrieNode *node, const char *name, const char *value, uint8_t paramType) 596{ 597 if (IS_READY_ONLY(name)) { 598 PARAM_CHECK(strlen(value) < PARAM_CONST_VALUE_LEN_MAX, 599 return PARAM_CODE_INVALID_VALUE, "Illegal param value %s", value); 600 if (node != NULL && node->dataIndex != 0) { 601 PARAM_LOGE("Read-only param was already set %s", name); 602 return PARAM_CODE_READ_ONLY; 603 } 604 } else { 605 PARAM_CHECK(strlen(value) < GetParamMaxLen(paramType), 606 return PARAM_CODE_INVALID_VALUE, "Illegal param value %s length", value); 607 } 608 return CheckParamValueType(name, value, paramType); 609} 610 611static int ReadParamName(ParamHandle handle, char *name, uint32_t length) 612{ 613 PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); 614 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 615 PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Param workspace has not init."); 616 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND); 617 uint32_t labelIndex = 0; 618 uint32_t index = 0; 619 PARAM_GET_HANDLE_INFO(handle, labelIndex, index); 620 WorkSpace *workSpace = GetWorkSpace(labelIndex); 621 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_NOT_FOUND, "Invalid workSpace for handle %x", handle); 622 ParamNode *entry = NULL; 623 if (PARAM_IS_ALIGNED(index)) { 624 entry = (ParamNode *)GetTrieNode(workSpace, index); 625 } 626 if (entry == NULL) { 627 return PARAM_CODE_NOT_FOUND; 628 } 629 PARAM_CHECK(length > entry->keyLength, return -1, "Invalid param size %u %u", entry->keyLength, length); 630 int ret = PARAM_MEMCPY(name, length, entry->data, entry->keyLength); 631 PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_PARAM, "Failed to copy name"); 632 name[entry->keyLength] = '\0'; 633 return 0; 634} 635 636INIT_LOCAL_API int CheckParamName(const char *name, int info) 637{ 638 PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param"); 639 size_t nameLen = strlen(name); 640 if (nameLen >= PARAM_NAME_LEN_MAX) { 641 return PARAM_CODE_INVALID_NAME; 642 } 643 if (strcmp(name, "#") == 0) { 644 return 0; 645 } 646 647 if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) { 648 PARAM_LOGE("CheckParamName %s %d", name, info); 649 return PARAM_CODE_INVALID_NAME; 650 } 651 652 /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */ 653 /* Don't allow ".." to appear in a param name */ 654 for (size_t i = 0; i < nameLen; i++) { 655 if (name[i] == '.') { 656 if (name[i - 1] == '.') { 657 return PARAM_CODE_INVALID_NAME; 658 } 659 continue; 660 } 661 if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') { 662 continue; 663 } 664 if (isalnum(name[i])) { 665 continue; 666 } 667 return PARAM_CODE_INVALID_NAME; 668 } 669 return 0; 670} 671 672static int CheckParamPermission_(WorkSpace **workspace, ParamTrieNode **node, 673 const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode) 674{ 675 ParamWorkSpace *paramSpace = GetParamWorkSpace(); 676 PARAM_CHECK(srcLabel != NULL, return DAC_RESULT_FORBIDED, "The srcLabel is null"); 677 WorkSpace *dacSpace = GetWorkSpace(WORKSPACE_INDEX_DAC); 678 PARAM_CHECK(paramSpace->checkParamPermission != NULL, return DAC_RESULT_FORBIDED, "Invalid check permission"); 679 ParamLabelIndex labelIndex = {0}; 680 // search node from dac space, and get selinux label index 681 *node = FindTrieNode(dacSpace, name, strlen(name), &labelIndex.dacLabelIndex); 682 labelIndex.workspace = GetWorkSpaceByName(name); 683 PARAM_CHECK(labelIndex.workspace != NULL, return DAC_RESULT_FORBIDED, "Invalid workSpace for %s", name); 684 labelIndex.selinuxLabelIndex = labelIndex.workspace->spaceIndex; 685 686 int ret = paramSpace->checkParamPermission(&labelIndex, srcLabel, name, mode); 687 PARAM_CHECK(ret == 0, return ret, 688 "Forbid to access %s label %u %u", name, labelIndex.dacLabelIndex, labelIndex.selinuxLabelIndex); 689 *workspace = labelIndex.workspace; 690 return ret; 691} 692 693INIT_LOCAL_API int CheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode) 694{ 695 ParamTrieNode *entry = NULL; 696 WorkSpace *workspace = NULL; 697 return CheckParamPermission_(&workspace, &entry, srcLabel, name, mode); 698} 699 700STATIC_INLINE ParamTrieNode *GetTrieNodeByHandle(ParamHandle handle) 701{ 702 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return NULL); 703 uint32_t labelIndex = 0; 704 uint32_t index = 0; 705 PARAM_GET_HANDLE_INFO(handle, labelIndex, index); 706 WorkSpace *workSpace = GetWorkSpace(labelIndex); 707 PARAM_CHECK(workSpace != NULL, return NULL, "Invalid workSpace for handle %x", handle); 708 if (PARAM_IS_ALIGNED(index)) { 709 return (ParamTrieNode *)GetTrieNode(workSpace, index); 710 } 711 return NULL; 712} 713 714STATIC_INLINE int ReadParamValue(ParamNode *entry, char *value, uint32_t *length) 715{ 716 if (entry == NULL) { 717 return PARAM_CODE_NOT_FOUND; 718 } 719 if (value == NULL) { 720 *length = entry->valueLength + 1; 721 return 0; 722 } 723 PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_VALUE, 724 "Invalid value len %u %u", *length, entry->valueLength); 725 uint32_t commitId = ReadCommitId(entry); 726 return ReadParamValue_(entry, &commitId, value, length); 727} 728 729int SystemReadParam(const char *name, char *value, uint32_t *len) 730{ 731 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return PARAM_WORKSPACE_NOT_INIT, 732 "SystemReadParam failed! name is:%s, errNum is:%d!", name, PARAM_WORKSPACE_NOT_INIT); 733 PARAM_CHECK(name != NULL && len != NULL, return PARAM_CODE_ERROR, 734 "SystemReadParam failed! name is:%s, errNum is:%d!", name, PARAM_CODE_ERROR); 735 ParamTrieNode *node = NULL; 736 WorkSpace *workspace = NULL; 737 int ret = CheckParamPermission_(&workspace, &node, GetParamSecurityLabel(), name, DAC_READ); 738 if (ret != 0) { 739 PARAM_LOGE("SystemReadParam failed! name is:%s, errNum is:%d!", name, ret); 740 return ret; 741 } 742#ifdef PARAM_SUPPORT_SELINUX 743 // search from real workspace 744 node = FindTrieNode(workspace, name, strlen(name), NULL); 745#endif 746 if (node == NULL) { 747 return PARAM_CODE_NOT_FOUND; 748 } 749 ret = ReadParamValue((ParamNode *)GetTrieNode(workspace, node->dataIndex), value, len); 750 if (ret != 0) { 751 PARAM_LOGE("SystemReadParam failed! name is:%s, errNum is:%d!", name, ret); 752 } 753 return ret; 754} 755 756int SystemFindParameter(const char *name, ParamHandle *handle) 757{ 758 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return PARAM_WORKSPACE_NOT_INIT, "Param workspace has not init."); 759 PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null"); 760 *handle = -1; 761 ParamTrieNode *entry = NULL; 762 WorkSpace *workspace = NULL; 763 int ret = CheckParamPermission_(&workspace, &entry, GetParamSecurityLabel(), name, DAC_READ); 764 PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name); 765#ifdef PARAM_SUPPORT_SELINUX 766 // search from real workspace 767 entry = FindTrieNode(workspace, name, strlen(name), NULL); 768#endif 769 if (entry != NULL && entry->dataIndex != 0) { 770 *handle = PARAM_HANDLE(workspace, entry->dataIndex); 771 return 0; 772 } else if (entry != NULL) { 773 return PARAM_CODE_NODE_EXIST; 774 } 775 return PARAM_CODE_NOT_FOUND; 776} 777 778int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId) 779{ 780 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init."); 781 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND); 782 PARAM_CHECK(handle != 0 && commitId != NULL, return -1, "The handle is null"); 783 ParamNode *entry = (ParamNode *)GetTrieNodeByHandle(handle); 784 if (entry == NULL) { 785 return PARAM_CODE_NOT_FOUND; 786 } 787 *commitId = ReadCommitId(entry); 788 return 0; 789} 790 791long long GetSystemCommitId(void) 792{ 793 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init."); 794 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC); 795 if (space == NULL || space->area == NULL) { 796 return 0; 797 } 798 return ATOMIC_UINT64_LOAD_EXPLICIT(&space->area->commitId, MEMORY_ORDER_ACQUIRE); 799} 800 801int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len) 802{ 803 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init."); 804 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND); 805 PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null"); 806 return ReadParamValue((ParamNode *)GetTrieNodeByHandle(handle), value, len); 807} 808 809INIT_LOCAL_API int CheckIfUidInGroup(const gid_t groupId, const char *groupCheckName) 810{ 811 PARAM_CHECK(groupCheckName != NULL, return -1, "Invalid groupCheckName"); 812 struct group *groupName = getgrnam(groupCheckName); 813 PARAM_CHECK(groupName != NULL, return -1, "Not find %s group", groupCheckName); 814 char **gr_mem = groupName->gr_mem; 815 PARAM_CHECK(gr_mem != NULL, return -1, "No member in %s", groupCheckName); 816 for (int i = 0; gr_mem[i] != NULL; ++i) { 817 struct group *userGroup = getgrnam(gr_mem[i]); 818 if (userGroup != NULL) { 819 if (groupId == userGroup->gr_gid) { 820 return 0; 821 } 822 } 823 } 824 PARAM_LOGE("Forbid to access, groupId %u not in %s", groupId, groupCheckName); 825 return PARAM_CODE_PERMISSION_DENIED; 826} 827