param_manager.c 15.0 KB
Newer Older
Z
zhong_ning 已提交
1
/*
S
sun_fan 已提交
2
 * Copyright (c) 2021 Huawei Device Co., Ltd.
Z
zhong_ning 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "param_manager.h"
X
xionglei6 已提交
17 18 19

#include <ctype.h>
#include <dlfcn.h>
X
xlei1030 已提交
20 21 22
#ifdef WITH_SELINUX
#include "selinux_parameter.h"
#endif
23

S
sun_fan 已提交
24 25 26
#if !defined PARAM_SUPPORT_SELINUX && !defined PARAM_SUPPORT_DAC
static ParamSecurityLabel g_defaultSecurityLabel;
#endif
Z
zhong_ning 已提交
27

S
sun_fan 已提交
28
static int GetParamSecurityOps(ParamWorkSpace *workSpace, int isInit)
Z
zhong_ning 已提交
29
{
S
sun_fan 已提交
30 31
    UNUSED(isInit);
#if (defined PARAM_SUPPORT_SELINUX || defined PARAM_SUPPORT_DAC)
4
411148299@qq.com 已提交
32
    int ret = RegisterSecurityOps(&workSpace->paramSecurityOps, isInit);
S
sun_fan 已提交
33 34 35 36 37 38
    PARAM_CHECK(workSpace->paramSecurityOps.securityInitLabel != NULL, return -1, "Invalid securityInitLabel");
    ret = workSpace->paramSecurityOps.securityInitLabel(&workSpace->securityLabel, isInit);
    PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init security");
#else
    workSpace->securityLabel = &g_defaultSecurityLabel;
    workSpace->securityLabel->flags |= LABEL_ALL_PERMISSION;
Z
zhong_ning 已提交
39
#endif
4
411148299@qq.com 已提交
40
    return 0;
S
sun_fan 已提交
41
}
Z
zhong_ning 已提交
42

S
sun_fan 已提交
43
int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead)
Z
zhong_ning 已提交
44
{
S
sun_fan 已提交
45 46
    PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param");
    if (PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
Z
zhong_ning 已提交
47 48
        return 0;
    }
S
sun_fan 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    int isInit = 0;
    int op = DAC_READ;
    if (onlyRead == 0) {
        isInit = LABEL_INIT_FOR_INIT;
        op = DAC_WRITE;
    }
    int ret = GetParamSecurityOps(workSpace, isInit);
    PARAM_CHECK(ret == 0, return -1, "Failed to get security operations");
    ParamSecurityOps *paramSecurityOps = &workSpace->paramSecurityOps;
    if (!LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
        PARAM_CHECK(paramSecurityOps->securityFreeLabel != NULL, return -1, "Invalid securityFreeLabel");
        PARAM_CHECK(paramSecurityOps->securityCheckFilePermission != NULL, return -1, "Invalid securityCheck");
        PARAM_CHECK(paramSecurityOps->securityCheckParamPermission != NULL, return -1, "Invalid securityCheck");
        if (isInit == LABEL_INIT_FOR_INIT) {
            PARAM_CHECK(paramSecurityOps->securityGetLabel != NULL, return -1, "Invalid securityGetLabel");
            PARAM_CHECK(paramSecurityOps->securityDecodeLabel != NULL, return -1, "Invalid securityDecodeLabel");
        } else {
            PARAM_CHECK(paramSecurityOps->securityEncodeLabel != NULL, return -1, "Invalid securityEncodeLabel");
        }
        ret = paramSecurityOps->securityCheckFilePermission(workSpace->securityLabel, PARAM_STORAGE_PATH, op);
        PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "No permission to read file %s", PARAM_STORAGE_PATH);
Z
zhong_ning 已提交
70
    }
71 72 73 74 75
    if (onlyRead) {
        ret = InitWorkSpace(CLIENT_PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead);
    } else {
        ret = InitWorkSpace(PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead);
    }
S
sun_fan 已提交
76 77
    PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init workspace");
    PARAM_SET_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT);
Z
zhong_ning 已提交
78 79 80 81 82
    return ret;
}

void CloseParamWorkSpace(ParamWorkSpace *workSpace)
{
X
xionglei6 已提交
83
    PARAM_CHECK(workSpace != NULL, return, "Invalid workSpace");
Z
zhong_ning 已提交
84
    CloseWorkSpace(&workSpace->paramSpace);
S
sun_fan 已提交
85 86 87 88
    if (workSpace->paramSecurityOps.securityFreeLabel != NULL) {
        workSpace->paramSecurityOps.securityFreeLabel(workSpace->securityLabel);
    }
    workSpace->flags = 0;
Z
zhong_ning 已提交
89 90
}

S
sun_fan 已提交
91
static uint32_t ReadCommitId(ParamNode *entry)
Z
zhong_ning 已提交
92
{
S
sun_fan 已提交
93 94 95 96
    uint32_t commitId = atomic_load_explicit(&entry->commitId, memory_order_acquire);
    while (commitId & PARAM_FLAGS_MODIFY) {
        futex_wait(&entry->commitId, commitId);
        commitId = atomic_load_explicit(&entry->commitId, memory_order_acquire);
Z
zhong_ning 已提交
97
    }
S
sun_fan 已提交
98
    return commitId & PARAM_FLAGS_COMMITID;
Z
zhong_ning 已提交
99 100
}

4
411148299@qq.com 已提交
101
int ReadParamCommitId(const ParamWorkSpace *workSpace, ParamHandle handle, uint32_t *commitId)
Z
zhong_ning 已提交
102
{
S
sun_fan 已提交
103 104
    PARAM_CHECK(workSpace != NULL && commitId != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
    ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
Z
zhong_ning 已提交
105
    if (entry == NULL) {
S
sun_fan 已提交
106
        return -1;
Z
zhong_ning 已提交
107
    }
S
sun_fan 已提交
108
    *commitId = ReadCommitId(entry);
Z
zhong_ning 已提交
109 110 111
    return 0;
}

4
411148299@qq.com 已提交
112
int ReadParamWithCheck(const ParamWorkSpace *workSpace, const char *name, uint32_t op, ParamHandle *handle)
Z
zhong_ning 已提交
113
{
S
sun_fan 已提交
114 115
    PARAM_CHECK(handle != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param handle");
    PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param name");
4
411148299@qq.com 已提交
116
    *handle = -1;
S
sun_fan 已提交
117 118
    int ret = CheckParamPermission(workSpace, workSpace->securityLabel, name, op);
    PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
Z
zhong_ning 已提交
119

S
sun_fan 已提交
120
    ParamTrieNode *node = FindTrieNode(&workSpace->paramSpace, name, strlen(name), NULL);
Z
zhong_ning 已提交
121 122 123
    if (node != NULL && node->dataIndex != 0) {
        *handle = node->dataIndex;
        return 0;
X
xionglei6 已提交
124 125
    } else if (node != NULL) {
        return PARAM_CODE_NODE_EXIST;
Z
zhong_ning 已提交
126
    }
S
sun_fan 已提交
127
    return PARAM_CODE_NOT_FOUND;
Z
zhong_ning 已提交
128 129
}

4
411148299@qq.com 已提交
130
int ReadParamValue(const ParamWorkSpace *workSpace, ParamHandle handle, char *value, uint32_t *length)
Z
zhong_ning 已提交
131
{
S
sun_fan 已提交
132 133
    PARAM_CHECK(workSpace != NULL && length != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
    ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
Z
zhong_ning 已提交
134 135 136 137
    if (entry == NULL) {
        return -1;
    }
    if (value == NULL) {
S
sun_fan 已提交
138
        *length = entry->valueLength + 1;
Z
zhong_ning 已提交
139 140
        return 0;
    }
S
sun_fan 已提交
141 142 143 144 145 146 147 148 149
    PARAM_CHECK(*length > entry->valueLength, return PARAM_CODE_INVALID_PARAM,
        "Invalid value len %u %u", *length, entry->valueLength);
    uint32_t commitId = ReadCommitId(entry);
    do {
        int ret = memcpy_s(value, *length, entry->data + entry->keyLength + 1, entry->valueLength);
        PARAM_CHECK(ret == EOK, return -1, "Failed to copy value");
        value[entry->valueLength] = '\0';
        *length = entry->valueLength;
    } while (commitId != ReadCommitId(entry));
Z
zhong_ning 已提交
150 151 152
    return 0;
}

4
411148299@qq.com 已提交
153
int ReadParamName(const ParamWorkSpace *workSpace, ParamHandle handle, char *name, uint32_t length)
Z
zhong_ning 已提交
154 155
{
    PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
156
    ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
Z
zhong_ning 已提交
157 158 159
    if (entry == NULL) {
        return -1;
    }
S
sun_fan 已提交
160 161 162 163 164
    PARAM_CHECK(length > entry->keyLength, return -1, "Invalid param size %u %u", entry->keyLength, length);
    int ret = memcpy_s(name, length, entry->data, entry->keyLength);
    PARAM_CHECK(ret == EOK, return PARAM_CODE_INVALID_PARAM, "Failed to copy name");
    name[entry->keyLength] = '\0';
    return 0;
Z
zhong_ning 已提交
165 166 167 168
}

int CheckParamName(const char *name, int info)
{
4
411148299@qq.com 已提交
169
    PARAM_CHECK(name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
Z
zhong_ning 已提交
170
    size_t nameLen = strlen(name);
S
sun_fan 已提交
171
    if (nameLen >= PARAM_NAME_LEN_MAX) {
Z
zhong_ning 已提交
172 173
        return PARAM_CODE_INVALID_NAME;
    }
S
sun_fan 已提交
174 175 176
    if (strcmp(name, "#") == 0) {
        return 0;
    }
Z
zhong_ning 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202

    if (nameLen < 1 || name[0] == '.' || (!info && name[nameLen - 1] == '.')) {
        PARAM_LOGE("CheckParamName %s %d", name, info);
        return PARAM_CODE_INVALID_NAME;
    }

    /* Only allow alphanumeric, plus '.', '-', '@', ':', or '_' */
    /* Don't allow ".." to appear in a param name */
    for (size_t i = 0; i < nameLen; i++) {
        if (name[i] == '.') {
            if (name[i - 1] == '.') {
                return PARAM_CODE_INVALID_NAME;
            }
            continue;
        }
        if (name[i] == '_' || name[i] == '-' || name[i] == '@' || name[i] == ':') {
            continue;
        }
        if (isalnum(name[i])) {
            continue;
        }
        return PARAM_CODE_INVALID_NAME;
    }
    return 0;
}

