param_manager.c 11.8 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 17
 * 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"
#include <ctype.h>
S
sun_fan 已提交
18
#include <dlfcn.h>
Z
zhong_ning 已提交
19 20

#define LABEL "Manager"
S
sun_fan 已提交
21 22 23
#if !defined PARAM_SUPPORT_SELINUX && !defined PARAM_SUPPORT_DAC
static ParamSecurityLabel g_defaultSecurityLabel;
#endif
Z
zhong_ning 已提交
24

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

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

void CloseParamWorkSpace(ParamWorkSpace *workSpace)
{
    CloseWorkSpace(&workSpace->paramSpace);
S
sun_fan 已提交
78 79 80 81
    if (workSpace->paramSecurityOps.securityFreeLabel != NULL) {
        workSpace->paramSecurityOps.securityFreeLabel(workSpace->securityLabel);
    }
    workSpace->flags = 0;
Z
zhong_ning 已提交
82 83
}

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

S
sun_fan 已提交
94
int ReadParamCommitId(ParamWorkSpace *workSpace, ParamHandle handle, uint32_t *commitId)
Z
zhong_ning 已提交
95
{
S
sun_fan 已提交
96 97
    PARAM_CHECK(workSpace != NULL && commitId != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
    ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
Z
zhong_ning 已提交
98
    if (entry == NULL) {
S
sun_fan 已提交
99
        return -1;
Z
zhong_ning 已提交
100
    }
S
sun_fan 已提交
101
    *commitId = ReadCommitId(entry);
Z
zhong_ning 已提交
102 103 104
    return 0;
}

S
sun_fan 已提交
105
int ReadParamWithCheck(ParamWorkSpace *workSpace, const char *name, int op, ParamHandle *handle)
Z
zhong_ning 已提交
106
{
S
sun_fan 已提交
107 108
    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");
Z
zhong_ning 已提交
109
    *handle = 0;
S
sun_fan 已提交
110 111
    int ret = CheckParamPermission(workSpace, workSpace->securityLabel, name, op);
    PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
Z
zhong_ning 已提交
112

S
sun_fan 已提交
113
    ParamTrieNode *node = FindTrieNode(&workSpace->paramSpace, name, strlen(name), NULL);
Z
zhong_ning 已提交
114 115 116 117
    if (node != NULL && node->dataIndex != 0) {
        *handle = node->dataIndex;
        return 0;
    }
S
sun_fan 已提交
118
    return PARAM_CODE_NOT_FOUND;
Z
zhong_ning 已提交
119 120
}

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

S
sun_fan 已提交
144
int ReadParamName(ParamWorkSpace *workSpace, ParamHandle handle, char *name, uint32_t length)
Z
zhong_ning 已提交
145 146
{
    PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
S
sun_fan 已提交
147
    ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
Z
zhong_ning 已提交
148 149 150
    if (entry == NULL) {
        return -1;
    }
S
sun_fan 已提交
151 152 153 154 155
    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 已提交
156 157 158 159 160
}

int CheckParamName(const char *name, int info)
{
    size_t nameLen = strlen(name);
S
sun_fan 已提交
161
    if (nameLen >= PARAM_NAME_LEN_MAX) {
Z
zhong_ning 已提交
162 163
        return PARAM_CODE_INVALID_NAME;
    }
S
sun_fan 已提交
164 165 166
    if (strcmp(name, "#") == 0) {
        return 0;
    }
Z
zhong_ning 已提交
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

    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;
}

S
sun_fan 已提交
193
static int ProcessParamTraversal(WorkSpace *workSpace, ParamTrieNode *node, void *cookie)
Z
zhong_ning 已提交
194
{
S
sun_fan 已提交
195 196 197 198 199
    UNUSED(workSpace);
    ParamTraversalContext *context = (ParamTraversalContext *)cookie;
    ParamTrieNode *current = (ParamTrieNode *)node;
    if (current == NULL) {
        return 0;
Z
zhong_ning 已提交
200
    }
S
sun_fan 已提交
201 202 203 204
    if (current->dataIndex == 0) {
        return 0;
    }
    context->traversalParamPtr(current->dataIndex, context->context);
Z
zhong_ning 已提交
205 206 207
    return 0;
}

S
sun_fan 已提交
208
int TraversalParam(ParamWorkSpace *workSpace, TraversalParamPtr walkFunc, void *cookie)
Z
zhong_ning 已提交
209
{
S
sun_fan 已提交
210 211 212 213
    ParamTraversalContext context = {
        walkFunc, cookie
    };
    return TraversalTrieNode(&workSpace->paramSpace, NULL, ProcessParamTraversal, &context);
Z
zhong_ning 已提交
214 215
}

S
sun_fan 已提交
216 217
int CheckParamPermission(ParamWorkSpace *workSpace,
    const ParamSecurityLabel *srcLabel, const char *name, int mode)
Z
zhong_ning 已提交
218
{
S
sun_fan 已提交
219 220
    if (LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
        return 0;
Z
zhong_ning 已提交
221
    }
S
sun_fan 已提交
222 223 224 225 226 227 228 229
    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 已提交
230

S
sun_fan 已提交
231
    ParamAuditData auditData = {};
Z
zhong_ning 已提交
232
    auditData.name = name;
S
sun_fan 已提交
233 234 235 236 237
    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 已提交
238 239
}

S
sun_fan 已提交
240
static int DumpTrieDataNodeTraversal(WorkSpace *workSpace, ParamTrieNode *node, void *cookie)
Z
zhong_ning 已提交
241
{
S
sun_fan 已提交
242 243 244 245
    int verbose = *(int *)cookie;
    ParamTrieNode *current = (ParamTrieNode *)node;
    if (current == NULL) {
        return 0;
Z
zhong_ning 已提交
246
    }
S
sun_fan 已提交
247 248 249 250
    if (verbose) {
        printf("    Trie node info [%5u,%5u,%5u] data [%5u,%5u] length:%-5d %s \n",
            current->left, current->right, current->child,
            current->dataIndex, current->labelIndex, current->length, current->key);
Z
zhong_ning 已提交
251
    }
S
sun_fan 已提交
252 253 254 255 256
    if (current->dataIndex != 0) {
        ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, current->dataIndex);
        if (entry != NULL) {
            printf("\tparameter length [%5d,%5d] %s \n",
                entry->keyLength, entry->valueLength, (entry != NULL) ? entry->data : "null");
Z
zhong_ning 已提交
257 258
        }
    }
S
sun_fan 已提交
259 260 261 262 263 264
    if (current->labelIndex != 0) {
        ParamSecruityNode *label = (ParamSecruityNode *)GetTrieNode(workSpace, current->labelIndex);
        if (label != NULL) {
            printf("\tparameter label dac %d %d %o %s \n",
                label->uid, label->gid, label->mode, (label->length > 0) ? label->data : "null");
        }
Z
zhong_ning 已提交
265
    }
S
sun_fan 已提交
266
    return 0;
Z
zhong_ning 已提交
267 268
}

