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 239 240 241 242 243 244 245 246
#ifdef WITH_SELINUX
void *g_selinuxHandle = NULL;
int CheckParamPermissionWithSelinux(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
{
    if (srcLabel == NULL || mode != DAC_WRITE) {
        return DAC_RESULT_PERMISSION;
    }
    static void (*setSelinuxLogCallback)();
    static int (*setParamCheck)(const char *paraName, struct ucred *uc);
X
xionglei6 已提交
247
    g_selinuxHandle = dlopen("/system/lib/libparaperm_checker.so", RTLD_LAZY);
X
xionglei6 已提交
248
    if (g_selinuxHandle == NULL) {
X
xionglei6 已提交
249
        PARAM_LOGE("Failed to dlopen libparaperm_checker.so, %s\n", dlerror());
X
xionglei6 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
        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);
    PARAM_LOGI("Selinux check name %s pid %d uid %d %d result %d", name, uc.pid, uc.uid, uc.gid, ret);
    return ret;
}
#endif

4
411148299@qq.com 已提交
278 279
int CheckParamPermission(const ParamWorkSpace *workSpace,
    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
Z
zhong_ning 已提交
280
{
4
411148299@qq.com 已提交
281 282
    PARAM_CHECK(workSpace != NULL && workSpace->securityLabel != NULL,
        return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
283 284
    if (LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
        return 0;
Z
zhong_ning 已提交
285
    }
S
sun_fan 已提交
286
    PARAM_CHECK(name != NULL && srcLabel != NULL, return -1, "Invalid param");
X
xlei1030 已提交
287
#ifdef WITH_SELINUX
X
xionglei6 已提交
288 289 290
    int ret = CheckParamPermissionWithSelinux(srcLabel, name, mode);
    if (ret == DAC_RESULT_PERMISSION) {
        return DAC_RESULT_PERMISSION;
X
xlei1030 已提交
291 292
    }
#endif
S
sun_fan 已提交
293 294 295 296 297 298 299
    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 已提交
300

S
sun_fan 已提交
301
    ParamAuditData auditData = {};
Z
zhong_ning 已提交
302
    auditData.name = name;
S
sun_fan 已提交
303 304 305 306 307
    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 已提交
308 309
}

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

4
411148299@qq.com 已提交
339
static void DumpWorkSpace(const ParamWorkSpace *workSpace, int verbose)
Z
zhong_ning 已提交
340
{
X
xionglei6 已提交
341 342
    PARAM_DUMP("workSpace information \n");
    PARAM_DUMP("    map file: %s \n", workSpace->paramSpace.fileName);
343
    if (workSpace->paramSpace.area != NULL) {
X
xionglei6 已提交
344 345 346 347 348 349
        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);
350
    }
X
xionglei6 已提交
351
    PARAM_DUMP("    node info: \n");
S
sun_fan 已提交
352
    TraversalTrieNode(&workSpace->paramSpace, NULL, DumpTrieDataNodeTraversal, (void *)&verbose);
Z
zhong_ning 已提交
353 354
}

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