4
411148299@qq.com 已提交
203
static int ProcessParamTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, void *cookie)
Z
zhong_ning 已提交
204
{
S
sun_fan 已提交
205 206 207 208 209
    UNUSED(workSpace);
    ParamTraversalContext *context = (ParamTraversalContext *)cookie;
    ParamTrieNode *current = (ParamTrieNode *)node;
    if (current == NULL) {
        return 0;
Z
zhong_ning 已提交
210
    }
S
sun_fan 已提交
211 212 213
    if (current->dataIndex == 0) {
        return 0;
    }
X
xionglei6 已提交
214 215 216 217 218 219 220 221
    ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
    if (entry == NULL) {
        return 0;
    }
    if ((strcmp("#", context->prefix) != 0) &&
        (strncmp(entry->data, context->prefix, strlen(context->prefix)) != 0)) {
        return 0;
    }
S
sun_fan 已提交
222
    context->traversalParamPtr(current->dataIndex, context->context);
Z
zhong_ning 已提交
223 224 225
    return 0;
}

X
xionglei6 已提交
226 227
int TraversalParam(const ParamWorkSpace *workSpace,
    const char *prefix, TraversalParamPtr walkFunc, void *cookie)
Z
zhong_ning 已提交
228
{
4
411148299@qq.com 已提交
229
    PARAM_CHECK(workSpace != NULL && walkFunc != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
230
    ParamTraversalContext context = {
X
xionglei6 已提交
231
        walkFunc, cookie, prefix
S
sun_fan 已提交
232
    };
X
xionglei6 已提交
233 234 235
    ParamTrieNode *root = FindTrieNode(&workSpace->paramSpace, prefix, strlen(prefix), NULL);
    PARAM_LOGV("TraversalParam prefix %s", prefix);
    return TraversalTrieNode(&workSpace->paramSpace, root, ProcessParamTraversal, &context);
Z
zhong_ning 已提交
236 237
}

X
xionglei6 已提交
238
#ifdef WITH_SELINUX
X
xionglei6 已提交
239 240
static void *g_selinuxHandle = NULL;
static int CheckParamPermissionWithSelinux(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
X
xionglei6 已提交
241 242 243
{
    static void (*setSelinuxLogCallback)();
    static int (*setParamCheck)(const char *paraName, struct ucred *uc);
X
xlei1030 已提交
244
    g_selinuxHandle = dlopen("/system/lib/libparaperm_checker.z.so", RTLD_LAZY);
X
xionglei6 已提交
245
    if (g_selinuxHandle == NULL) {
X
xlei1030 已提交
246
        PARAM_LOGE("Failed to dlopen libparaperm_checker.z.so, %s\n", dlerror());
X
xionglei6 已提交
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
        return DAC_RESULT_FORBIDED;
    }
    if (setSelinuxLogCallback == NULL) {
        setSelinuxLogCallback = (void (*)())dlsym(g_selinuxHandle, "SetSelinuxLogCallback");
        if (setSelinuxLogCallback == NULL) {
            PARAM_LOGE("Failed to dlsym setSelinuxLogCallback, %s\n", dlerror());
            return DAC_RESULT_FORBIDED;
        }
    }
    (*setSelinuxLogCallback)();

    if (setParamCheck == NULL) {
        setParamCheck = (int (*)(const char *paraName, struct ucred *uc))dlsym(g_selinuxHandle, "SetParamCheck");
        if (setParamCheck == NULL) {
            PARAM_LOGE("Failed to dlsym setParamCheck, %s\n", dlerror());
            return DAC_RESULT_FORBIDED;
        }
    }
    struct ucred uc;
    uc.pid = srcLabel->cred.pid;
    uc.uid = srcLabel->cred.uid;
    uc.gid = srcLabel->cred.gid;
    int ret = setParamCheck(name, &uc);
X
xionglei6 已提交
270 271 272
    if (ret != 0) {
        PARAM_LOGI("Selinux check name %s pid %d uid %d %d result %d", name, uc.pid, uc.uid, uc.gid, ret);
    }
X
xionglei6 已提交
273 274 275 276
    return ret;
}
#endif

4
411148299@qq.com 已提交
277 278
int CheckParamPermission(const ParamWorkSpace *workSpace,
    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
Z
zhong_ning 已提交
279
{
4
411148299@qq.com 已提交
280 281
    PARAM_CHECK(workSpace != NULL && workSpace->securityLabel != NULL,
        return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
282 283
    if (LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
        return 0;
Z
zhong_ning 已提交
284
    }
S
sun_fan 已提交
285
    PARAM_CHECK(name != NULL && srcLabel != NULL, return -1, "Invalid param");
X
xlei1030 已提交
286
#ifdef WITH_SELINUX
X
xionglei6 已提交
287 288 289 290 291
    if (mode == DAC_WRITE) {
        int ret = CheckParamPermissionWithSelinux(srcLabel, name, mode);
        if (ret == DAC_RESULT_PERMISSION) {
            return DAC_RESULT_PERMISSION;
        }
X
xlei1030 已提交
292 293
    }
#endif
S
sun_fan 已提交
294 295 296 297 298 299 300
    if (workSpace->paramSecurityOps.securityCheckParamPermission == NULL) {
        return DAC_RESULT_FORBIDED;
    }
    uint32_t labelIndex = 0;
    FindTrieNode(&workSpace->paramSpace, name, strlen(name), &labelIndex);
    ParamSecruityNode *node = (ParamSecruityNode *)GetTrieNode(&workSpace->paramSpace, labelIndex);
    PARAM_CHECK(node != NULL, return DAC_RESULT_FORBIDED, "Can not get security label %d", labelIndex);
Z
zhong_ning 已提交
301

S
sun_fan 已提交
302
    ParamAuditData auditData = {};
Z
zhong_ning 已提交
303
    auditData.name = name;
S
sun_fan 已提交
304 305 306 307 308
    auditData.dacData.uid = node->uid;
    auditData.dacData.gid = node->gid;
    auditData.dacData.mode = node->mode;
    auditData.label = node->data;
    return workSpace->paramSecurityOps.securityCheckParamPermission(srcLabel, &auditData, mode);
Z
zhong_ning 已提交
309 310
}

4
411148299@qq.com 已提交
311
static int DumpTrieDataNodeTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, void *cookie)
Z
zhong_ning 已提交
312
{
S
sun_fan 已提交
313 314 315 316
    int verbose = *(int *)cookie;
    ParamTrieNode *current = (ParamTrieNode *)node;
    if (current == NULL) {
        return 0;
Z
zhong_ning 已提交
317
    }
S
sun_fan 已提交
318
    if (verbose) {
X
xionglei6 已提交
319
        PARAM_DUMP("\tTrie node info [%u,%u,%u] data: %u label: %u key length:%d \n\t  key: %s \n",
S
sun_fan 已提交
320 321
            current->left, current->right, current->child,
            current->dataIndex, current->labelIndex, current->length, current->key);
Z
zhong_ning 已提交
322
    }
S
sun_fan 已提交
323 324 325
    if (current->dataIndex != 0) {
        ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
        if (entry != NULL) {
X
xionglei6 已提交
326
            PARAM_DUMP("\tparameter length info [%d, %d] \n\t  param: %s \n",
S
sun_fan 已提交
327
                entry->keyLength, entry->valueLength, (entry != NULL) ? entry->data : "null");
Z
zhong_ning 已提交
328 329
        }
    }
4
411148299@qq.com 已提交
330
    if (current->labelIndex != 0 && verbose) {
S
sun_fan 已提交
331 332
        ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(workSpace, current->labelIndex);
        if (label != NULL) {
X
xionglei6 已提交
333
            PARAM_DUMP("\tparameter label dac %d %d %o \n\t  label: %s \n",
S
sun_fan 已提交
334 335
                label->uid, label->gid, label->mode, (label->length > 0) ? label->data : "null");
        }
Z
zhong_ning 已提交
336
    }
S
sun_fan 已提交
337
    return 0;
Z
zhong_ning 已提交
338 339
}

4
411148299@qq.com 已提交
340
static void DumpWorkSpace(const ParamWorkSpace *workSpace, int verbose)
Z
zhong_ning 已提交
341
{
X
xionglei6 已提交
342 343
    PARAM_DUMP("workSpace information \n");
    PARAM_DUMP("    map file: %s \n", workSpace->paramSpace.fileName);
344
    if (workSpace->paramSpace.area != NULL) {
X
xionglei6 已提交
345 346 347 348 349 350
        PARAM_DUMP("    total size: %d \n", workSpace->paramSpace.area->dataSize);
        PARAM_DUMP("    first offset: %d \n", workSpace->paramSpace.area->firstNode);
        PARAM_DUMP("    current offset: %d \n", workSpace->paramSpace.area->currOffset);
        PARAM_DUMP("    total node: %d \n", workSpace->paramSpace.area->trieNodeCount);
        PARAM_DUMP("    total param node: %d \n", workSpace->paramSpace.area->paramNodeCount);
        PARAM_DUMP("    total security node: %d\n", workSpace->paramSpace.area->securityNodeCount);
351
    }
X
xionglei6 已提交
352
    PARAM_DUMP("    node info: \n");
S
sun_fan 已提交
353
    TraversalTrieNode(&workSpace->paramSpace, NULL, DumpTrieDataNodeTraversal, (void *)&verbose);
Z
zhong_ning 已提交
354 355
}

4
411148299@qq.com 已提交
356
void DumpParameters(const ParamWorkSpace *workSpace, int verbose)
Z
zhong_ning 已提交
357
{
4
411148299@qq.com 已提交
358
    PARAM_CHECK(workSpace != NULL && workSpace->securityLabel != NULL, return, "Invalid param");
X
xionglei6 已提交
359
    PARAM_DUMP("Dump all paramters begin ...\n");
S
sun_fan 已提交
360 361
    DumpWorkSpace(workSpace, verbose);
    if (verbose) {
X
xionglei6 已提交
362 363
        PARAM_DUMP("Local sercurity information\n");
        PARAM_DUMP("\t pid: %d uid: %d gid: %d \n",
S
sun_fan 已提交
364 365 366 367
            workSpace->securityLabel->cred.pid,
            workSpace->securityLabel->cred.uid,
            workSpace->securityLabel->cred.gid);
    }
X
xionglei6 已提交
368
    PARAM_DUMP("Dump all paramters finish\n");
Z
zhong_ning 已提交
369
}