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"
28 static DUMP_PRINTF g_printf = printf;
29
30 static int ReadParamName(ParamHandle handle, char *name, uint32_t length);
31
SystemCheckMatchParamWait(const char * name,const char * value)32 ParamNode *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
ProcessParamTraversal(const WorkSpace * workSpace,const ParamTrieNode * node,const void * cookie)64 static 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
SystemTraversalParameter(const char * prefix,TraversalParamPtr traversalParameter,void * cookie)86 int 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
DumpTrieDataNodeTraversal(const WorkSpace * workSpace,const ParamTrieNode * node,const void * cookie)124 static 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
HashNodeTraverseForDump(WorkSpace * workSpace,int verbose)161 static 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
SystemDumpParameters(int verbose,int index,int (* dump)(const char * fmt,...))184 void 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
SysCheckParamExist(const char * name)239 INIT_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
GetParamSecurityAuditData(const char * name,int type,ParamAuditData * auditData)267 INIT_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
CreateCtrlInfo(ServiceCtrlInfo ** ctrlInfo,const char * cmd,uint32_t offset,uint8_t ctrlParam,const char * format,...)296 static 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
GetServiceCtrlInfoForPowerCtrl(const char * name,const char * value,ServiceCtrlInfo ** ctrlInfo)317 static 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
GetServiceCtrlInfo(const char * name,const char * value,ServiceCtrlInfo ** ctrlInfo)341 INIT_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
CheckParameterSet(const char * name,const char * value,const ParamSecurityLabel * srcLabel,int * ctrlService)378 INIT_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
SystemGetParameterName(ParamHandle handle,char * name,unsigned int len)417 int 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
AddParam(WorkSpace * workSpace,ParamInfos paramInfos,uint32_t * dataIndex)423 static 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
UpdateParam(const WorkSpace * workSpace,uint32_t * dataIndex,const char * name,const char * value,int mode)450 static 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
WriteParam(const char * name,const char * value,uint32_t * dataIndex,int mode)484 INIT_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
GetNextWorkSpace(WorkSpace * curr)533 INIT_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
GetParamValueType(const char * name)548 INIT_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
CheckParamValueType(const char * name,const char * value,uint8_t paramType)563 static 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
CheckParamValue(const ParamTrieNode * node,const char * name,const char * value,uint8_t paramType)595 INIT_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 PARAM_CHECK(strstr(value, "\n") == NULL,
609 return PARAM_CODE_INVALID_VALUE, "Illegal param value %s for \\n", value);
610 return CheckParamValueType(name, value, paramType);
611 }
612
ReadParamName(ParamHandle handle,char * name,uint32_t length)613 static int ReadParamName(ParamHandle handle, char *name, uint32_t length)
614 {
615 PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
616 ParamWorkSpace *paramSpace = GetParamWorkSpace();
617 PARAM_WORKSPACE_CHECK(paramSpace, return -1, "Param workspace has not init.");
618 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
619 uint32_t labelIndex = 0;
620 uint32_t index = 0;
621 PARAM_GET_HANDLE_INFO(handle, labelIndex, index);
622 WorkSpace *workSpace = GetWorkSpace(labelIndex);
623 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_NOT_FOUND, "Invalid workSpace for handle %x", handle);
624 ParamNode *entry = NULL;
625 if (PARAM_IS_ALIGNED(index)) {
626 entry = (ParamNode *)GetTrieNode(workSpace, index);
627 }
628 if (entry == NULL) {
629 return PARAM_CODE_NOT_FOUND;
630 }
631 PARAM_CHECK(length > entry->keyLength, return -1, "Invalid param size %u %u", entry->keyLength, length);
632 int ret = PARAM_MEMCPY(name, length, entry->data, entry->keyLength);
633 PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_PARAM, "Failed to copy name");
634 name[entry->keyLength] = '\0';
635 return 0;
636 }
637
CheckParamName(const char * name,int info)638 INIT_LOCAL_API int CheckParamName(const char *name, int info)
639 {
640 PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
641 size_t nameLen = strlen(name);
642 if (nameLen >= PARAM_NAME_LEN_MAX) {
643 return PARAM_CODE_INVALID_NAME;
644 }
645 if (strcmp(name, "#") == 0) {
646 return 0;
647 }
648
649 if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) {
650 PARAM_LOGE("CheckParamName %s %d", name, info);
651 return PARAM_CODE_INVALID_NAME;
652 }
653
654 /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
655 /* Don't allow ".." to appear in a param name */
656 for (size_t i = 0; i < nameLen; i++) {
657 if (name[i] == '.') {
658 if (name[i - 1] == '.') {
659 return PARAM_CODE_INVALID_NAME;
660 }
661 continue;
662 }
663 if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') {
664 continue;
665 }
666 if (isalnum(name[i])) {
667 continue;
668 }
669 return PARAM_CODE_INVALID_NAME;
670 }
671 return 0;
672 }
673
CheckParamPermission_(WorkSpace ** workspace,ParamTrieNode ** node,const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)674 static int CheckParamPermission_(WorkSpace **workspace, ParamTrieNode **node,
675 const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
676 {
677 ParamWorkSpace *paramSpace = GetParamWorkSpace();
678 PARAM_CHECK(srcLabel != NULL, return DAC_RESULT_FORBIDED, "The srcLabel is null");
679 WorkSpace *dacSpace = GetWorkSpace(WORKSPACE_INDEX_DAC);
680 PARAM_CHECK(paramSpace->checkParamPermission != NULL, return DAC_RESULT_FORBIDED, "Invalid check permission");
681 ParamLabelIndex labelIndex = {0};
682 // search node from dac space, and get selinux label index
683 *node = FindTrieNode(dacSpace, name, strlen(name), &labelIndex.dacLabelIndex);
684 labelIndex.workspace = GetWorkSpaceByName(name);
685 PARAM_CHECK(labelIndex.workspace != NULL, return DAC_RESULT_FORBIDED, "Invalid workSpace for %s", name);
686 labelIndex.selinuxLabelIndex = labelIndex.workspace->spaceIndex;
687
688 int ret = paramSpace->checkParamPermission(&labelIndex, srcLabel, name, mode);
689 PARAM_CHECK(ret == 0, return ret,
690 "Forbid to access %s label %u %u", name, labelIndex.dacLabelIndex, labelIndex.selinuxLabelIndex);
691 *workspace = labelIndex.workspace;
692 return ret;
693 }
694
CheckParamPermission(const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)695 INIT_LOCAL_API int CheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
696 {
697 ParamTrieNode *entry = NULL;
698 WorkSpace *workspace = NULL;
699 return CheckParamPermission_(&workspace, &entry, srcLabel, name, mode);
700 }
701
GetTrieNodeByHandle(ParamHandle handle)702 STATIC_INLINE ParamTrieNode *GetTrieNodeByHandle(ParamHandle handle)
703 {
704 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return NULL);
705 uint32_t labelIndex = 0;
706 uint32_t index = 0;
707 PARAM_GET_HANDLE_INFO(handle, labelIndex, index);
708 WorkSpace *workSpace = GetWorkSpace(labelIndex);
709 PARAM_CHECK(workSpace != NULL, return NULL, "Invalid workSpace for handle %x", handle);
710 if (PARAM_IS_ALIGNED(index)) {
711 return (ParamTrieNode *)GetTrieNode(workSpace, index);
712 }
713 return NULL;
714 }
715
ReadParamValue(ParamNode * entry,char * value,uint32_t * length)716 STATIC_INLINE int ReadParamValue(ParamNode *entry, char *value, uint32_t *length)
717 {
718 if (entry == NULL) {
719 return PARAM_CODE_NOT_FOUND;
720 }
721 if (value == NULL) {
722 *length = entry->valueLength + 1;
723 return 0;
724 }
725 PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_VALUE,
726 "Invalid value len %u %u", *length, entry->valueLength);
727 uint32_t commitId = ReadCommitId(entry);
728 return ReadParamValue_(entry, &commitId, value, length);
729 }
730
SystemReadParam(const char * name,char * value,uint32_t * len)731 int SystemReadParam(const char *name, char *value, uint32_t *len)
732 {
733 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return PARAM_WORKSPACE_NOT_INIT,
734 "SystemReadParam failed! name is:%s, errNum is:%d!", name, PARAM_WORKSPACE_NOT_INIT);
735 PARAM_CHECK(name != NULL && len != NULL, return PARAM_CODE_ERROR,
736 "SystemReadParam failed! name is:%s, errNum is:%d!", name, PARAM_CODE_ERROR);
737 ParamTrieNode *node = NULL;
738 WorkSpace *workspace = NULL;
739 int ret = CheckParamPermission_(&workspace, &node, GetParamSecurityLabel(), name, DAC_READ);
740 if (ret != 0) {
741 PARAM_LOGE("SystemReadParam failed! name is:%s, errNum is:%d!", name, ret);
742 return ret;
743 }
744 #ifdef PARAM_SUPPORT_SELINUX
745 // search from real workspace
746 node = FindTrieNode(workspace, name, strlen(name), NULL);
747 #endif
748 if (node == NULL) {
749 return PARAM_CODE_NOT_FOUND;
750 }
751 ret = ReadParamValue((ParamNode *)GetTrieNode(workspace, node->dataIndex), value, len);
752 if (ret != 0) {
753 PARAM_LOGE("SystemReadParam failed! name is:%s, errNum is:%d!", name, ret);
754 }
755 return ret;
756 }
757
SystemFindParameter(const char * name,ParamHandle * handle)758 int SystemFindParameter(const char *name, ParamHandle *handle)
759 {
760 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return PARAM_WORKSPACE_NOT_INIT, "Param workspace has not init.");
761 PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null");
762 *handle = -1;
763 ParamTrieNode *entry = NULL;
764 WorkSpace *workspace = NULL;
765 int ret = CheckParamPermission_(&workspace, &entry, GetParamSecurityLabel(), name, DAC_READ);
766 PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
767 #ifdef PARAM_SUPPORT_SELINUX
768 // search from real workspace
769 entry = FindTrieNode(workspace, name, strlen(name), NULL);
770 #endif
771 if (entry != NULL && entry->dataIndex != 0) {
772 *handle = PARAM_HANDLE(workspace, entry->dataIndex);
773 return 0;
774 } else if (entry != NULL) {
775 return PARAM_CODE_NODE_EXIST;
776 }
777 return PARAM_CODE_NOT_FOUND;
778 }
779
SystemGetParameterCommitId(ParamHandle handle,uint32_t * commitId)780 int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId)
781 {
782 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
783 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
784 PARAM_CHECK(handle != 0 && commitId != NULL, return -1, "The handle is null");
785 ParamNode *entry = (ParamNode *)GetTrieNodeByHandle(handle);
786 if (entry == NULL) {
787 return PARAM_CODE_NOT_FOUND;
788 }
789 *commitId = ReadCommitId(entry);
790 return 0;
791 }
792
GetSystemCommitId(void)793 long long GetSystemCommitId(void)
794 {
795 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
796 WorkSpace *space = GetWorkSpace(WORKSPACE_INDEX_DAC);
797 if (space == NULL || space->area == NULL) {
798 return 0;
799 }
800 return ATOMIC_UINT64_LOAD_EXPLICIT(&space->area->commitId, MEMORY_ORDER_ACQUIRE);
801 }
802
SystemGetParameterValue(ParamHandle handle,char * value,unsigned int * len)803 int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len)
804 {
805 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return -1, "Param workspace has not init.");
806 PARAM_ONLY_CHECK(handle != (ParamHandle)-1, return PARAM_CODE_NOT_FOUND);
807 PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null");
808 return ReadParamValue((ParamNode *)GetTrieNodeByHandle(handle), value, len);
809 }
810
CheckIfUidInGroup(const gid_t groupId,const char * groupCheckName)811 INIT_LOCAL_API int CheckIfUidInGroup(const gid_t groupId, const char *groupCheckName)
812 {
813 PARAM_CHECK(groupCheckName != NULL, return -1, "Invalid groupCheckName");
814 struct group *groupName = getgrnam(groupCheckName);
815 PARAM_CHECK(groupName != NULL, return -1, "Not find %s group", groupCheckName);
816 char **gr_mem = groupName->gr_mem;
817 PARAM_CHECK(gr_mem != NULL, return -1, "No member in %s", groupCheckName);
818 for (int i = 0; gr_mem[i] != NULL; ++i) {
819 struct group *userGroup = getgrnam(gr_mem[i]);
820 if (userGroup != NULL) {
821 if (groupId == userGroup->gr_gid) {
822 return 0;
823 }
824 }
825 }
826 PARAM_LOGE("Forbid to access, groupId %u not in %s", groupId, groupCheckName);
827 return PARAM_CODE_PERMISSION_DENIED;
828 }
829