• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&paramSpace->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 = &param->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, &param->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(&param->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, &param->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 }