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