diff --git a/BUILD.gn b/BUILD.gn index 25f7d3a695de937ac1af68c1d21e941f54e3cca2..a373e40ca6784413e4c134945d1339be8e67f79b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -135,6 +135,7 @@ ohos_static_library("libselinux_klog_static") { ohos_static_library("libparaperm_checker_static") { output_name = "libparaperm_checker_static" sources = [ + "$SELINUX_ROOT_DIR/interfaces/policycoreutils/src/contexts_trie.cpp", "$SELINUX_ROOT_DIR/interfaces/policycoreutils/src/paraperm_checker.cpp", ] include_dirs = [ @@ -254,6 +255,7 @@ ohos_executable("param_check") { ] cflags = [ "-D_GNU_SOURCE", + "-DTIME_DISPLAY", "-Wall", "-Werror", ] diff --git a/interfaces/policycoreutils/include/contexts_trie.h b/interfaces/policycoreutils/include/contexts_trie.h new file mode 100644 index 0000000000000000000000000000000000000000..793e3c6d32f8822cec220c775f79ffddbbf94e3e --- /dev/null +++ b/interfaces/policycoreutils/include/contexts_trie.h @@ -0,0 +1,38 @@ +/* + * 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. + */ + +#ifndef CONTEXTS_TRIE_H +#define CONTEXTS_TRIE_H + +#include +#include + +class ParamContextsTrie { +public: + ParamContextsTrie() {} + ~ParamContextsTrie() {} + + ParamContextsTrie *FindChild(std::string element); + bool Insert(const std::string ¶mPrefix, const std::string &contexts); + bool Search(const std::string ¶Name, char **context); + void Clear(); + +private: + std::string prefixLabel = ""; + std::string matchLabel = ""; + std::unordered_map childen; +}; + +#endif // CONTEXTS_TRIE_H diff --git a/interfaces/policycoreutils/include/hap_restorecon.h b/interfaces/policycoreutils/include/hap_restorecon.h index 482b5bee6334ebef8b54b3b63a74fa809fe508ab..7792b52b67b9123c9feafbb70df862309722d7f6 100644 --- a/interfaces/policycoreutils/include/hap_restorecon.h +++ b/interfaces/policycoreutils/include/hap_restorecon.h @@ -23,8 +23,8 @@ #define SELINUX_HAP_RESTORECON_RECURSE 1 -// parameters of each SehapContext in file sehap_contexts -struct SehapContext { +// parameters of each SehapInfo in file sehap_contexts +struct SehapInfo { std::string apl = ""; std::string name = ""; std::string domain = ""; @@ -42,7 +42,7 @@ public: int HapDomainSetcontext(const std::string &apl, const std::string &packageName); protected: - static std::unordered_map sehapContextsBuff; + static std::unordered_map sehapContextsBuff; static struct selabel_handle *fileContextsHandle; private: @@ -50,7 +50,7 @@ private: const std::string &packageName); int HapContextsLookup(bool isDomain, const std::string &apl, const std::string &packageName, context_t con); int HapLabelLookup(const std::string &apl, const std::string &packageName, char **secontextPtr); - int TypeSet(std::unordered_map::iterator &iter, bool isDomain, context_t con); + int TypeSet(std::unordered_map::iterator &iter, bool isDomain, context_t con); static void RestoreconInit(); static bool HapContextsLoad(); diff --git a/interfaces/policycoreutils/include/selinux_parameter.h b/interfaces/policycoreutils/include/selinux_parameter.h index 46ea5206c3cd2886fee58d8dd2acd502983c84a5..069bdaca32071883b3dfdf09543e6419700a0b3c 100644 --- a/interfaces/policycoreutils/include/selinux_parameter.h +++ b/interfaces/policycoreutils/include/selinux_parameter.h @@ -29,10 +29,10 @@ typedef struct ParameterNode { char *paraContext; } ParameterNode; -typedef struct ParameterInfoList { +typedef struct ParamContextsList { struct ParameterNode info; - struct ParameterInfoList *next; -} ParameterInfoList; + struct ParamContextsList *next; +} ParamContextsList; /** * @brief set selinux log print to dmesg @@ -45,24 +45,24 @@ void SetSelinuxLogCallback(void); * * @return head of param context list */ -ParameterInfoList *GetParamList(void); +ParamContextsList *GetParamList(void); /** * @brief destroy param list get from GetParamList * * @param list the head of contexts list */ -void DestroyParamList(ParameterInfoList **list); +void DestroyParamList(ParamContextsList **list); /** * @brief for a particular paraName, get its context * * @param paraName the name of param - * @param context the selinux context of param + * @param context the selinux context of param, must free it after use * * @return 0 for success, or an error code */ -int GetParamLabel(const char *paraName, const char **context); +int GetParamLabel(const char *paraName, char **context); /** * @brief for read particular paraName, check its selinux permmisson diff --git a/interfaces/policycoreutils/src/contexts_trie.cpp b/interfaces/policycoreutils/src/contexts_trie.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14af6a6e15f8b127c6991424966577ba208f115d --- /dev/null +++ b/interfaces/policycoreutils/src/contexts_trie.cpp @@ -0,0 +1,137 @@ +/* + * 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 +#include +#include "callbacks.h" +#include "contexts_trie.h" + +static std::vector StringSplit(std::string paraName, std::string split = ".") +{ + size_t pos; + std::vector result; + while ((pos = paraName.find(split)) != std::string::npos) { + std::string element = paraName.substr(0, pos); + if (!element.empty()) { + result.push_back(element); + } + paraName.erase(0, pos + split.length()); + } + if (!paraName.empty()) { + result.push_back(paraName); + } + return result; +} + +static std::string GetFirstElement(std::string ¶Name, std::string split = ".") +{ + size_t pos; + if ((pos = paraName.find(split)) != std::string::npos) { + std::string element = paraName.substr(0, pos); + paraName.erase(0, pos + split.length()); + if (!element.empty()) { + return element; + } + } + std::string result = paraName; + paraName = ""; + return result; +} + +ParamContextsTrie *ParamContextsTrie::FindChild(std::string element) +{ + ParamContextsTrie *root = this; + auto iter = root->childen.find(element); + if (iter != root->childen.end()) { + return iter->second; + } + return nullptr; +} + +bool ParamContextsTrie::Insert(const std::string ¶mPrefix, const std::string &contexts) +{ + ParamContextsTrie *root = this; + std::vector elements = StringSplit(paramPrefix); + for (const auto &element : elements) { + if (root->childen[element] == nullptr) { + root->childen[element] = new (std::nothrow) ParamContextsTrie(); + if (root->childen[element] == nullptr) { + return false; + } + } + root = root->childen[element]; + } + if (paramPrefix.back() == '.') { + root->prefixLabel = contexts; + } else { + root->matchLabel = contexts; + } + return true; +} + +bool ParamContextsTrie::Search(const std::string ¶Name, char **context) +{ + ParamContextsTrie *root = this; + std::string tmpString = paraName; + std::string element = GetFirstElement(tmpString); + const char *updataCurLabel = ""; + while (!element.empty()) { + auto child = root->FindChild(element); + if (child == nullptr) { + if (!root->prefixLabel.empty()) { + *context = strdup(root->prefixLabel.c_str()); + return true; + } else if (strcmp(updataCurLabel, "")) { + *context = strdup(updataCurLabel); + return true; + } else { + return false; + } + } + if (!root->prefixLabel.empty()) + updataCurLabel = root->prefixLabel.c_str(); + root = child; + element = GetFirstElement(tmpString); + } + + if (!root->matchLabel.empty()) { + *context = strdup(root->matchLabel.c_str()); + return true; + } else if (strcmp(updataCurLabel, "")) { + *context = strdup(updataCurLabel); + return true; + } else { + return false; + } +} + +void ParamContextsTrie::Clear() +{ + ParamContextsTrie *root = this; + std::deque nodeDeque; + for (auto child : root->childen) { + nodeDeque.emplace_back(child.second); + } + while (!nodeDeque.empty()) { + root = nodeDeque.front(); + nodeDeque.pop_front(); + if (root != nullptr) { + for (auto child : root->childen) { + nodeDeque.emplace_back(child.second); + } + delete root; + } + } +} diff --git a/interfaces/policycoreutils/src/hap_restorecon.cpp b/interfaces/policycoreutils/src/hap_restorecon.cpp index 16ca3ff5b1fa97a56d80ce545f6bdbcf53442a38..2966e7c2493dc5db4a9a08ca8bc2674ce54079b5 100644 --- a/interfaces/policycoreutils/src/hap_restorecon.cpp +++ b/interfaces/policycoreutils/src/hap_restorecon.cpp @@ -40,7 +40,7 @@ static pthread_once_t FC_ONCE = PTHREAD_ONCE_INIT; } // namespace struct selabel_handle *HapContext::fileContextsHandle = nullptr; -std::unordered_map HapContext::sehapContextsBuff; +std::unordered_map HapContext::sehapContextsBuff; HapContext::HapContext() {} @@ -61,8 +61,9 @@ static bool CouldSkip(const std::string &line) return true; } int i = 0; - while (isspace(line[i++])) - ; + while (isspace(line[i])) { + i++; + } if (line[i] == '#') { return true; } @@ -72,11 +73,11 @@ static bool CouldSkip(const std::string &line) return false; } -static struct SehapContext DecodeString(std::string &line) +static struct SehapInfo DecodeString(std::string &line) { std::stringstream input(line); std::string tmp; - struct SehapContext contextBuff; + struct SehapInfo contextBuff; bool aplVisit = false; bool nameVisit = false; bool domainVisit = false; @@ -136,9 +137,9 @@ bool HapContext::HapContextsLoad() lineNum++; if (CouldSkip(line)) continue; - struct SehapContext tmpContext = DecodeString(line); - if (!tmpContext.apl.empty()) { - sehapContextsBuff.emplace(tmpContext.apl + tmpContext.name, tmpContext); + struct SehapInfo tmpInfo = DecodeString(line); + if (!tmpInfo.apl.empty()) { + sehapContextsBuff.emplace(tmpInfo.apl + tmpInfo.name, tmpInfo); } else { SELINUX_LOG_INFO(LABEL, "hap_contexts read fail in line %{public}d", lineNum); } @@ -152,7 +153,7 @@ bool HapContext::HapContextsLoad() return true; } -int HapContext::TypeSet(std::unordered_map::iterator &iter, bool isDomain, context_t con) +int HapContext::TypeSet(std::unordered_map::iterator &iter, bool isDomain, context_t con) { std::string type = ""; if (isDomain) { diff --git a/interfaces/policycoreutils/src/paraperm_checker.cpp b/interfaces/policycoreutils/src/paraperm_checker.cpp index 768b8943dc1d99807ed6d8de408f35bac0875031..d3a2ce059627d8137fd3ef8bc86c6431c0d10ac7 100644 --- a/interfaces/policycoreutils/src/paraperm_checker.cpp +++ b/interfaces/policycoreutils/src/paraperm_checker.cpp @@ -23,10 +23,10 @@ #include #include #include -#include #include "callbacks.h" #include "selinux_error.h" #include "selinux_klog.h" +#include "contexts_trie.h" using namespace Selinux; @@ -34,7 +34,8 @@ namespace { static const std::string PARAMETER_CONTEXTS_FILE = "/system/etc/selinux/targeted/contexts/parameter_contexts"; static const std::string TYPE_PREFIX = "u:object_r:"; static pthread_once_t FC_ONCE = PTHREAD_ONCE_INIT; -static std::unordered_map paraInfo; +static std::unique_ptr g_contextsTrie = nullptr; +static ParamContextsList *g_contextsList = nullptr; static const int CONTEXTS_LENGTH_MIN = 16; // sizeof("x u:object_r:x:s0") } // namespace @@ -69,6 +70,15 @@ static void SelinuxSetCallback() selinux_set_callback(SELINUX_CB_AUDIT, cb); } +static void ReleaseMem() +{ + DestroyParamList(&g_contextsList); + if (g_contextsTrie != nullptr) { + g_contextsTrie->Clear(); + g_contextsTrie = nullptr; + } +} + static int CheckParaNameValid(const char *paraName) { if (paraName == nullptr) { @@ -91,8 +101,9 @@ static bool CouldSkip(const std::string &line) return true; } int i = 0; - while (isspace(line[i++])) - ; + while (isspace(line[i])) { + i++; + } if (line[i] == '#') { return true; } @@ -124,28 +135,64 @@ static struct ParameterInfo DecodeString(const std::string &line) return contextBuff; } +static bool InsertContextsList(ParameterInfo tmpInfo, ParamContextsList **head) +{ + ParamContextsList *node = (ParamContextsList *)malloc(sizeof(ParamContextsList)); + if (node == nullptr) { + return false; + } + struct ParameterNode contextBuff = {nullptr, nullptr}; + contextBuff.paraName = strdup(tmpInfo.paraName.c_str()); + contextBuff.paraContext = strdup(tmpInfo.paraContext.c_str()); + node->info = contextBuff; + node->next = nullptr; + (*head)->next = node; + *head = (*head)->next; + return true; +} + static bool ParameterContextsLoad() { - // load parameter_contexts file + ReleaseMem(); std::ifstream contextsFile(PARAMETER_CONTEXTS_FILE); - if (contextsFile) { - int lineNum = 0; - std::string line; - while (getline(contextsFile, line)) { - lineNum++; - if (CouldSkip(line)) - continue; - struct ParameterInfo tmpContext = DecodeString(line); - if (!tmpContext.paraContext.empty() && !tmpContext.paraName.empty()) { - paraInfo.emplace(tmpContext.paraName, tmpContext); - } else { - selinux_log(SELINUX_ERROR, "parameter_contexts read fail in line %d\n", lineNum); - } - } - } else { + if (!contextsFile) { selinux_log(SELINUX_ERROR, "Load parameter_contexts fail, no such file: %s\n", PARAMETER_CONTEXTS_FILE.c_str()); return false; } + g_contextsTrie = std::make_unique(); + g_contextsList = (ParamContextsList *)malloc(sizeof(ParamContextsList)); + if (g_contextsList == nullptr) { + selinux_log(SELINUX_ERROR, "malloc param info list head fail\n"); + return false; + } + ParamContextsList *head = g_contextsList; + int lineNum = 0; + std::string line; + while (getline(contextsFile, line)) { + lineNum++; + if (CouldSkip(line)) + continue; + struct ParameterInfo tmpInfo = DecodeString(line); + if (tmpInfo.paraContext.empty() || tmpInfo.paraName.empty()) { + selinux_log(SELINUX_ERROR, "parameter_contexts read fail in line %d\n", lineNum); + continue; + } + if (!g_contextsTrie->Insert(tmpInfo.paraName, tmpInfo.paraContext)) { + selinux_log(SELINUX_ERROR, "insert contexts trie node fail\n"); + contextsFile.close(); + ReleaseMem(); + return false; + } + if (!InsertContextsList(tmpInfo, &head)) { + selinux_log(SELINUX_ERROR, "malloc param info list node fail\n"); + contextsFile.close(); + ReleaseMem(); + return false; + } + } + head = g_contextsList->next; + free(g_contextsList); + g_contextsList = head; selinux_log(SELINUX_INFO, "Load parameter_contexts succes: %s\n", PARAMETER_CONTEXTS_FILE.c_str()); contextsFile.close(); return true; @@ -172,13 +219,13 @@ void SetSelinuxLogCallback() return; } -void DestroyParamList(ParameterInfoList **list) +void DestroyParamList(ParamContextsList **list) { if (list == nullptr) { return; } - ParameterInfoList *tmpNode; - ParameterInfoList *listHead = *list; + ParamContextsList *tmpNode; + ParamContextsList *listHead = *list; while (listHead != nullptr) { tmpNode = listHead->next; free(listHead->info.paraName); @@ -192,43 +239,17 @@ void DestroyParamList(ParameterInfoList **list) return; } -ParameterInfoList *GetParamList() +ParamContextsList *GetParamList() { - // GetParamList for hash map - ParameterInfoList *ptrParaInfo = nullptr; - if (paraInfo.empty()) { + if (g_contextsList == nullptr) { if (!ParameterContextsLoad()) { return nullptr; } } - - ptrParaInfo = (ParameterInfoList *)malloc(sizeof(ParameterInfoList)); - if (ptrParaInfo == nullptr) { - return nullptr; - } - ParameterInfoList *head = ptrParaInfo; - for (auto info : paraInfo) { - ParameterInfoList *node = (ParameterInfoList *)malloc(sizeof(ParameterInfoList)); - if (node == nullptr) { - DestroyParamList(&ptrParaInfo); - return nullptr; - } - struct ParameterNode contextBuff = {nullptr, nullptr}; - contextBuff.paraName = strdup(info.second.paraName.c_str()); - contextBuff.paraContext = strdup(info.second.paraContext.c_str()); - node->info = contextBuff; - node->next = nullptr; - head->next = node; - head = head->next; - } - selinux_log(SELINUX_INFO, "Get contexts list for hash map succes\n"); - head = ptrParaInfo->next; - free(ptrParaInfo); - ptrParaInfo = nullptr; - return head; + return g_contextsList; } -int GetParamLabel(const char *paraName, const char **context) +int GetParamLabel(const char *paraName, char **context) { if (paraName == nullptr || context == nullptr) { return -SELINUX_PTR_NULL; @@ -240,30 +261,17 @@ int GetParamLabel(const char *paraName, const char **context) return ret; } - if (paraInfo.empty()) { + if (g_contextsTrie == nullptr) { if (!ParameterContextsLoad()) { return -SELINUX_CONTEXTS_FILE_LOAD_ERROR; } } - std::string name(paraName); - auto pos = name.find_last_of("."); - while (pos != std::string::npos) { - auto iter = paraInfo.find(name); - if (iter != paraInfo.end()) { - *context = iter->second.paraContext.c_str(); - selinux_log(SELINUX_INFO, "find context: %s\n", *context); - return SELINUX_SUCC; - } - name = name.substr(0, pos + 1); - pos = name.substr(0, pos).find_last_of("."); - } - auto iter = paraInfo.find(name); - if (iter != paraInfo.end()) { - *context = iter->second.paraContext.c_str(); - selinux_log(SELINUX_INFO, "find context: %s\n", *context); - return SELINUX_SUCC; + + if (!g_contextsTrie->Search(std::string(paraName), context)) { + return -SELINUX_KEY_NOT_FOUND; } - return -SELINUX_KEY_NOT_FOUND; + selinux_log(SELINUX_INFO, "find context: %s\n", *context); + return SELINUX_SUCC; } int ReadParamCheck(const char *paraName) @@ -285,9 +293,9 @@ int ReadParamCheck(const char *paraName) msg.name = paraName; ucred uc = {.pid = getpid(), .uid = getuid(), .gid = getgid()}; msg.ucred = &uc; - const char *destContext = nullptr; + char *destContext = nullptr; if (GetParamLabel(paraName, &destContext) != 0) { - destContext = "u:object_r:default_para:s0"; + destContext = strdup("u:object_r:default_para:s0"); } if (srcContext == nullptr || destContext == nullptr) { freecon(srcContext); @@ -297,6 +305,7 @@ int ReadParamCheck(const char *paraName) destContext); int res = selinux_check_access(srcContext, destContext, "file", "read", &msg); freecon(srcContext); + free(destContext); return res == 0 ? SELINUX_SUCC : -SELINUX_PERMISSION_DENY; } @@ -319,11 +328,12 @@ int SetParamCheck(const char *paraName, struct ucred *uc) selinux_log(SELINUX_ERROR, "getpidcon failed!\n"); return -SELINUX_GET_CONTEXT_ERROR; } - const char *destContext = nullptr; + char *destContext = nullptr; if (GetParamLabel(paraName, &destContext) != 0) { - destContext = "u:object_r:default_para:s0"; + destContext = strdup("u:object_r:default_para:s0"); } int res = CheckPerm(std::string(paraName), srcContext, destContext, *uc); freecon(srcContext); + free(destContext); return res; } diff --git a/interfaces/policycoreutils/src/service_checker.cpp b/interfaces/policycoreutils/src/service_checker.cpp index 0943269a3a24b753f3d30cc3154b8073538e7d60..b1c57b0ddcd861f0068612a748550ad4148d870a 100644 --- a/interfaces/policycoreutils/src/service_checker.cpp +++ b/interfaces/policycoreutils/src/service_checker.cpp @@ -69,8 +69,9 @@ static bool CouldSkip(const std::string &line) return true; } int i = 0; - while (isspace(line[i++])) - ; + while (isspace(line[i])) { + i++; + } if (line[i] == '#') { return true; } @@ -134,9 +135,9 @@ bool ServiceChecker::ServiceContextsLoad() lineNum++; if (CouldSkip(line)) continue; - struct ServiceInfo tmpContext = DecodeString(line); - if (!tmpContext.serviceContext.empty() && !tmpContext.serviceName.empty()) { - serviceMap.emplace(tmpContext.serviceName, tmpContext); + struct ServiceInfo tmpInfo = DecodeString(line); + if (!tmpInfo.serviceContext.empty() && !tmpInfo.serviceName.empty()) { + serviceMap.emplace(tmpInfo.serviceName, tmpInfo); } else { selinux_log(SELINUX_ERROR, "service_contexts read fail in line %d\n", lineNum); } diff --git a/interfaces/tools/param_check/test.cpp b/interfaces/tools/param_check/test.cpp index 76a0b357269d5f1c12b4bf79819bb84053000b2a..7d838e0a0bc9589a7ff838643fdaca0a5702d786 100644 --- a/interfaces/tools/param_check/test.cpp +++ b/interfaces/tools/param_check/test.cpp @@ -16,37 +16,45 @@ #include #include #include +#include +#ifdef TIME_DISPLAY #include -#include "selinux_parameter.h" +#endif #include "selinux_error.h" +#include "selinux_parameter.h" using namespace Selinux; +#ifdef TIME_DISPLAY const static long USEC_PER_SEC = 1000000L; +#endif + struct testInput { - std::string pid; std::string paraName; - bool read; + char cmd = '\0'; }; static void TestLoadList() { - struct timeval start, end, diff; std::string path = "/dev/__parameters__/"; - - ParameterInfoList *buff = nullptr; + ParamContextsList *buff = nullptr; +#ifdef TIME_DISPLAY + struct timeval start, end, diff; gettimeofday(&start, nullptr); +#endif buff = GetParamList(); if (buff == nullptr) { std::cout << "buff empty" << std::endl; return; } +#ifdef TIME_DISPLAY gettimeofday(&end, nullptr); timersub(&end, &start, &diff); int runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; std::cout << "GetParamList time use: " << runtime_us << std::endl; +#endif - ParameterInfoList *head = buff; + ParamContextsList *head = buff; while (buff != nullptr) { if (security_check_context(buff->info.paraContext) < 0) { std::cout << "failed check context: " << buff->info.paraContext << std::endl; @@ -66,55 +74,99 @@ static void TestLoadList() } buff = buff->next; } - +#ifdef TIME_DISPLAY gettimeofday(&start, nullptr); +#endif DestroyParamList(&head); +#ifdef TIME_DISPLAY gettimeofday(&end, nullptr); timersub(&end, &start, &diff); runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; std::cout << "DestroyParamList time use: " << runtime_us << std::endl; +#endif } static void TestGetContext(std::string ¶Name) { + char *context = nullptr; +#ifdef TIME_DISPLAY struct timeval start, end, diff; - const char *context = nullptr; gettimeofday(&start, nullptr); +#endif int res = GetParamLabel(paraName.c_str(), &context); +#ifdef TIME_DISPLAY + gettimeofday(&end, nullptr); + timersub(&end, &start, &diff); + int runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; + std::cout << "time use: " << runtime_us << std::endl; +#endif if (res == 0) { std::cout << "para " << paraName.c_str() << "'s context is " << context << std::endl; } else { - std::cout << "para " << paraName.c_str() << "'s context get fail, err: " << res << std::endl; + std::cout << "para " << paraName.c_str() << "'s context get fail, " << GetErrStr(res) << std::endl; + } + if (!context) { + free(context); } +} + +static void TestReadPara(std::string ¶Name) +{ +#ifdef TIME_DISPLAY + struct timeval start, end, diff; + gettimeofday(&start, nullptr); +#endif + std::cout << GetErrStr(ReadParamCheck(paraName.c_str())) << std::endl; +#ifdef TIME_DISPLAY + gettimeofday(&end, nullptr); + timersub(&end, &start, &diff); + int runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; + std::cout << "time use: " << runtime_us << std::endl; +#endif +} + +static void TestSetPara(std::string ¶Name, struct ucred *uc) +{ +#ifdef TIME_DISPLAY + struct timeval start, end, diff; + gettimeofday(&start, nullptr); +#endif + std::cout << GetErrStr(SetParamCheck(paraName.c_str(), uc)) << std::endl; +#ifdef TIME_DISPLAY gettimeofday(&end, nullptr); timersub(&end, &start, &diff); int runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; - std::cout << "GetParamLabel time use: " << runtime_us << std::endl; + std::cout << "time use: " << runtime_us << std::endl; +#endif } static void PrintUsage() { - std::cout << "Usage:" << std::endl; - std::cout << "param_check -n abc.efg -r" << std::endl; - std::cout << "param_check -p $(pidof init) -n abc.efg -w" << std::endl; - std::cout << "param_check -g build_version" << std::endl; - std::cout << "param_check -l" << std::endl; - std::cout << "" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -h (--help) show the help information. [eg: param_check -h]" << std::endl; - std::cout << " -p (--pid) subject process pid. [eg: -p 1]" << std::endl; - std::cout << " -n (--paraName) paraName. [eg: -n build_version]" << std::endl; - std::cout << " -g (--getContext) get context for paraName. [eg: -g build_version]" << std::endl; - std::cout << " -r (--read) read para perm. [eg: -r]" << std::endl; - std::cout << " -w (--write) write para perm. [eg: -w]" << std::endl; - std::cout << " -l (--list) load para list. [eg: -l]" << std::endl; + std::cout << " -g (--getContext) get context for paraName. [eg: param_check -g]" << std::endl; + std::cout << " -r (--read) read para perm. [eg: param_check -r]" << std::endl; + std::cout << " -w (--write) write para perm. [eg: param_check -w]" << std::endl; + std::cout << " -l (--list) load para list. [eg: param_check -l]" << std::endl; + std::cout << " -n (--paraName) paraName. [eg: param_check -r|-w|-g -n para_name]" + << std::endl; + std::cout << "" << std::endl; + std::cout << "Usage:" << std::endl; + std::cout << ">>>>>>> choice 1: continuous input parameters" << std::endl; + std::cout << "step 1:" << std::endl; + std::cout << "param_check -r|-w|-g|-l" << std::endl; + std::cout << "step 2:" << std::endl; + std::cout << "input param name and press 'enter' to continue, or ctrl+C to end process" << std::endl; + std::cout << "" << std::endl; + std::cout << ">>>>>>> choice 2: single input parameter" << std::endl; + std::cout << "param_check -r|-w|-g -n para_name" << std::endl; std::cout << "" << std::endl; } static void SetOptions(int argc, char *argv[], const option *options, testInput &input) { int index = 0; - const char *optStr = "lhrwn:p:g:"; + const char *optStr = "hgrwln:"; int para = 0; while ((para = getopt_long(argc, argv, optStr, options, &index)) != -1) { switch (para) { @@ -122,25 +174,20 @@ static void SetOptions(int argc, char *argv[], const option *options, testInput PrintUsage(); exit(0); } - case 'p': { - input.pid = optarg; - break; - } case 'n': { input.paraName = optarg; break; } case 'g': { - std::string paraName = optarg; - TestGetContext(paraName); - exit(0); + input.cmd = 'g'; + break; } case 'r': { - input.read = true; + input.cmd = 'r'; break; } case 'w': { - input.read = false; + input.cmd = 'w'; break; } case 'l': { @@ -154,16 +201,56 @@ static void SetOptions(int argc, char *argv[], const option *options, testInput } } +static void Test(testInput &testCmd) +{ + std::string paraName; + switch (testCmd.cmd) { + case 'g': { + if (!testCmd.paraName.empty()) { + TestGetContext(testCmd.paraName); + exit(0); + } + while (std::cin >> paraName) { + TestGetContext(paraName); + } + exit(0); + } + case 'r': { + if (!testCmd.paraName.empty()) { + TestReadPara(testCmd.paraName); + exit(0); + } + while (std::cin >> paraName) { + TestReadPara(paraName); + } + exit(0); + } + case 'w': { + struct ucred uc; + uc.pid = getpid(); + uc.uid = getuid(); + uc.gid = getgid(); + if (!testCmd.paraName.empty()) { + TestSetPara(testCmd.paraName, &uc); + exit(0); + } + while (std::cin >> paraName) { + TestSetPara(paraName, &uc); + } + exit(0); + } + default: + PrintUsage(); + exit(-1); + } +} + int main(int argc, char *argv[]) { struct option options[] = { - {"help", no_argument, nullptr, 'h'}, - {"pid", required_argument, nullptr, 'p'}, - {"paraName", required_argument, nullptr, 'n'}, - {"read", no_argument, nullptr, 'r'}, - {"write", no_argument, nullptr, 'w'}, - {"list", no_argument, nullptr, 'l'}, - {"getContext", required_argument, nullptr, 'g'}, + {"help", no_argument, nullptr, 'h'}, {"paraName", required_argument, nullptr, 'n'}, + {"read", no_argument, nullptr, 'r'}, {"write", no_argument, nullptr, 'w'}, + {"list", no_argument, nullptr, 'l'}, {"getContext", no_argument, nullptr, 'g'}, {nullptr, no_argument, nullptr, 0}, }; @@ -174,24 +261,6 @@ int main(int argc, char *argv[]) SetSelinuxLogCallback(); testInput testCmd; SetOptions(argc, argv, options, testCmd); - int res = 0; - struct timeval start, end, diff; - gettimeofday(&start, nullptr); - if (testCmd.read) { - res = ReadParamCheck(testCmd.paraName.c_str()); - std::cout << GetErrStr(res) << std::endl; - } else { - struct ucred uc; - uc.pid = atoi(testCmd.pid.c_str()); - uc.uid = 0; - uc.gid = 0; - res = SetParamCheck(testCmd.paraName.c_str(), &uc); - std::cout << GetErrStr(res) << std::endl; - } - gettimeofday(&end, nullptr); - timersub(&end, &start, &diff); - int runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; - std::cout << "time use: " << runtime_us << std::endl; - + Test(testCmd); exit(0); } diff --git a/scripts/build_contexts.py b/scripts/build_contexts.py index b510bc57107cedbd9a75b5736d8f3c3c4b241fe8..62ec74a700b9c583c6d4b24f7a65e8dd9235bdef 100755 --- a/scripts/build_contexts.py +++ b/scripts/build_contexts.py @@ -21,6 +21,7 @@ import os import argparse import re import shutil +from collections import defaultdict SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__)) LOCAL_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, "../")) @@ -50,21 +51,6 @@ def run_command(in_cmd): raise Exception(rc) -def build_file_contexts_tmp(output_tmp, input_file_contexts_list): - build_tmp_cmd = ["m4", - "--fatal-warnings", - "-s", input_file_contexts_list, ">", output_tmp] - run_command(build_tmp_cmd) - - -def build_file_contexts_bin(args, input_file_contexts_tmp): - build_bin_cmd = [args.tool_path + "/sefcontext_compile", - "-o", args.dst_file, - "-p", args.policy_file, - input_file_contexts_tmp] - run_command(build_bin_cmd) - - def traverse_folder_in_type(search_dir, file_suffix): """ for special folder search_dir, find all files endwith file_suffix. @@ -94,6 +80,44 @@ def combine_file_contexts(file_contexts_list, combined_file_contexts): run_command(grep_cmd) +def check_redefinition(contexts_file): + type_hash = defaultdict(list) + err = 0 + with open(contexts_file, 'r') as contexts_read: + pattern = re.compile(r'(\S+)\s+u:object_r:\S+:s0') + line_index = 0 + for line in contexts_read: + line_ = line.lstrip() + line_index += 1 + if line_.startswith('#') or line_.strip() == '': + continue + match = pattern.match(line_) + if match: + type_hash[match.group(1)].append(line_index) + else: + print(contexts_file + ":" + + str(line_index) + " format check fail") + err = 1 + contexts_read.close() + if err: + print("***********************************************************") + print("please check whether the format meets the following rules:") + print("[required format]: * u:object_r:*:s0") + print("***********************************************************") + raise Exception(err) + err = 0 + for type_key in type_hash.keys(): + if len(type_hash[type_key]) > 1: + err = 1 + err_msg = contexts_file + ":" + for linenum in type_hash[type_key]: + err_msg += str(linenum) + " " + err_msg += "'type " + str(type_key) + " is redefinition'" + print(err_msg) + if err: + raise Exception(err) + + def check_contexts_file(args, contexts_file): """ check whether context used in contexts_file is defined in policy.31. @@ -101,7 +125,10 @@ def check_contexts_file(args, contexts_file): :param contexts_file: path of contexts file :return: """ + check_redefinition(contexts_file) + check_cmd = [args.tool_path + "/sefcontext_compile", + "-o", contexts_file + ".bin", "-p", args.policy_file, contexts_file] run_command(check_cmd) @@ -123,7 +150,7 @@ def check_sehap_contexts(args, contexts_file, domain): err = 0 with open(contexts_file + "_bk", 'r') as contexts_read, open(contexts_file, 'w') as contexts_write: pattern = re.compile( - r'apl=(system_core|system_basic|normal)[ \t]+(name=[\w\.-]+[ \t]+)?domain=([\w-]+)[ \t]+type=([\w-]+)[ \t]*\n') + r'apl=(system_core|system_basic|normal)\s+(name=\S+\s+)?domain=(\S+)\s+type=(\S+)\s*\n') line_index = 0 for line in contexts_read: line_ = line.lstrip() @@ -134,13 +161,14 @@ def check_sehap_contexts(args, contexts_file, domain): match = pattern.match(line_) if match: if domain: - line = match[1] + " u:r:" + match[3] + ":s0\n" + line = match.group(1) + " u:r:" + match.group(3) + ":s0\n" else: - line = match[4] + " u:object_r:" + match[4] + ":s0\n" + line = match.group(1) + " u:object_r:" + \ + match.group(4) + ":s0\n" contexts_write.write(line) else: - print(contexts_file + - ":" + str(line_index) + " format check fail") + print(contexts_file + ":" + + str(line_index) + " format check fail") err = 1 contexts_read.close() contexts_write.close() @@ -156,6 +184,7 @@ def check_sehap_contexts(args, contexts_file, domain): print("***********************************************************") raise Exception(err) check_cmd = [args.tool_path + "/sefcontext_compile", + "-o", contexts_file + ".bin", "-p", args.policy_file, contexts_file] rc = os.system(" ".join(check_cmd)) @@ -167,19 +196,29 @@ def check_sehap_contexts(args, contexts_file, domain): os.unlink(contexts_file + ".bin") -def main(args): - output_path = os.path.abspath(os.path.dirname(args.dst_file)) - +def build_file_contetxs(args, output_path): file_contexts_list = traverse_folder_in_type( POLICY_PATH, "file_contexts") combined_file_contexts = output_path + "/file_contexts" combine_file_contexts(file_contexts_list, combined_file_contexts) - file_contexts_tmp = output_path + "/file_contexts.tmp" - build_file_contexts_tmp(file_contexts_tmp, combined_file_contexts) + build_tmp_cmd = ["m4", + "--fatal-warnings", + "-s", combined_file_contexts, ">", output_path + "/file_contexts.tmp"] + run_command(build_tmp_cmd) + + build_bin_cmd = [args.tool_path + "/sefcontext_compile", + "-o", args.dst_file, + "-p", args.policy_file, + output_path + "/file_contexts.tmp"] + run_command(build_bin_cmd) + + +def main(args): + output_path = os.path.abspath(os.path.dirname(args.dst_file)) - build_file_contexts_bin(args, file_contexts_tmp) + build_file_contetxs(args, output_path) check_contexts_file(args, SERVICE_CONTEXTS_PATH) check_contexts_file(args, HDF_SERVICE_CONTEXTS_PATH) diff --git a/sepolicy/base/public/parameter.te b/sepolicy/base/public/parameter.te index 689cccf51815891dcf09f7092daa7d2e5d1d0193..8ad0964664e895232976f9fac17f448c7bb0a59f 100644 --- a/sepolicy/base/public/parameter.te +++ b/sepolicy/base/public/parameter.te @@ -34,5 +34,6 @@ type hilog_param, parameter_type; type persist_param, parameter_type; type persist_sys_param, parameter_type; type debug_param, parameter_type; +type default_para, parameter_type; type build_version_param, parameter_type; diff --git a/test/unittest/src/selinux_unit_test.cpp b/test/unittest/src/selinux_unit_test.cpp index 2fbd50eb10fe44fdee55e67ccb47022f18f4880d..438dc91ec1e04ddafde825f7fed7f036cc88758a 100644 --- a/test/unittest/src/selinux_unit_test.cpp +++ b/test/unittest/src/selinux_unit_test.cpp @@ -656,10 +656,10 @@ HWTEST_F(SelinuxUnitTest, HapDomainSetcontext003, TestSize.Level1) */ HWTEST_F(SelinuxUnitTest, GetParamList001, TestSize.Level1) { - ParameterInfoList *buff = nullptr; + ParamContextsList *buff = nullptr; buff = GetParamList(); ASSERT_NE(nullptr, buff); - ParameterInfoList *head = buff; + ParamContextsList *head = buff; bool find = false; while (buff != nullptr) { if (std::string(buff->info.paraName) == TEST_PARA_NAME && @@ -696,7 +696,7 @@ HWTEST_F(SelinuxUnitTest, DestroyParamList001, TestSize.Level1) */ HWTEST_F(SelinuxUnitTest, GetParamLabel001, TestSize.Level1) { - const char *context = nullptr; + char *context = nullptr; ASSERT_EQ(-SELINUX_PTR_NULL, GetParamLabel(nullptr, &context)); ASSERT_EQ(-SELINUX_PTR_NULL, GetParamLabel(TEST_PARA_NAME.c_str(), nullptr)); @@ -706,6 +706,9 @@ HWTEST_F(SelinuxUnitTest, GetParamLabel001, TestSize.Level1) } ASSERT_EQ(-SELINUX_KEY_NOT_FOUND, GetParamLabel(TEST_NOT_EXIST_PARA_NAME.c_str(), &context)); + if (!context) { + free(context); + } } /** @@ -716,9 +719,12 @@ HWTEST_F(SelinuxUnitTest, GetParamLabel001, TestSize.Level1) */ HWTEST_F(SelinuxUnitTest, GetParamLabel002, TestSize.Level1) { - const char *context = nullptr; + char *context = nullptr; ASSERT_EQ(SELINUX_SUCC, GetParamLabel(TEST_PARA_NAME.c_str(), &context)); ASSERT_EQ(TEST_PARA_CONTEXT, std::string(context)); + if (!context) { + free(context); + } } /**