1d9f0492fSopenharmony_ci/* 2d9f0492fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License. 5d9f0492fSopenharmony_ci * You may obtain a copy of the License at 6d9f0492fSopenharmony_ci * 7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8d9f0492fSopenharmony_ci * 9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and 13d9f0492fSopenharmony_ci * limitations under the License. 14d9f0492fSopenharmony_ci */ 15d9f0492fSopenharmony_ci#include <errno.h> 16d9f0492fSopenharmony_ci#include <dlfcn.h> 17d9f0492fSopenharmony_ci#include <sys/socket.h> 18d9f0492fSopenharmony_ci 19d9f0492fSopenharmony_ci#include "init_utils.h" 20d9f0492fSopenharmony_ci#include "param_manager.h" 21d9f0492fSopenharmony_ci#include "param_security.h" 22d9f0492fSopenharmony_ci#include "param_utils.h" 23d9f0492fSopenharmony_ci#include "param_base.h" 24d9f0492fSopenharmony_ci#ifdef PARAM_SUPPORT_SELINUX 25d9f0492fSopenharmony_ci#include "selinux_parameter.h" 26d9f0492fSopenharmony_ci#endif 27d9f0492fSopenharmony_ci 28d9f0492fSopenharmony_ci#if defined (__aarch64__) || defined(__x86_64__) || (defined(__riscv) && __riscv_xlen == 64) 29d9f0492fSopenharmony_ci#define CHECKER_LIB_NAME "/system/lib64/libparaperm_checker.z.so" 30d9f0492fSopenharmony_ci#define CHECKER_UPDATER_LIB "/lib64/libparaperm_checker.z.so" 31d9f0492fSopenharmony_ci#else 32d9f0492fSopenharmony_ci#define CHECKER_LIB_NAME "/system/lib/libparaperm_checker.z.so" 33d9f0492fSopenharmony_ci#define CHECKER_UPDATER_LIB "/lib/libparaperm_checker.z.so" 34d9f0492fSopenharmony_ci#endif 35d9f0492fSopenharmony_citypedef int (*SelinuxSetParamCheck)(const char *paraName, const char *destContext, const SrcInfo *info); 36d9f0492fSopenharmony_ci 37d9f0492fSopenharmony_cistatic int InitSelinuxOpsForInit(SelinuxSpace *selinuxSpace) 38d9f0492fSopenharmony_ci{ 39d9f0492fSopenharmony_ci if (selinuxSpace->selinuxHandle == NULL) { 40d9f0492fSopenharmony_ci const char *libname = (GetParamWorkSpace()->ops.updaterMode == 1) ? CHECKER_UPDATER_LIB : CHECKER_LIB_NAME; 41d9f0492fSopenharmony_ci selinuxSpace->selinuxHandle = dlopen(libname, RTLD_LAZY); 42d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->selinuxHandle != NULL, 43d9f0492fSopenharmony_ci return 0, "Failed to dlsym selinuxHandle, %s", dlerror()); 44d9f0492fSopenharmony_ci } 45d9f0492fSopenharmony_ci void *handle = selinuxSpace->selinuxHandle; 46d9f0492fSopenharmony_ci if (selinuxSpace->setParamCheck == NULL) { 47d9f0492fSopenharmony_ci selinuxSpace->setParamCheck = (SelinuxSetParamCheck)dlsym(handle, "SetParamCheck"); 48d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->setParamCheck != NULL, return -1, "Failed to dlsym setParamCheck %s", dlerror()); 49d9f0492fSopenharmony_ci } 50d9f0492fSopenharmony_ci if (selinuxSpace->getParamList == NULL) { 51d9f0492fSopenharmony_ci selinuxSpace->getParamList = (ParamContextsList *(*)()) dlsym(handle, "GetParamList"); 52d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->getParamList != NULL, return -1, "Failed to dlsym getParamList %s", dlerror()); 53d9f0492fSopenharmony_ci } 54d9f0492fSopenharmony_ci if (selinuxSpace->getParamLabel == NULL) { 55d9f0492fSopenharmony_ci selinuxSpace->getParamLabel = (const char *(*)(const char *))dlsym(handle, "GetParamLabel"); 56d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->getParamLabel != NULL, return -1, "Failed to dlsym getParamLabel %s", dlerror()); 57d9f0492fSopenharmony_ci } 58d9f0492fSopenharmony_ci if (selinuxSpace->initParamSelinux == NULL) { 59d9f0492fSopenharmony_ci selinuxSpace->initParamSelinux = (int (*)(int))dlsym(handle, "InitParamSelinux"); 60d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->initParamSelinux != NULL, return -1, "Failed to dlsym initParamSelinux "); 61d9f0492fSopenharmony_ci } 62d9f0492fSopenharmony_ci if (selinuxSpace->getParamLabelIndex == NULL) { 63d9f0492fSopenharmony_ci selinuxSpace->getParamLabelIndex = (int (*)(const char *))dlsym(handle, "GetParamLabelIndex"); 64d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->getParamLabelIndex != NULL, return -1, "Failed to dlsym getParamLabelIndex "); 65d9f0492fSopenharmony_ci } 66d9f0492fSopenharmony_ci if (selinuxSpace->setSelinuxLogCallback == NULL) { 67d9f0492fSopenharmony_ci selinuxSpace->setSelinuxLogCallback = (void (*)())dlsym(handle, "SetInitSelinuxLog"); 68d9f0492fSopenharmony_ci } 69d9f0492fSopenharmony_ci if (selinuxSpace->destroyParamList == NULL) { 70d9f0492fSopenharmony_ci selinuxSpace->destroyParamList = 71d9f0492fSopenharmony_ci (void (*)(ParamContextsList **))dlsym(handle, "DestroyParamList"); 72d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->destroyParamList != NULL, 73d9f0492fSopenharmony_ci return -1, "Failed to dlsym destroyParamList %s", dlerror()); 74d9f0492fSopenharmony_ci } 75d9f0492fSopenharmony_ci 76d9f0492fSopenharmony_ci // init and open avc log 77d9f0492fSopenharmony_ci int ret = selinuxSpace->initParamSelinux(1); 78d9f0492fSopenharmony_ci if (selinuxSpace->setSelinuxLogCallback != NULL) { 79d9f0492fSopenharmony_ci selinuxSpace->setSelinuxLogCallback(); 80d9f0492fSopenharmony_ci } 81d9f0492fSopenharmony_ci return ret; 82d9f0492fSopenharmony_ci} 83d9f0492fSopenharmony_ci 84d9f0492fSopenharmony_cistatic int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit) 85d9f0492fSopenharmony_ci{ 86d9f0492fSopenharmony_ci PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace"); 87d9f0492fSopenharmony_ci UNUSED(isInit); 88d9f0492fSopenharmony_ci PARAM_CHECK(security != NULL, return -1, "Invalid security"); 89d9f0492fSopenharmony_ci security->cred.pid = getpid(); 90d9f0492fSopenharmony_ci security->cred.uid = geteuid(); 91d9f0492fSopenharmony_ci security->cred.gid = getegid(); 92d9f0492fSopenharmony_ci security->flags[PARAM_SECURITY_SELINUX] = 0; 93d9f0492fSopenharmony_ci PARAM_LOGV("InitLocalSecurityLabel"); 94d9f0492fSopenharmony_ci#if !(defined STARTUP_INIT_TEST || defined LOCAL_TEST) 95d9f0492fSopenharmony_ci if ((bool)isInit) { 96d9f0492fSopenharmony_ci int ret = InitSelinuxOpsForInit(&GetParamWorkSpace()->selinuxSpace); 97d9f0492fSopenharmony_ci PARAM_CHECK(ret == 0, return -1, "Failed to init selinux ops"); 98d9f0492fSopenharmony_ci } else { 99d9f0492fSopenharmony_ci SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace; 100d9f0492fSopenharmony_ci selinuxSpace->initParamSelinux = InitParamSelinux; 101d9f0492fSopenharmony_ci selinuxSpace->getParamList = GetParamList; 102d9f0492fSopenharmony_ci selinuxSpace->getParamLabel = GetParamLabel; 103d9f0492fSopenharmony_ci selinuxSpace->destroyParamList = DestroyParamList; 104d9f0492fSopenharmony_ci selinuxSpace->getParamLabelIndex = GetParamLabelIndex; 105d9f0492fSopenharmony_ci // init 106d9f0492fSopenharmony_ci selinuxSpace->initParamSelinux(isInit); 107d9f0492fSopenharmony_ci } 108d9f0492fSopenharmony_ci#endif 109d9f0492fSopenharmony_ci PARAM_LOGV("Load selinux lib success."); 110d9f0492fSopenharmony_ci return 0; 111d9f0492fSopenharmony_ci} 112d9f0492fSopenharmony_ci 113d9f0492fSopenharmony_cistatic int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel) 114d9f0492fSopenharmony_ci{ 115d9f0492fSopenharmony_ci return 0; 116d9f0492fSopenharmony_ci} 117d9f0492fSopenharmony_ci 118d9f0492fSopenharmony_cistatic void SetSelinuxFileCon(const char *name, const char *context) 119d9f0492fSopenharmony_ci{ 120d9f0492fSopenharmony_ci PARAM_CHECK(GetParamWorkSpace() != NULL && GetParamWorkSpace()->ops.setfilecon != NULL, 121d9f0492fSopenharmony_ci return, "Invalid workspace or setfilecon"); 122d9f0492fSopenharmony_ci static char buffer[FILENAME_LEN_MAX] = {0}; 123d9f0492fSopenharmony_ci int len = PARAM_SPRINTF(buffer, sizeof(buffer), "%s/%s", PARAM_STORAGE_PATH, context); 124d9f0492fSopenharmony_ci if (len > 0) { 125d9f0492fSopenharmony_ci buffer[len] = '\0'; 126d9f0492fSopenharmony_ci PARAM_LOGV("setfilecon name %s path: %s %s ", name, context, buffer); 127d9f0492fSopenharmony_ci if (GetParamWorkSpace()->ops.setfilecon(buffer, context) < 0) { 128d9f0492fSopenharmony_ci PARAM_LOGE("Failed to setfilecon %s ", context); 129d9f0492fSopenharmony_ci } 130d9f0492fSopenharmony_ci } 131d9f0492fSopenharmony_ci} 132d9f0492fSopenharmony_ci 133d9f0492fSopenharmony_cistatic void HandleSelinuxLabelForOpen(const ParameterNode *paramNode, int readOnly) 134d9f0492fSopenharmony_ci{ 135d9f0492fSopenharmony_ci uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE; 136d9f0492fSopenharmony_ci int ret = OpenWorkSpace(labelIndex, readOnly); 137d9f0492fSopenharmony_ci if (ret != 0) { 138d9f0492fSopenharmony_ci PARAM_LOGE("Forbid to add selinux workspace %s %s", paramNode->paraName, paramNode->paraContext); 139d9f0492fSopenharmony_ci return; 140d9f0492fSopenharmony_ci } 141d9f0492fSopenharmony_ci if (!readOnly) { 142d9f0492fSopenharmony_ci // set selinux label 143d9f0492fSopenharmony_ci SetSelinuxFileCon(paramNode->paraName, paramNode->paraContext); 144d9f0492fSopenharmony_ci } 145d9f0492fSopenharmony_ci} 146d9f0492fSopenharmony_ci 147d9f0492fSopenharmony_cistatic void HandleSelinuxLabelForInit(const ParameterNode *paramNode, int readOnly) 148d9f0492fSopenharmony_ci{ 149d9f0492fSopenharmony_ci uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE; 150d9f0492fSopenharmony_ci int ret = AddWorkSpace(paramNode->paraContext, labelIndex, readOnly, 0); 151d9f0492fSopenharmony_ci PARAM_CHECK(ret == 0, return, "Not enough memory for %s", paramNode->paraContext); 152d9f0492fSopenharmony_ci 153d9f0492fSopenharmony_ci ParamWorkSpace *paramSpace = GetParamWorkSpace(); 154d9f0492fSopenharmony_ci PARAM_CHECK(paramSpace != NULL, return, "Invalid workspace"); 155d9f0492fSopenharmony_ci if (paramSpace->maxLabelIndex < labelIndex) { 156d9f0492fSopenharmony_ci paramSpace->maxLabelIndex = labelIndex; 157d9f0492fSopenharmony_ci } 158d9f0492fSopenharmony_ci} 159d9f0492fSopenharmony_ci 160d9f0492fSopenharmony_ciint SelinuxGetAllLabel(int readOnly, 161d9f0492fSopenharmony_ci void (*handleSelinuxLabel)(const ParameterNode *paramNode, int readOnly)) 162d9f0492fSopenharmony_ci{ 163d9f0492fSopenharmony_ci SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace; 164d9f0492fSopenharmony_ci PARAM_CHECK(selinuxSpace->getParamList != NULL, return DAC_RESULT_FORBIDED, "Invalid getParamList"); 165d9f0492fSopenharmony_ci ParamContextsList *node = selinuxSpace->getParamList(); 166d9f0492fSopenharmony_ci int count = 0; 167d9f0492fSopenharmony_ci while (node != NULL) { 168d9f0492fSopenharmony_ci PARAM_LOGV("SelinuxGetAllLabel index %d name %s content %s", 169d9f0492fSopenharmony_ci node->info.index, node->info.paraName, node->info.paraContext); 170d9f0492fSopenharmony_ci if (node->info.paraContext == NULL || node->info.paraName == NULL) { 171d9f0492fSopenharmony_ci node = node->next; 172d9f0492fSopenharmony_ci continue; 173d9f0492fSopenharmony_ci } 174d9f0492fSopenharmony_ci handleSelinuxLabel(&node->info, readOnly); 175d9f0492fSopenharmony_ci count++; 176d9f0492fSopenharmony_ci node = node->next; 177d9f0492fSopenharmony_ci } 178d9f0492fSopenharmony_ci ParameterNode tmpNode = {WORKSPACE_NAME_DEF_SELINUX, WORKSPACE_NAME_DEF_SELINUX, 0}; 179d9f0492fSopenharmony_ci handleSelinuxLabel(&tmpNode, readOnly); 180d9f0492fSopenharmony_ci PARAM_LOGV("Selinux get all label counts %d.", count); 181d9f0492fSopenharmony_ci return 0; 182d9f0492fSopenharmony_ci} 183d9f0492fSopenharmony_ci 184d9f0492fSopenharmony_cistatic void HandleSelinuxLabelForPermission(const ParameterNode *paramNode, int readOnly) 185d9f0492fSopenharmony_ci{ 186d9f0492fSopenharmony_ci uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE; 187d9f0492fSopenharmony_ci if (labelIndex == WORKSPACE_INDEX_BASE) { 188d9f0492fSopenharmony_ci return; 189d9f0492fSopenharmony_ci } 190d9f0492fSopenharmony_ci if (*(paramNode->paraName + strlen(paramNode->paraName) - 1) != '.') { 191d9f0492fSopenharmony_ci return; 192d9f0492fSopenharmony_ci } 193d9f0492fSopenharmony_ci // save selinux index 194d9f0492fSopenharmony_ci ParamWorkSpace *paramWorkspace = GetParamWorkSpace(); 195d9f0492fSopenharmony_ci PARAM_CHECK(paramWorkspace != NULL && paramWorkspace->workSpace != NULL, return, "Invalid workspace"); 196d9f0492fSopenharmony_ci WorkSpace *space = paramWorkspace->workSpace[WORKSPACE_INDEX_DAC]; 197d9f0492fSopenharmony_ci PARAM_CHECK(space != NULL && space->area != NULL, return, "Failed to get dac space %s", paramNode->paraName); 198d9f0492fSopenharmony_ci uint32_t index = 0; 199d9f0492fSopenharmony_ci (void)FindTrieNode(space, paramNode->paraName, strlen(paramNode->paraName), &index); 200d9f0492fSopenharmony_ci ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, index); 201d9f0492fSopenharmony_ci PARAM_CHECK(node != NULL, return, "Can not get security label for %s", paramNode->paraName); 202d9f0492fSopenharmony_ci PARAM_LOGV("HandleSelinuxLabelForPermission %s selinuxIndex [ %u %u] dac %u %s ", 203d9f0492fSopenharmony_ci paramNode->paraName, labelIndex, node->selinuxIndex, index, paramNode->paraContext); 204d9f0492fSopenharmony_ci ParamAuditData auditData = {0}; 205d9f0492fSopenharmony_ci auditData.dacData.gid = node->gid; 206d9f0492fSopenharmony_ci auditData.dacData.uid = node->uid; 207d9f0492fSopenharmony_ci auditData.dacData.mode = node->mode; 208d9f0492fSopenharmony_ci auditData.dacData.paramType = node->type; 209d9f0492fSopenharmony_ci auditData.selinuxIndex = labelIndex; 210d9f0492fSopenharmony_ci auditData.name = paramNode->paraName; 211d9f0492fSopenharmony_ci auditData.memberNum = 1; 212d9f0492fSopenharmony_ci auditData.members[0] = node->gid; 213d9f0492fSopenharmony_ci AddSecurityLabel(&auditData); 214d9f0492fSopenharmony_ci} 215d9f0492fSopenharmony_ci 216d9f0492fSopenharmony_cistatic int SelinuxGetParamSecurityLabel(const char *cmd, int readOnly) 217d9f0492fSopenharmony_ci{ 218d9f0492fSopenharmony_ci if (cmd == NULL || strcmp(cmd, "create") == 0) { // for init and other processor 219d9f0492fSopenharmony_ci return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForInit); 220d9f0492fSopenharmony_ci } 221d9f0492fSopenharmony_ci if ((strcmp(cmd, "init") == 0) && (!readOnly)) { // only for init 222d9f0492fSopenharmony_ci return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForOpen); 223d9f0492fSopenharmony_ci } 224d9f0492fSopenharmony_ci if ((strcmp(cmd, "permission") == 0) && (!readOnly)) { // only for init 225d9f0492fSopenharmony_ci return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForPermission); 226d9f0492fSopenharmony_ci } 227d9f0492fSopenharmony_ci if ((strcmp(cmd, "open") == 0) && readOnly) { // for read only 228d9f0492fSopenharmony_ci static int loadLabels = 0; 229d9f0492fSopenharmony_ci if (loadLabels) { 230d9f0492fSopenharmony_ci return 0; 231d9f0492fSopenharmony_ci } 232d9f0492fSopenharmony_ci loadLabels = 1; 233d9f0492fSopenharmony_ci return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForOpen); 234d9f0492fSopenharmony_ci } 235d9f0492fSopenharmony_ci return 0; 236d9f0492fSopenharmony_ci} 237d9f0492fSopenharmony_ci 238d9f0492fSopenharmony_cistatic int SelinuxGetParamSecurityLabelForInit(const char *path) 239d9f0492fSopenharmony_ci{ 240d9f0492fSopenharmony_ci return SelinuxGetParamSecurityLabel(path, 0); 241d9f0492fSopenharmony_ci} 242d9f0492fSopenharmony_ci 243d9f0492fSopenharmony_cistatic int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags) 244d9f0492fSopenharmony_ci{ 245d9f0492fSopenharmony_ci UNUSED(flags); 246d9f0492fSopenharmony_ci UNUSED(localLabel); 247d9f0492fSopenharmony_ci UNUSED(fileName); 248d9f0492fSopenharmony_ci return 0; 249d9f0492fSopenharmony_ci} 250d9f0492fSopenharmony_ci 251d9f0492fSopenharmony_cistatic int UpdaterCheckParamPermission(const ParamLabelIndex *labelIndex, 252d9f0492fSopenharmony_ci const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode) 253d9f0492fSopenharmony_ci{ 254d9f0492fSopenharmony_ci return DAC_RESULT_PERMISSION; 255d9f0492fSopenharmony_ci} 256d9f0492fSopenharmony_ci 257d9f0492fSopenharmony_cistatic int SelinuxGetParamSecurityLabelForOther(const char *path) 258d9f0492fSopenharmony_ci{ 259d9f0492fSopenharmony_ci return SelinuxGetParamSecurityLabel(path, 1); 260d9f0492fSopenharmony_ci} 261d9f0492fSopenharmony_ci 262d9f0492fSopenharmony_ciINIT_LOCAL_API int RegisterSecuritySelinuxOps(ParamSecurityOps *ops, int isInit) 263d9f0492fSopenharmony_ci{ 264d9f0492fSopenharmony_ci PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace"); 265d9f0492fSopenharmony_ci PARAM_CHECK(ops != NULL, return -1, "Invalid param"); 266d9f0492fSopenharmony_ci int ret = PARAM_STRCPY(ops->name, sizeof(ops->name), "selinux"); 267d9f0492fSopenharmony_ci ops->securityGetLabel = NULL; 268d9f0492fSopenharmony_ci ops->securityInitLabel = InitLocalSecurityLabel; 269d9f0492fSopenharmony_ci ops->securityCheckFilePermission = CheckFilePermission; 270d9f0492fSopenharmony_ci if (GetParamWorkSpace()->ops.updaterMode == 1) { 271d9f0492fSopenharmony_ci ops->securityCheckParamPermission = UpdaterCheckParamPermission; 272d9f0492fSopenharmony_ci } else { 273d9f0492fSopenharmony_ci#ifdef STARTUP_INIT_TEST 274d9f0492fSopenharmony_ci ops->securityCheckParamPermission = SelinuxCheckParamPermission; 275d9f0492fSopenharmony_ci#endif 276d9f0492fSopenharmony_ci } 277d9f0492fSopenharmony_ci ops->securityFreeLabel = FreeLocalSecurityLabel; 278d9f0492fSopenharmony_ci if (isInit != 0) { 279d9f0492fSopenharmony_ci ops->securityGetLabel = SelinuxGetParamSecurityLabelForInit; 280d9f0492fSopenharmony_ci } else { 281d9f0492fSopenharmony_ci ops->securityGetLabel = SelinuxGetParamSecurityLabelForOther; 282d9f0492fSopenharmony_ci } 283d9f0492fSopenharmony_ci return ret; 284d9f0492fSopenharmony_ci} 285