param_manager.c 13.1 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"
17

Z
zhong_ning 已提交
18 19
#include <ctype.h>

S
sun_fan 已提交
20 21 22
#if !defined PARAM_SUPPORT_SELINUX && !defined PARAM_SUPPORT_DAC
static ParamSecurityLabel g_defaultSecurityLabel;
#endif
Z
zhong_ning 已提交
23

S
sun_fan 已提交
24
static int GetParamSecurityOps(ParamWorkSpace *workSpace, int isInit)
Z
zhong_ning 已提交
25
{
S
sun_fan 已提交
26 27
    UNUSED(isInit);
#if (defined PARAM_SUPPORT_SELINUX || defined PARAM_SUPPORT_DAC)
4
411148299@qq.com 已提交
28
    int ret = RegisterSecurityOps(&workSpace->paramSecurityOps, isInit);
S
sun_fan 已提交
29 30 31 32 33 34
    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 已提交
35
#endif
4
411148299@qq.com 已提交
36
    return 0;
S
sun_fan 已提交
37
}
Z
zhong_ning 已提交
38

S
sun_fan 已提交
39
int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead)
Z
zhong_ning 已提交
40
{
S
sun_fan 已提交
41 42
    PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param");
    if (PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
Z
zhong_ning 已提交
43 44
        return 0;
    }
S
sun_fan 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
    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 已提交
66
    }
67 68 69 70 71
    if (onlyRead) {
        ret = InitWorkSpace(CLIENT_PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead);
    } else {
        ret = InitWorkSpace(PARAM_STORAGE_PATH, &workSpace->paramSpace, onlyRead);
    }
S
sun_fan 已提交
72 73
    PARAM_CHECK(ret == 0, return PARAM_CODE_INVALID_NAME, "Failed to init workspace");
    PARAM_SET_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT);
Z
zhong_ning 已提交
74 75 76 77 78
    return ret;
}

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

S
sun_fan 已提交
87
static uint32_t ReadCommitId(ParamNode *entry)
Z
zhong_ning 已提交
88
{
S
sun_fan 已提交
89 90 91 92
    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 已提交
93
    }
S
sun_fan 已提交
94
    return commitId & PARAM_FLAGS_COMMITID;
Z
zhong_ning 已提交
95 96
}

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