S
sun_fan 已提交
269
static void DumpWorkSpace(ParamWorkSpace *workSpace, int verbose)
Z
zhong_ning 已提交
270
{
S
sun_fan 已提交
271 272 273 274 275 276 277 278 279 280
    printf("workSpace information \n");
    printf("    map file: %s \n", workSpace->paramSpace.fileName);
    printf("    total size: %d \n", workSpace->paramSpace.area->dataSize);
    printf("    first offset: %d \n", workSpace->paramSpace.area->firstNode);
    printf("    current offset: %d \n", workSpace->paramSpace.area->currOffset);
    printf("    total node: %d \n", workSpace->paramSpace.area->trieNodeCount);
    printf("    total param node: %d \n", workSpace->paramSpace.area->paramNodeCount);
    printf("    total security node: %d\n", workSpace->paramSpace.area->securityNodeCount);
    printf("    node info: \n");
    TraversalTrieNode(&workSpace->paramSpace, NULL, DumpTrieDataNodeTraversal, (void *)&verbose);
Z
zhong_ning 已提交
281 282
}

S
sun_fan 已提交
283
void DumpParameters(ParamWorkSpace *workSpace, int verbose)
Z
zhong_ning 已提交
284
{
S
sun_fan 已提交
285 286 287 288 289 290 291 292 293 294
    printf("Dump all paramters begin ...\n");
    DumpWorkSpace(workSpace, verbose);
    if (verbose) {
        printf("Local sercurity information\n");
        printf("\t pid: %d uid: %d gid: %d \n",
            workSpace->securityLabel->cred.pid,
            workSpace->securityLabel->cred.uid,
            workSpace->securityLabel->cred.gid);
    }
    printf("Dump all paramters finish\n");
Z
zhong_ning 已提交
295
}