Files
sun_fan 017f716d4b init : fix param .
Signed-off-by: sun_fan <sun_fan1@hoperun.com>
2021-09-13 19:58:03 +08:00

296 lines
12 KiB
C

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* 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>
#include <dlfcn.h>
#define LABEL "Manager"
#if !defined PARAM_SUPPORT_SELINUX && !defined PARAM_SUPPORT_DAC
static ParamSecurityLabel g_defaultSecurityLabel;
#endif
static int GetParamSecurityOps(ParamWorkSpace *workSpace, int isInit)
{
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;
#endif
return ret;
}
int InitParamWorkSpace(ParamWorkSpace *workSpace, int onlyRead)
{
PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid param");
if (PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
return 0;
}
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);
}
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);
return ret;
}
void CloseParamWorkSpace(ParamWorkSpace *workSpace)
{
CloseWorkSpace(&workSpace->paramSpace);
if (workSpace->paramSecurityOps.securityFreeLabel != NULL) {
workSpace->paramSecurityOps.securityFreeLabel(workSpace->securityLabel);
}
workSpace->flags = 0;
}
static uint32_t ReadCommitId(ParamNode *entry)
{
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);
}
return commitId & PARAM_FLAGS_COMMITID;
}
int ReadParamCommitId(ParamWorkSpace *workSpace, ParamHandle handle, uint32_t *commitId)
{
PARAM_CHECK(workSpace != NULL && commitId != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
if (entry == NULL) {
return -1;
}
*commitId = ReadCommitId(entry);
return 0;
}
int ReadParamWithCheck(ParamWorkSpace *workSpace, const char *name, int op, ParamHandle *handle)
{
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");
*handle = 0;
int ret = CheckParamPermission(workSpace, workSpace->securityLabel, name, op);
PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
ParamTrieNode *node = FindTrieNode(&workSpace->paramSpace, name, strlen(name), NULL);
if (node != NULL && node->dataIndex != 0) {
*handle = node->dataIndex;
return 0;
}
return PARAM_CODE_NOT_FOUND;
}
int ReadParamValue(ParamWorkSpace *workSpace, ParamHandle handle, char *value, uint32_t *length)
{
PARAM_CHECK(workSpace != NULL && length != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
if (entry == NULL) {
return -1;
}
if (value == NULL) {
*length = entry->valueLength + 1;
return 0;
}
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));
return 0;
}
int ReadParamName(ParamWorkSpace *workSpace, ParamHandle handle, char *name, uint32_t length)
{
PARAM_CHECK(workSpace != NULL && name != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
ParamNode *entry = (ParamNode *)GetTrieNode(&workSpace->paramSpace, handle);
if (entry == NULL) {
return -1;
}
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;
}
int CheckParamName(const char *name, int info)
{
size_t nameLen = strlen(name);
if (nameLen >= PARAM_NAME_LEN_MAX) {
return PARAM_CODE_INVALID_NAME;
}
if (strcmp(name, "#") == 0) {
return 0;
}
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;
}
static int ProcessParamTraversal(WorkSpace *workSpace, ParamTrieNode *node, void *cookie)
{
UNUSED(workSpace);
ParamTraversalContext *context = (ParamTraversalContext *)cookie;
ParamTrieNode *current = (ParamTrieNode *)node;
if (current == NULL) {
return 0;
}
if (current->dataIndex == 0) {
return 0;
}
context->traversalParamPtr(current->dataIndex, context->context);
return 0;
}
int TraversalParam(ParamWorkSpace *workSpace, TraversalParamPtr walkFunc, void *cookie)
{
ParamTraversalContext context = {
walkFunc, cookie
};
return TraversalTrieNode(&workSpace->paramSpace, NULL, ProcessParamTraversal, &context);
}
int CheckParamPermission(ParamWorkSpace *workSpace,
const ParamSecurityLabel *srcLabel, const char *name, int mode)
{
if (LABEL_IS_ALL_PERMITTED(workSpace->securityLabel)) {
return 0;
}
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);
ParamAuditData auditData = {};
auditData.name = name;
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);
}
static int DumpTrieDataNodeTraversal(WorkSpace *workSpace, ParamTrieNode *node, void *cookie)
{
int verbose = *(int *)cookie;
ParamTrieNode *current = (ParamTrieNode *)node;
if (current == NULL) {
return 0;
}
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);
}
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");
}
}
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");
}
}
return 0;
}
static void DumpWorkSpace(ParamWorkSpace *workSpace, int verbose)
{
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);
}
void DumpParameters(ParamWorkSpace *workSpace, int verbose)
{
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");
}