4
411148299@qq.com 已提交
108
int ReadParamWithCheck(const ParamWorkSpace *workSpace, const char *name, uint32_t op, ParamHandle *handle)
Z
zhong_ning 已提交
109
{
S
sun_fan 已提交
110 111
    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 已提交
112
    *handle = -1;
S
sun_fan 已提交
113 114
    int ret = CheckParamPermission(workSpace, workSpace->securityLabel, name, op);
    PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
Z
zhong_ning 已提交
115

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

4
411148299@qq.com 已提交
126
int ReadParamValue(const ParamWorkSpace *workSpace, ParamHandle handle, char *value, uint32_t *length)
Z
zhong_ning 已提交
127
{
S
sun_fan 已提交
128 129
    PARAM_CHECK(workSpace != NULL && length != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
    ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
Z
zhong_ning 已提交
130 131 132 133
    if (entry == NULL) {
        return -1;
    }
    if (value == NULL) {
S
sun_fan 已提交
134
        *length = entry->valueLength + 1;
Z
zhong_ning 已提交
135 136
        return 0;
    }
S
sun_fan 已提交
137 138 139 140 141 142 143 144 145
    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 已提交
146 147 148
    return 0;
}

4
411148299@qq.com 已提交
149
int ReadParamName(const ParamWorkSpace *workSpace, ParamHandle handle, char *name, uint32_t length)
Z
zhong_ning 已提交
150 151
{
    PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
152
    ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
Z
zhong_ning 已提交
153 154 155
    if (entry == NULL) {
        return -1;
    }
S
sun_fan 已提交
156 157 158 159 160
    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 已提交
161 162 163 164
}

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

    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 已提交
199
static int ProcessParamTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, void *cookie)
Z
zhong_ning 已提交
200
{
S
sun_fan 已提交
201 202 203 204 205
    UNUSED(workSpace);
    ParamTraversalContext *context = (ParamTraversalContext *)cookie;
    ParamTrieNode *current = (ParamTrieNode *)node;
    if (current == NULL) {
        return 0;
Z
zhong_ning 已提交
206
    }
S
sun_fan 已提交
207 208 209
    if (current->dataIndex == 0) {
        return 0;
    }
X
xionglei6 已提交
210 211 212 213 214 215 216 217
    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 已提交
218
    context->traversalParamPtr(current->dataIndex, context->context);
Z
zhong_ning 已提交
219 220 221
    return 0;
}

X
xionglei6 已提交
222 223
int TraversalParam(const ParamWorkSpace *workSpace,
    const char *prefix, TraversalParamPtr walkFunc, void *cookie)
Z
zhong_ning 已提交
224
{
4
411148299@qq.com 已提交
225
    PARAM_CHECK(workSpace != NULL && walkFunc != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
226
    ParamTraversalContext context = {
X
xionglei6 已提交
227
        walkFunc, cookie, prefix
S
sun_fan 已提交
228
    };
X
xionglei6 已提交
229 230 231
    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 已提交
232 233
}

4
411148299@qq.com 已提交
234 235
int CheckParamPermission(const ParamWorkSpace *workSpace,
    const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
Z
zhong_ning 已提交
236
{
4
411148299@qq.com 已提交
237 238
    PARAM_CHECK(workSpace != NULL && workSpace->securityLabel != NULL,
        return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
239 240
    if (LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
        return 0;
Z
zhong_ning 已提交
241
    }
S
sun_fan 已提交
242 243 244 245 246 247 248 249
    PARAM_CHECK(name != NULL && srcLabel != NULL, return -1, "Invalid param");
    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 已提交
250

S
sun_fan 已提交
251
    ParamAuditData auditData = {};
Z
zhong_ning 已提交
252
    auditData.name = name;
S
sun_fan 已提交
253 254 255 256 257
    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 已提交
258 259
}

4
411148299@qq.com 已提交
260
static int DumpTrieDataNodeTraversal(const WorkSpace *workSpace, const ParamTrieNode *node, void *cookie)
Z
zhong_ning 已提交
261
{
S
sun_fan 已提交
262 263 264 265
    int verbose = *(int *)cookie;
    ParamTrieNode *current = (ParamTrieNode *)node;
    if (current == NULL) {
        return 0;
Z
zhong_ning 已提交
266
    }
S
sun_fan 已提交
267
    if (verbose) {
X
xionglei6 已提交
268
        PARAM_DUMP("\tTrie node info [%u,%u,%u] data: %u label: %u key length:%d \n\t  key: %s \n",
S
sun_fan 已提交
269 270
            current->left, current->right, current->child,
            current->dataIndex, current->labelIndex, current->length, current->key);
Z
zhong_ning 已提交
271
    }
S
sun_fan 已提交
272 273 274
    if (current->dataIndex != 0) {
        ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
        if (entry != NULL) {
X
xionglei6 已提交
275
            PARAM_DUMP("\tparameter length info [%d, %d] \n\t  param: %s \n",
S
sun_fan 已提交
276
                entry->keyLength, entry->valueLength, (entry != NULL) ? entry->data : "null");
Z
zhong_ning 已提交
277 278
        }
    }
4
411148299@qq.com 已提交
279
    if (current->labelIndex != 0 && verbose) {
S
sun_fan 已提交
280 281
        ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(workSpace, current->labelIndex);
        if (label != NULL) {
X
xionglei6 已提交
282
            PARAM_DUMP("\tparameter label dac %d %d %o \n\t  label: %s \n",
S
sun_fan 已提交
283 284
                label->uid, label->gid, label->mode, (label->length > 0) ? label->data : "null");
        }
Z
zhong_ning 已提交
285
    }
S
sun_fan 已提交
286
    return 0;
Z
zhong_ning 已提交
287 288
}

4
411148299@qq.com 已提交
289
static void DumpWorkSpace(const ParamWorkSpace *workSpace, int verbose)
Z
zhong_ning 已提交
290
{
X
xionglei6 已提交
291 292
    PARAM_DUMP("workSpace information \n");
    PARAM_DUMP("    map file: %s \n", workSpace->paramSpace.fileName);
293
    if (workSpace->paramSpace.area != NULL) {
X
xionglei6 已提交
294 295 296 297 298 299
        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);
300
    }
X
xionglei6 已提交
301
    PARAM_DUMP("    node info: \n");
S
sun_fan 已提交
302
    TraversalTrieNode(&workSpace->paramSpace, NULL, DumpTrieDataNodeTraversal, (void *)&verbose);
Z
zhong_ning 已提交
303 304
}

4
411148299@qq.com 已提交
305
void DumpParameters(const ParamWorkSpace *workSpace, int verbose)
Z
zhong_ning 已提交
306
{
4
411148299@qq.com 已提交
307
    PARAM_CHECK(workSpace != NULL && workSpace->securityLabel != NULL, return, "Invalid param");
X
xionglei6 已提交
308
    PARAM_DUMP("Dump all paramters begin ...\n");
S
sun_fan 已提交
309 310
    DumpWorkSpace(workSpace, verbose);
    if (verbose) {
X
xionglei6 已提交
311 312
        PARAM_DUMP("Local sercurity information\n");
        PARAM_DUMP("\t pid: %d uid: %d gid: %d \n",
S
sun_fan 已提交
313 314 315 316
            workSpace->securityLabel->cred.pid,
            workSpace->securityLabel->cred.uid,
            workSpace->securityLabel->cred.gid);
    }
X
xionglei6 已提交
317
    PARAM_DUMP("Dump all paramters finish\n");
Z
zhong_ning 已提交
318
}