• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <dlfcn.h>
20 #ifdef WITH_SELINUX
21 #include "selinux_parameter.h"
22 #endif
23 
24 #if !defined PARAM_SUPPORT_SELINUX && !defined PARAM_SUPPORT_DAC
25 static ParamSecurityLabel g_defaultSecurityLabel;
26 #endif
27 
GetParamSecurityOps(ParamWorkSpace * workSpace,int isInit)28 static int GetParamSecurityOps(ParamWorkSpace *workSpace, int isInit)
29 {
30     UNUSED(isInit);
31 #if (defined PARAM_SUPPORT_SELINUX || defined PARAM_SUPPORT_DAC)
32     int ret = RegisterSecurityOps(&workSpace->paramSecurityOps, isInit);
33     PARAM_CHECK(workSpace->paramSecurityOps.securityInitLabel != NULL, return -1, "Invalid securityInitLabel");
34     ret = workSpace->paramSecurityOps.securityInitLabel(&workSpace->securityLabel, isInit);
35     PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init security");
36 #else
37     workSpace->securityLabel = &g_defaultSecurityLabel;
38     workSpace->securityLabel->flags |= LABEL_ALL_PERMISSION;
39 #endif
40     return 0;
41 }
42 
InitParamWorkSpace(ParamWorkSpace * workSpace,int onlyRead)43 int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead)
44 {
45     PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param");
46     if (PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
47         return 0;
48     }
49     int isInit = 0;
50     int op = DAC_READ;
51     if (onlyRead == 0) {
52         isInit = LABEL_INIT_FOR_INIT;
53         op = DAC_WRITE;
54     }
55     int ret = GetParamSecurityOps(workSpace, isInit);
56     PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
57     ParamSecurityOps *paramSecurityOps = &workSpace->paramSecurityOps;
58     if (!LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
59         PARAM_CHECK(paramSecurityOps->securityFreeLabel != NULL, return -1, "Invalid securityFreeLabel");
60         PARAM_CHECK(paramSecurityOps->securityCheckFilePermission != NULL, return -1, "Invalid securityCheck");
61         PARAM_CHECK(paramSecurityOps->securityCheckParamPermission != NULL, return -1, "Invalid securityCheck");
62         if (isInit == LABEL_INIT_FOR_INIT) {
63             PARAM_CHECK(paramSecurityOps->securityGetLabel != NULL, return -1, "Invalid securityGetLabel");
64             PARAM_CHECK(paramSecurityOps->securityDecodeLabel != NULL, return -1, "Invalid securityDecodeLabel");
65         } else {
66             PARAM_CHECK(paramSecurityOps->securityEncodeLabel != NULL, return -1, "Invalid securityEncodeLabel");
67         }
68         ret = paramSecurityOps->securityCheckFilePermission(workSpace->securityLabel, PARAM_STORAGE_PATH, op);
69         PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "No permission to read file %s", PARAM_STORAGE_PATH);
70     }
71     if (onlyRead) {
72         ret = InitWorkSpace(CLIENT_PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead);
73     } else {
74         ret = InitWorkSpace(PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead);
75     }
76     PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init workspace");
77     PARAM_SET_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT);
78     return ret;
79 }
80 
CloseParamWorkSpace(ParamWorkSpace * workSpace)81 void CloseParamWorkSpace(ParamWorkSpace *workSpace)
82 {
83     PARAM_CHECK(workSpace != NULL, return, "Invalid workSpace");
84     CloseWorkSpace(&workSpace->paramSpace);
85     if (workSpace->paramSecurityOps.securityFreeLabel != NULL) {
86         workSpace->paramSecurityOps.securityFreeLabel(workSpace->securityLabel);
87     }
88     workSpace->flags = 0;
89 }
90 
ReadCommitId(ParamNode * entry)91 static uint32_t ReadCommitId(ParamNode *entry)
92 {
93     uint32_t commitId = atomic_load_explicit(&entry->commitId, memory_order_acquire);
94     while (commitId & PARAM_FLAGS_MODIFY) {
95         futex_wait(&entry->commitId, commitId);
96         commitId = atomic_load_explicit(&entry->commitId, memory_order_acquire);
97     }
98     return commitId & PARAM_FLAGS_COMMITID;
99 }
100 
ReadParamCommitId(const ParamWorkSpace * workSpace,ParamHandle handle,uint32_t * commitId)101 int ReadParamCommitId(const ParamWorkSpace *workSpace, ParamHandle handle, uint32_t *commitId)
102 {
103     PARAM_CHECK(workSpace != NULL && commitId != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
104     ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
105     if (entry == NULL) {
106         return -1;
107     }
108     *commitId = ReadCommitId(entry);
109     return 0;
110 }
111 
ReadParamWithCheck(const ParamWorkSpace * workSpace,const char * name,uint32_t op,ParamHandle * handle)112 int ReadParamWithCheck(const ParamWorkSpace *workSpace, const char *name, uint32_t op, ParamHandle *handle)
113 {
114     PARAM_CHECK(handle != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param handle");
115     PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param name");
116     *handle = -1;
117 #ifdef READ_CHECK
118     int ret = CheckParamPermission(workSpace, workSpace->securityLabel, name, op);
119     PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
120 #endif
121     ParamTrieNode *node = FindTrieNode(&workSpace->paramSpace, name, strlen(name), NULL);
122     if (node != NULL && node->dataIndex != 0) {
123         *handle = node->dataIndex;
124         return 0;
125     } else if (node != NULL) {
126         return PARAM_CODE_NODE_EXIST;
127     }
128     return PARAM_CODE_NOT_FOUND;
129 }
130 
ReadParamValue(const ParamWorkSpace * workSpace,ParamHandle handle,char * value,uint32_t * length)131 int ReadParamValue(const ParamWorkSpace *workSpace, ParamHandle handle, char *value, uint32_t *length)
132 {
133     PARAM_CHECK(workSpace != NULL && length != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
134     ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
135     if (entry == NULL) {
136         return -1;
137     }
138     if (value == NULL) {
139         *length = entry->valueLength + 1;
140         return 0;
141     }
142     PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_PARAM,
143         "Invalid value len %u %u", *length, entry->valueLength);
144     uint32_t commitId = ReadCommitId(entry);
145     do {
146         int ret = memcpy_s(value, *length, entry->data + entry->keyLength + 1, entry->valueLength);
147         PARAM_CHECK(ret == EOK, return -1, "Failed to copy value");
148         value[entry->valueLength] = '\0';
149         *length = entry->valueLength;
150     } while (commitId != ReadCommitId(entry));
151     return 0;
152 }
153 
ReadParamName(const ParamWorkSpace * workSpace,ParamHandle handle,char * name,uint32_t length)154 int ReadParamName(const ParamWorkSpace *workSpace, ParamHandle handle, char *name, uint32_t length)
155 {
156     PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
157     ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
158     if (entry == NULL) {
159         return -1;
160     }
161     PARAM_CHECK(length > entry->keyLength, return -1, "Invalid param size %u %u", entry->keyLength, length);
162     int ret = memcpy_s(name, length, entry->data, entry->keyLength);
163     PARAM_CHECK(ret == EOK, return PARAM_CODE_INVALID_PARAM, "Failed to copy name");
164     name[entry->keyLength] = '\0';
165     return 0;
166 }
167 
CheckParamName(const char * name,int info)168 int CheckParamName(const char *name, int info)
169 {
170     PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
171     size_t nameLen = strlen(name);
172     if (nameLen >= PARAM_NAME_LEN_MAX) {
173         return PARAM_CODE_INVALID_NAME;
174     }
175     if (strcmp(name, "#") == 0) {
176         return 0;
177     }
178 
179     if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) {
180         PARAM_LOGE("CheckParamName %s %d", name, info);
181         return PARAM_CODE_INVALID_NAME;
182     }
183 
184     /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
185     /* Don't allow ".." to appear in a param name */
186     for (size_t i = 0; i < nameLen; i++) {
187         if (name[i] == '.') {
188             if (name[i - 1] == '.') {
189                 return PARAM_CODE_INVALID_NAME;
190             }
191             continue;
192         }
193         if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') {
194             continue;
195         }
196         if (isalnum(name[i])) {
197             continue;
198         }
199         return PARAM_CODE_INVALID_NAME;
200     }
201     return 0;
202 }
203 
ProcessParamTraversal(const WorkSpace * workSpace,const ParamTrieNode * node,void * cookie)204 static int ProcessParamTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, void *cookie)
205 {
206     UNUSED(workSpace);
207     ParamTraversalContext *context = (ParamTraversalContext *)cookie;
208     ParamTrieNode *current = (ParamTrieNode *)node;
209     if (current == NULL) {
210         return 0;
211     }
212     if (current->dataIndex == 0) {
213         return 0;
214     }
215     ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
216     if (entry == NULL) {
217         return 0;
218     }
219     if ((strcmp("#", context->prefix) != 0) &&
220         (strncmp(entry->data, context->prefix, strlen(context->prefix)) != 0)) {
221         return 0;
222     }
223     context->traversalParamPtr(current->dataIndex, context->context);
224     return 0;
225 }
226 
TraversalParam(const ParamWorkSpace * workSpace,const char * prefix,TraversalParamPtr walkFunc,void * cookie)227 int TraversalParam(const ParamWorkSpace *workSpace,
228     const char *prefix, TraversalParamPtr walkFunc, void *cookie)
229 {
230     PARAM_CHECK(workSpace != NULL && walkFunc != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
231     ParamTraversalContext context = {
232         walkFunc, cookie, prefix
233     };
234     ParamTrieNode *root = FindTrieNode(&workSpace->paramSpace, prefix, strlen(prefix), NULL);
235     PARAM_LOGV("TraversalParam prefix %s", prefix);
236     return TraversalTrieNode(&workSpace->paramSpace, root, ProcessParamTraversal, &context);
237 }
238 
239 #ifdef WITH_SELINUX
240 static void *g_selinuxHandle = NULL;
CheckParamPermissionWithSelinux(const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)241 static int CheckParamPermissionWithSelinux(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
242 {
243     static void (*setSelinuxLogCallback)();
244     static int (*setParamCheck)(const char *paraName, struct ucred *uc);
245     g_selinuxHandle = dlopen("/system/lib/libparaperm_checker.z.so", RTLD_LAZY);
246     if (g_selinuxHandle == NULL) {
247         PARAM_LOGE("Failed to dlopen libparaperm_checker.z.so, %s\n", dlerror());
248         return DAC_RESULT_FORBIDED;
249     }
250     if (setSelinuxLogCallback == NULL) {
251         setSelinuxLogCallback = (void (*)())dlsym(g_selinuxHandle, "SetSelinuxLogCallback");
252         if (setSelinuxLogCallback == NULL) {
253             PARAM_LOGE("Failed to dlsym setSelinuxLogCallback, %s\n", dlerror());
254             return DAC_RESULT_FORBIDED;
255         }
256     }
257     (*setSelinuxLogCallback)();
258 
259     if (setParamCheck == NULL) {
260         setParamCheck = (int (*)(const char *paraName, struct ucred *uc))dlsym(g_selinuxHandle, "SetParamCheck");
261         if (setParamCheck == NULL) {
262             PARAM_LOGE("Failed to dlsym setParamCheck, %s\n", dlerror());
263             return DAC_RESULT_FORBIDED;
264         }
265     }
266     struct ucred uc;
267     uc.pid = srcLabel->cred.pid;
268     uc.uid = srcLabel->cred.uid;
269     uc.gid = srcLabel->cred.gid;
270     int ret = setParamCheck(name, &uc);
271     if (ret != 0) {
272         PARAM_LOGI("Selinux check name %s pid %d uid %d %d result %d", name, uc.pid, uc.uid, uc.gid, ret);
273     }
274     return ret;
275 }
276 #endif
277 
CheckParamPermission(const ParamWorkSpace * workSpace,const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)278 int CheckParamPermission(const ParamWorkSpace *workSpace,
279     const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
280 {
281     PARAM_CHECK(workSpace != NULL && workSpace->securityLabel != NULL,
282         return PARAM_CODE_INVALID_PARAM, "Invalid param");
283     if (LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
284         return 0;
285     }
286     PARAM_CHECK(name != NULL && srcLabel != NULL, return -1, "Invalid param");
287 #ifdef WITH_SELINUX
288     if (mode == DAC_WRITE) {
289         int ret = CheckParamPermissionWithSelinux(srcLabel, name, mode);
290         if (ret != DAC_RESULT_PERMISSION) {
291             return DAC_RESULT_PERMISSION;
292         }
293     }
294 #endif
295     if (workSpace->paramSecurityOps.securityCheckParamPermission == NULL) {
296         return DAC_RESULT_FORBIDED;
297     }
298     uint32_t labelIndex = 0;
299     FindTrieNode(&workSpace->paramSpace, name, strlen(name), &labelIndex);
300     ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&workSpace->paramSpace, labelIndex);
301     PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
302 
303     ParamAuditData auditData = {};
304     auditData.name = name;
305     auditData.dacData.uid = node->uid;
306     auditData.dacData.gid = node->gid;
307     auditData.dacData.mode = node->mode;
308     auditData.label = node->data;
309     return workSpace->paramSecurityOps.securityCheckParamPermission(srcLabel, &auditData, mode);
310 }
311 
DumpTrieDataNodeTraversal(const WorkSpace * workSpace,const ParamTrieNode * node,void * cookie)312 static int DumpTrieDataNodeTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, void *cookie)
313 {
314     int verbose = *(int *)cookie;
315     ParamTrieNode *current = (ParamTrieNode *)node;
316     if (current == NULL) {
317         return 0;
318     }
319     if (verbose) {
320         PARAM_DUMP("\tTrie node info [%u,%u,%u] data: %u label: %u key length:%d \n\t  key: %s \n",
321             current->left, current->right, current->child,
322             current->dataIndex, current->labelIndex, current->length, current->key);
323     }
324     if (current->dataIndex != 0) {
325         ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
326         if (entry != NULL) {
327             PARAM_DUMP("\tparameter length info [%d, %d] \n\t  param: %s \n",
328                 entry->keyLength, entry->valueLength, (entry != NULL) ? entry->data : "null");
329         }
330     }
331     if (current->labelIndex != 0 && verbose) {
332         ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(workSpace, current->labelIndex);
333         if (label != NULL) {
334             PARAM_DUMP("\tparameter label dac %d %d %o \n\t  label: %s \n",
335                 label->uid, label->gid, label->mode, (label->length > 0) ? label->data : "null");
336         }
337     }
338     return 0;
339 }
340 
DumpWorkSpace(const ParamWorkSpace * workSpace,int verbose)341 static void DumpWorkSpace(const ParamWorkSpace *workSpace, int verbose)
342 {
343     PARAM_DUMP("workSpace information \n");
344     PARAM_DUMP("    map file: %s \n", workSpace->paramSpace.fileName);
345     if (workSpace->paramSpace.area != NULL) {
346         PARAM_DUMP("    total size: %d \n", workSpace->paramSpace.area->dataSize);
347         PARAM_DUMP("    first offset: %d \n", workSpace->paramSpace.area->firstNode);
348         PARAM_DUMP("    current offset: %d \n", workSpace->paramSpace.area->currOffset);
349         PARAM_DUMP("    total node: %d \n", workSpace->paramSpace.area->trieNodeCount);
350         PARAM_DUMP("    total param node: %d \n", workSpace->paramSpace.area->paramNodeCount);
351         PARAM_DUMP("    total security node: %d\n", workSpace->paramSpace.area->securityNodeCount);
352     }
353     PARAM_DUMP("    node info: \n");
354     TraversalTrieNode(&workSpace->paramSpace, NULL, DumpTrieDataNodeTraversal, (void *)&verbose);
355 }
356 
DumpParameters(const ParamWorkSpace * workSpace,int verbose)357 void DumpParameters(const ParamWorkSpace *workSpace, int verbose)
358 {
359     PARAM_CHECK(workSpace != NULL && workSpace->securityLabel != NULL, return, "Invalid param");
360     PARAM_DUMP("Dump all paramters begin ...\n");
361     DumpWorkSpace(workSpace, verbose);
362     if (verbose) {
363         PARAM_DUMP("Local sercurity information\n");
364         PARAM_DUMP("\t pid: %d uid: %d gid: %d \n",
365             workSpace->securityLabel->cred.pid,
366             workSpace->securityLabel->cred.uid,
367             workSpace->securityLabel->cred.gid);
368     }
369     PARAM_DUMP("Dump all paramters finish\n");
370 }
371