1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "param_base.h"
16
17 #include <ctype.h>
18 #include <limits.h>
19
20 #include "param_manager.h"
21 #include "param_trie.h"
22
23 static int ReadParamValue(ParamHandle handle, char *value, uint32_t *length);
24
25 static ParamWorkSpace g_paramWorkSpace = {0};
WorkSpaceNodeCompare(const HashNode * node1,const HashNode * node2)26 PARAM_STATIC int WorkSpaceNodeCompare(const HashNode *node1, const HashNode *node2)
27 {
28 WorkSpace *workSpace1 = HASHMAP_ENTRY(node1, WorkSpace, hashNode);
29 WorkSpace *workSpace2 = HASHMAP_ENTRY(node2, WorkSpace, hashNode);
30 return strcmp(workSpace1->fileName, workSpace2->fileName);
31 }
32
WorkSpaceKeyCompare(const HashNode * node1,const void * key)33 static int WorkSpaceKeyCompare(const HashNode *node1, const void *key)
34 {
35 WorkSpace *workSpace1 = HASHMAP_ENTRY(node1, WorkSpace, hashNode);
36 return strcmp(workSpace1->fileName, (char *)key);
37 }
38
WorkSpaceGetNodeHasCode(const HashNode * node)39 static int WorkSpaceGetNodeHasCode(const HashNode *node)
40 {
41 WorkSpace *workSpace = HASHMAP_ENTRY(node, WorkSpace, hashNode);
42 size_t nameLen = strlen(workSpace->fileName);
43 return GenerateKeyHasCode(workSpace->fileName, nameLen);
44 }
45
WorkSpaceGetKeyHasCode(const void * key)46 static int WorkSpaceGetKeyHasCode(const void *key)
47 {
48 const char *buff = (char *)key;
49 return GenerateKeyHasCode(buff, strlen(buff));
50 }
51
WorkSpaceFree(const HashNode * node)52 static void WorkSpaceFree(const HashNode *node)
53 {
54 WorkSpace *workSpace = HASHMAP_ENTRY(node, WorkSpace, hashNode);
55 CloseWorkSpace(workSpace);
56 }
InitParamSecurity(ParamWorkSpace * workSpace,RegisterSecurityOpsPtr registerOps,ParamSecurityType type,int isInit,int op)57 static int InitParamSecurity(ParamWorkSpace *workSpace,
58 RegisterSecurityOpsPtr registerOps, ParamSecurityType type, int isInit, int op)
59 {
60 PARAM_CHECK(workSpace != NULL && type < PARAM_SECURITY_MAX, return -1, "Invalid param");
61 int ret = 0;
62 if (registerOps != NULL) {
63 ret = registerOps(&workSpace->paramSecurityOps[type], isInit);
64 PARAM_CHECK(workSpace->paramSecurityOps[type].securityInitLabel != NULL,
65 return -1, "Invalid securityInitLabel");
66 ret = workSpace->paramSecurityOps[type].securityInitLabel(&workSpace->securityLabel, isInit);
67 PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init security");
68 }
69
70 ParamSecurityOps *paramSecurityOps = GetParamSecurityOps(type);
71 PARAM_CHECK(paramSecurityOps != NULL, return -1, "Invalid paramSecurityOps");
72 PARAM_CHECK(paramSecurityOps->securityFreeLabel != NULL, return -1, "Invalid securityFreeLabel");
73 PARAM_CHECK(paramSecurityOps->securityCheckFilePermission != NULL, return -1, "Invalid securityCheck");
74 PARAM_CHECK(paramSecurityOps->securityCheckParamPermission != NULL, return -1, "Invalid securityCheck");
75 if (isInit == LABEL_INIT_FOR_INIT) {
76 PARAM_CHECK(paramSecurityOps->securityGetLabel != NULL, return -1, "Invalid securityGetLabel");
77 }
78 ret = paramSecurityOps->securityCheckFilePermission(&workSpace->securityLabel, PARAM_STORAGE_PATH, op);
79 PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "No permission to read file %s", PARAM_STORAGE_PATH);
80 PARAM_LOGI("Init parameter %s success", paramSecurityOps->name);
81 return 0;
82 }
83
RegisterSecurityOps(int onlyRead)84 INIT_LOCAL_API int RegisterSecurityOps(int onlyRead)
85 {
86 int isInit = 0;
87 int op = DAC_READ;
88 if (onlyRead == 0) {
89 isInit = LABEL_INIT_FOR_INIT;
90 op = DAC_WRITE;
91 }
92 int ret = InitParamSecurity(&g_paramWorkSpace, RegisterSecurityDacOps, PARAM_SECURITY_DAC, isInit, op);
93 PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
94 #ifdef PARAM_SUPPORT_SELINUX
95 ret = InitParamSecurity(&g_paramWorkSpace, RegisterSecuritySelinuxOps, PARAM_SECURITY_SELINUX, isInit, op);
96 PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
97 #endif
98 return ret;
99 }
100
CheckNeedInit(int onlyRead,const PARAM_WORKSPACE_OPS * ops)101 static int CheckNeedInit(int onlyRead, const PARAM_WORKSPACE_OPS *ops)
102 {
103 if (ops != NULL) {
104 g_paramWorkSpace.ops.updaterMode = ops->updaterMode;
105 if (g_paramWorkSpace.ops.logFunc == NULL) {
106 g_paramWorkSpace.ops.logFunc = ops->logFunc;
107 }
108 #ifdef PARAM_SUPPORT_SELINUX
109 g_paramWorkSpace.ops.setfilecon = ops->setfilecon;
110 #endif
111 }
112 if (PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) {
113 return 0;
114 }
115 if (onlyRead == 0) {
116 return 1;
117 }
118 #if !(defined __LITEOS_A__ || defined __LITEOS_M__)
119 if (getpid() == 1) { // init process only for write
120 return 0;
121 }
122 // for ut, do not init workspace
123 char path[PATH_MAX] = { 0 };
124 (void)readlink("/proc/self/exe", path, sizeof(path) - 1);
125 char *name = strrchr(path, '/');
126 if (name != NULL) {
127 name++;
128 } else {
129 name = path;
130 }
131 if (strcmp(name, "init_unittest") == 0) {
132 PARAM_LOGW("Can not init client for init_test");
133 return 0;
134 }
135 #endif
136 return 1;
137 }
138
InitParamWorkSpace(int onlyRead,const PARAM_WORKSPACE_OPS * ops)139 INIT_INNER_API int InitParamWorkSpace(int onlyRead, const PARAM_WORKSPACE_OPS *ops)
140 {
141 if (CheckNeedInit(onlyRead, ops) == 0) {
142 return 0;
143 }
144 paramMutexEnvInit();
145 HashInfo info = {
146 WorkSpaceNodeCompare,
147 WorkSpaceKeyCompare,
148 WorkSpaceGetNodeHasCode,
149 WorkSpaceGetKeyHasCode,
150 WorkSpaceFree,
151 HASH_BUTT
152 };
153 int ret = OH_HashMapCreate(&g_paramWorkSpace.workSpaceHashHandle, &info);
154 PARAM_CHECK(ret == 0, return -1, "Failed to create hash map for workspace");
155 WORKSPACE_INIT_LOCK(g_paramWorkSpace);
156 OH_ListInit(&g_paramWorkSpace.workSpaceList);
157 PARAM_SET_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT);
158
159 ret = RegisterSecurityOps(onlyRead);
160 PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
161
162 #ifndef PARAM_SUPPORT_SELINUX
163 ret = AddWorkSpace(WORKSPACE_NAME_NORMAL, onlyRead, PARAM_WORKSPACE_MAX);
164 PARAM_CHECK(ret == 0, return -1, "Failed to add dac workspace");
165 #endif
166 // add dac workspace
167 ret = AddWorkSpace(WORKSPACE_NAME_DAC, onlyRead, PARAM_WORKSPACE_SMALL);
168 PARAM_CHECK(ret == 0, return -1, "Failed to add dac workspace");
169 if (onlyRead == 0) {
170 // load user info for dac
171 LoadGroupUser();
172 // add default dac policy
173 ParamAuditData auditData = {0};
174 auditData.name = "#";
175 auditData.dacData.gid = DAC_DEFAULT_GROUP; // 2000 for shell
176 auditData.dacData.uid = DAC_DEFAULT_USER; // for root
177 auditData.dacData.mode = DAC_DEFAULT_MODE; // 0774 default mode
178 auditData.dacData.paramType = PARAM_TYPE_STRING;
179 ret = AddSecurityLabel(&auditData);
180 PARAM_CHECK(ret == 0, return ret, "Failed to add default dac label");
181 }
182 return ret;
183 }
184
CloseParamWorkSpace(void)185 INIT_LOCAL_API void CloseParamWorkSpace(void)
186 {
187 PARAM_LOGI("CloseParamWorkSpace");
188 if (!PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) {
189 return;
190 }
191 WORKSPACE_RW_LOCK(g_paramWorkSpace);
192 if (g_paramWorkSpace.workSpaceHashHandle != NULL) {
193 OH_HashMapDestory(g_paramWorkSpace.workSpaceHashHandle);
194 g_paramWorkSpace.workSpaceHashHandle = NULL;
195 }
196 WORKSPACE_RW_UNLOCK(g_paramWorkSpace);
197 for (int i = 0; i < PARAM_SECURITY_MAX; i++) {
198 if (g_paramWorkSpace.paramSecurityOps[i].securityFreeLabel != NULL) {
199 g_paramWorkSpace.paramSecurityOps[i].securityFreeLabel(&g_paramWorkSpace.securityLabel);
200 }
201 }
202 #ifdef PARAMWORKSPACE_NEED_MUTEX
203 ParamRWMutexDelete(&g_paramWorkSpace.rwlock);
204 #endif
205 g_paramWorkSpace.flags = 0;
206 }
207
ParamWorBaseLog(InitLogLevel logLevel,uint32_t domain,const char * tag,const char * fmt,...)208 INIT_LOCAL_API void ParamWorBaseLog(InitLogLevel logLevel, uint32_t domain, const char *tag, const char *fmt, ...)
209 {
210 if (g_paramWorkSpace.ops.logFunc != NULL) {
211 va_list vargs;
212 va_start(vargs, fmt);
213 g_paramWorkSpace.ops.logFunc(logLevel, domain, tag, fmt, vargs);
214 va_end(vargs);
215 }
216 }
217
GetParamWorkSpace(void)218 INIT_INNER_API ParamWorkSpace *GetParamWorkSpace(void)
219 {
220 if (!PARAM_TEST_FLAG(g_paramWorkSpace.flags, WORKSPACE_FLAGS_INIT)) {
221 PARAM_LOGE("GetParamWorkSpace %p", &g_paramWorkSpace);
222 return NULL;
223 }
224 return &g_paramWorkSpace;
225 }
226
SystemReadParam(const char * name,char * value,uint32_t * len)227 int SystemReadParam(const char *name, char *value, uint32_t *len)
228 {
229 PARAM_WORKSPACE_CHECK(&g_paramWorkSpace, return -1, "Param workspace has not init.");
230 PARAM_CHECK(name != NULL && len != NULL && strlen(name) > 0, return -1, "The name or value is null");
231 ParamHandle handle = 0;
232 int ret = ReadParamWithCheck(name, DAC_READ, &handle);
233 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
234 PARAM_CHECK(ret == 0, return ret, "Forbid to get parameter %s", name);
235 }
236 return ReadParamValue(handle, value, len);
237 }
238
InitParameterClient(void)239 void InitParameterClient(void)
240 {
241 if (getpid() == 1) {
242 return;
243 }
244 PARAM_WORKSPACE_OPS ops = {0};
245 ops.updaterMode = 0;
246 InitParamWorkSpace(1, &ops);
247 }
248
AddWorkSpace(const char * name,int onlyRead,uint32_t spaceSize)249 INIT_LOCAL_API int AddWorkSpace(const char *name, int onlyRead, uint32_t spaceSize)
250 {
251 ParamWorkSpace *paramSpace = GetParamWorkSpace();
252 PARAM_CHECK(paramSpace != NULL, return -1, "Invalid workspace");
253 int ret = 0;
254 // check exist
255 #ifdef PARAM_SUPPORT_SELINUX
256 const char *realName = name;
257 #else
258 const char *realName = WORKSPACE_NAME_NORMAL;
259 #endif
260 WORKSPACE_RW_LOCK(*paramSpace);
261 HashNode *node = OH_HashMapGet(paramSpace->workSpaceHashHandle, (const void *)realName);
262 if (node != NULL) {
263 WORKSPACE_RW_UNLOCK(*paramSpace);
264 return 0;
265 }
266 if (onlyRead == 0) {
267 PARAM_LOGI("AddWorkSpace %s spaceSize: %u onlyRead %s", name, spaceSize, onlyRead ? "true" : "false");
268 }
269 WorkSpace *workSpace = NULL;
270 do {
271 ret = -1;
272 const size_t size = strlen(realName) + 1;
273 workSpace = (WorkSpace *)malloc(sizeof(WorkSpace) + size);
274 PARAM_CHECK(workSpace != NULL, break, "Failed to create workspace for %s", realName);
275 workSpace->flags = 0;
276 workSpace->area = NULL;
277 OH_ListInit(&workSpace->node);
278 ret = ParamStrCpy(workSpace->fileName, size, realName);
279 PARAM_CHECK(ret == 0, break, "Failed to copy file name %s", realName);
280 HASHMAPInitNode(&workSpace->hashNode);
281 ret = InitWorkSpace(workSpace, onlyRead, spaceSize);
282 PARAM_CHECK(ret == 0, break, "Failed to init workspace %s", realName);
283 ret = OH_HashMapAdd(paramSpace->workSpaceHashHandle, &workSpace->hashNode);
284 PARAM_CHECK(ret == 0, CloseWorkSpace(workSpace);
285 workSpace = NULL;
286 break, "Failed to add hash node");
287 OH_ListAddTail(¶mSpace->workSpaceList, &workSpace->node);
288 ret = 0;
289 workSpace = NULL;
290 } while (0);
291 if (workSpace != NULL) {
292 free(workSpace);
293 }
294 WORKSPACE_RW_UNLOCK(*paramSpace);
295 PARAM_LOGV("AddWorkSpace %s %s", name, ret == 0 ? "success" : "fail");
296 return ret;
297 }
298
SystemFindParameter(const char * name,ParamHandle * handle)299 int SystemFindParameter(const char *name, ParamHandle *handle)
300 {
301 PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null");
302 int ret = ReadParamWithCheck(name, DAC_READ, handle);
303 if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
304 PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
305 }
306 return ret;
307 }
308
SystemGetParameterCommitId(ParamHandle handle,uint32_t * commitId)309 int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId)
310 {
311 PARAM_CHECK(handle != 0 && commitId != NULL, return -1, "The handle is null");
312
313 ParamNode *entry = (ParamNode *)GetTrieNodeByHandle(handle);
314 if (entry == NULL) {
315 return PARAM_CODE_NOT_FOUND;
316 }
317 *commitId = ReadCommitId(entry);
318 return 0;
319 }
320
GetSystemCommitId(void)321 long long GetSystemCommitId(void)
322 {
323 WorkSpace *space = GetWorkSpace(WORKSPACE_NAME_DAC);
324 if (space == NULL || space->area == NULL) {
325 return 0;
326 }
327 return ATOMIC_LOAD_EXPLICIT(&space->area->commitId, memory_order_acquire);
328 }
329
SystemGetParameterValue(ParamHandle handle,char * value,unsigned int * len)330 int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len)
331 {
332 PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null");
333 return ReadParamValue(handle, value, len);
334 }
335
ReadParamValue_(ParamNode * entry,uint32_t * commitId,char * value,uint32_t * length)336 static int ReadParamValue_(ParamNode *entry, uint32_t *commitId, char *value, uint32_t *length)
337 {
338 uint32_t id = *commitId;
339 do {
340 *commitId = id;
341 int ret = ParamMemcpy(value, *length, entry->data + entry->keyLength + 1, entry->valueLength);
342 PARAM_CHECK(ret == 0, return -1, "Failed to copy value");
343 value[entry->valueLength] = '\0';
344 *length = entry->valueLength;
345 id = ReadCommitId(entry);
346 } while (*commitId != id); // if change,must read
347 return 0;
348 }
349
ReadParamValue(ParamHandle handle,char * value,uint32_t * length)350 static int ReadParamValue(ParamHandle handle, char *value, uint32_t *length)
351 {
352 ParamWorkSpace *paramSpace = GetParamWorkSpace();
353 PARAM_CHECK(paramSpace != NULL, return -1, "Invalid workspace");
354 PARAM_CHECK(length != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
355 ParamNode *entry = (ParamNode *)GetTrieNodeByHandle(handle);
356 if (entry == NULL) {
357 return PARAM_CODE_NOT_FOUND;
358 }
359 if (value == NULL) {
360 *length = entry->valueLength + 1;
361 return 0;
362 }
363 PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_PARAM,
364 "Invalid value len %u %u", *length, entry->valueLength);
365 uint32_t commitId = ReadCommitId(entry);
366 return ReadParamValue_(entry, &commitId, value, length);
367 }
368
CachedParameterCreate(const char * name,const char * defValue)369 CachedHandle CachedParameterCreate(const char *name, const char *defValue)
370 {
371 PARAM_CHECK(name != NULL && defValue != NULL, return NULL, "Invalid name or default value");
372 PARAM_CHECK(GetParamWorkSpace() != NULL, return NULL, "Invalid workspace");
373 PARAM_WORKSPACE_CHECK(GetParamWorkSpace(), return NULL, "Invalid param workspace");
374 uint32_t nameLen = strlen(name);
375 PARAM_CHECK(nameLen < PARAM_NAME_LEN_MAX, return NULL, "Invalid name %s", name);
376 uint32_t valueLen = strlen(defValue);
377 if (IS_READY_ONLY(name)) {
378 PARAM_CHECK(valueLen < PARAM_CONST_VALUE_LEN_MAX, return NULL, "Illegal param value %s", defValue);
379 } else {
380 PARAM_CHECK(valueLen < PARAM_VALUE_LEN_MAX, return NULL, "Illegal param value %s length", defValue);
381 }
382
383 int ret = CheckParamPermission(GetParamSecurityLabel(), name, DAC_READ);
384 PARAM_CHECK(ret == 0, return NULL, "Forbid to access parameter %s", name);
385 WorkSpace *workspace = GetWorkSpace(name);
386 PARAM_CHECK(workspace != NULL, return NULL, "Invalid workSpace");
387 ParamTrieNode *node = FindTrieNode(workspace, name, strlen(name), NULL);
388
389 CachedParameter *param = (CachedParameter *)malloc(
390 sizeof(CachedParameter) + PARAM_ALIGN(nameLen) + 1 + PARAM_VALUE_LEN_MAX);
391 PARAM_CHECK(param != NULL, return NULL, "Failed to create CachedParameter for %s", name);
392 ret = ParamStrCpy(param->data, nameLen + 1, name);
393 PARAM_CHECK(ret == 0, free(param);
394 return NULL, "Failed to copy name %s", name);
395 param->workspace = workspace;
396 param->nameLen = nameLen;
397 param->paramValue = ¶m->data[PARAM_ALIGN(nameLen) + 1];
398 param->bufferLen = PARAM_VALUE_LEN_MAX;
399 param->dataCommitId = (uint32_t)-1;
400 if (node != NULL && node->dataIndex != 0) {
401 param->dataIndex = node->dataIndex;
402 ParamNode *entry = (ParamNode *)GetTrieNode(workspace, node->dataIndex);
403 PARAM_CHECK(entry != NULL, free(param);
404 return NULL, "Failed to get trie node %s", name);
405 uint32_t length = param->bufferLen;
406 param->dataCommitId = ReadCommitId(entry);
407 ret = ReadParamValue_(entry, ¶m->dataCommitId, param->paramValue, &length);
408 PARAM_CHECK(ret == 0, free(param);
409 return NULL, "Failed to read parameter value %s", name);
410 } else {
411 param->dataIndex = 0;
412 ret = ParamStrCpy(param->paramValue, param->bufferLen, defValue);
413 PARAM_CHECK(ret == 0, free(param);
414 return NULL, "Failed to copy name %s", name);
415 }
416 param->spaceCommitId = ATOMIC_LOAD_EXPLICIT(&workspace->area->commitId, memory_order_acquire);
417 PARAM_LOGV("CachedParameterCreate %u %u %lld \n", param->dataIndex, param->dataCommitId, param->spaceCommitId);
418 return (CachedHandle)param;
419 }
420
CachedParameterCheck(CachedParameter * param)421 static const char *CachedParameterCheck(CachedParameter *param)
422 {
423 if (param->dataIndex == 0) {
424 // no change, do not to find
425 long long spaceCommitId = ATOMIC_LOAD_EXPLICIT(¶m->workspace->area->commitId, memory_order_acquire);
426 if (param->spaceCommitId == spaceCommitId) {
427 return param->paramValue;
428 }
429 param->spaceCommitId = spaceCommitId;
430 ParamTrieNode *node = FindTrieNode(param->workspace, param->data, param->nameLen, NULL);
431 if (node != NULL) {
432 param->dataIndex = node->dataIndex;
433 } else {
434 return param->paramValue;
435 }
436 }
437 ParamNode *entry = (ParamNode *)GetTrieNode(param->workspace, param->dataIndex);
438 PARAM_CHECK(entry != NULL, return param->paramValue, "Failed to get trie node %s", param->data);
439 uint32_t dataCommitId = ATOMIC_LOAD_EXPLICIT(&entry->commitId, memory_order_acquire);
440 dataCommitId &= PARAM_FLAGS_COMMITID;
441 if (param->dataCommitId == dataCommitId) {
442 return param->paramValue;
443 }
444 uint32_t length = param->bufferLen;
445 param->dataCommitId = dataCommitId;
446 int ret = ReadParamValue_(entry, ¶m->dataCommitId, param->paramValue, &length);
447 PARAM_CHECK(ret == 0, return NULL, "Failed to copy value %s", param->data);
448 PARAM_LOGI("CachedParameterCheck %u", param->dataCommitId);
449 return param->paramValue;
450 }
451
CachedParameterGet(CachedHandle handle)452 const char *CachedParameterGet(CachedHandle handle)
453 {
454 CachedParameter *param = (CachedParameter *)handle;
455 PARAM_CHECK(param != NULL, return NULL, "Invalid handle");
456 return CachedParameterCheck(param);
457 }
458
CachedParameterDestroy(CachedHandle handle)459 void CachedParameterDestroy(CachedHandle handle)
460 {
461 if (handle != NULL) {
462 free(handle);
463 }
464 }