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