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
35 typedef int (*SelinuxSetParamCheck)(const char *paraName, const char *destContext, const SrcInfo *info);
36
37 #if !(defined STARTUP_INIT_TEST || defined LOCAL_TEST)
InitSelinuxOpsForInit(SelinuxSpace * selinuxSpace)38 static int InitSelinuxOpsForInit(SelinuxSpace *selinuxSpace)
39 {
40 if (selinuxSpace->selinuxHandle == NULL) {
41 const char *libname = (GetParamWorkSpace()->ops.updaterMode == 1) ? CHECKER_UPDATER_LIB : CHECKER_LIB_NAME;
42 selinuxSpace->selinuxHandle = dlopen(libname, RTLD_LAZY);
43 PARAM_CHECK(selinuxSpace->selinuxHandle != NULL,
44 return 0, "Failed to dlsym selinuxHandle, %s", dlerror());
45 }
46 void *handle = selinuxSpace->selinuxHandle;
47 if (selinuxSpace->setParamCheck == NULL) {
48 selinuxSpace->setParamCheck = (SelinuxSetParamCheck)dlsym(handle, "SetParamCheck");
49 PARAM_CHECK(selinuxSpace->setParamCheck != NULL, return -1, "Failed to dlsym setParamCheck %s", dlerror());
50 }
51 if (selinuxSpace->getParamList == NULL) {
52 selinuxSpace->getParamList = (ParamContextsList *(*)()) dlsym(handle, "GetParamList");
53 PARAM_CHECK(selinuxSpace->getParamList != NULL, return -1, "Failed to dlsym getParamList %s", dlerror());
54 }
55 if (selinuxSpace->getParamLabel == NULL) {
56 selinuxSpace->getParamLabel = (const char *(*)(const char *))dlsym(handle, "GetParamLabel");
57 PARAM_CHECK(selinuxSpace->getParamLabel != NULL, return -1, "Failed to dlsym getParamLabel %s", dlerror());
58 }
59 if (selinuxSpace->initParamSelinux == NULL) {
60 selinuxSpace->initParamSelinux = (int (*)(int))dlsym(handle, "InitParamSelinux");
61 PARAM_CHECK(selinuxSpace->initParamSelinux != NULL, return -1, "Failed to dlsym initParamSelinux ");
62 }
63 if (selinuxSpace->getParamLabelIndex == NULL) {
64 selinuxSpace->getParamLabelIndex = (int (*)(const char *))dlsym(handle, "GetParamLabelIndex");
65 PARAM_CHECK(selinuxSpace->getParamLabelIndex != NULL, return -1, "Failed to dlsym getParamLabelIndex ");
66 }
67 if (selinuxSpace->setSelinuxLogCallback == NULL) {
68 selinuxSpace->setSelinuxLogCallback = (void (*)())dlsym(handle, "SetInitSelinuxLog");
69 }
70 if (selinuxSpace->destroyParamList == NULL) {
71 selinuxSpace->destroyParamList =
72 (void (*)(ParamContextsList **))dlsym(handle, "DestroyParamList");
73 PARAM_CHECK(selinuxSpace->destroyParamList != NULL,
74 return -1, "Failed to dlsym destroyParamList %s", dlerror());
75 }
76
77 // init and open avc log
78 int ret = selinuxSpace->initParamSelinux(1);
79 if (selinuxSpace->setSelinuxLogCallback != NULL) {
80 selinuxSpace->setSelinuxLogCallback();
81 }
82 return ret;
83 }
84 #endif
85
InitLocalSecurityLabel(ParamSecurityLabel * security,int isInit)86 static int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit)
87 {
88 PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace");
89 UNUSED(isInit);
90 PARAM_CHECK(security != NULL, return -1, "Invalid security");
91 security->cred.pid = getpid();
92 security->cred.uid = geteuid();
93 security->cred.gid = getegid();
94 security->flags[PARAM_SECURITY_SELINUX] = 0;
95 PARAM_LOGV("InitLocalSecurityLabel");
96 #if !(defined STARTUP_INIT_TEST || defined LOCAL_TEST)
97 if ((bool)isInit) {
98 int ret = InitSelinuxOpsForInit(&GetParamWorkSpace()->selinuxSpace);
99 PARAM_CHECK(ret == 0, return -1, "Failed to init selinux ops");
100 } else {
101 SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
102 selinuxSpace->initParamSelinux = InitParamSelinux;
103 selinuxSpace->getParamList = GetParamList;
104 selinuxSpace->getParamLabel = GetParamLabel;
105 selinuxSpace->destroyParamList = DestroyParamList;
106 selinuxSpace->getParamLabelIndex = GetParamLabelIndex;
107 // init
108 selinuxSpace->initParamSelinux(isInit);
109 }
110 #endif
111 PARAM_LOGV("Load selinux lib success.");
112 return 0;
113 }
114
FreeLocalSecurityLabel(ParamSecurityLabel * srcLabel)115 static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
116 {
117 return 0;
118 }
119
SetSelinuxFileCon(const char * name,const char * context)120 static void SetSelinuxFileCon(const char *name, const char *context)
121 {
122 PARAM_CHECK(GetParamWorkSpace() != NULL && GetParamWorkSpace()->ops.setfilecon != NULL,
123 return, "Invalid workspace or setfilecon");
124 static char buffer[FILENAME_LEN_MAX] = {0};
125 int len = PARAM_SPRINTF(buffer, sizeof(buffer), "%s/%s", PARAM_STORAGE_PATH, context);
126 if (len > 0) {
127 buffer[len] = '\0';
128 PARAM_LOGV("setfilecon name %s path: %s %s ", name, context, buffer);
129 if (GetParamWorkSpace()->ops.setfilecon(buffer, context) < 0) {
130 PARAM_LOGE("Failed to setfilecon %s ", context);
131 }
132 }
133 }
134
HandleSelinuxLabelForOpen(const ParameterNode * paramNode,int readOnly)135 static void HandleSelinuxLabelForOpen(const ParameterNode *paramNode, int readOnly)
136 {
137 uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE;
138 int ret = OpenWorkSpace(labelIndex, readOnly);
139 if (ret != 0) {
140 PARAM_LOGE("Forbid to add selinux workspace %s %s", paramNode->paraName, paramNode->paraContext);
141 return;
142 }
143 if (!readOnly) {
144 // set selinux label
145 SetSelinuxFileCon(paramNode->paraName, paramNode->paraContext);
146 }
147 }
148
HandleSelinuxLabelForInit(const ParameterNode * paramNode,int readOnly)149 static void HandleSelinuxLabelForInit(const ParameterNode *paramNode, int readOnly)
150 {
151 uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE;
152 int ret = AddWorkSpace(paramNode->paraContext, labelIndex, readOnly, 0);
153 PARAM_CHECK(ret == 0, return, "Not enough memory for %s", paramNode->paraContext);
154
155 ParamWorkSpace *paramSpace = GetParamWorkSpace();
156 PARAM_CHECK(paramSpace != NULL, return, "Invalid workspace");
157 if (paramSpace->maxLabelIndex < labelIndex) {
158 paramSpace->maxLabelIndex = labelIndex;
159 }
160 }
161
SelinuxGetAllLabel(int readOnly,void (* handleSelinuxLabel)(const ParameterNode * paramNode,int readOnly))162 int SelinuxGetAllLabel(int readOnly,
163 void (*handleSelinuxLabel)(const ParameterNode *paramNode, int readOnly))
164 {
165 SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
166 PARAM_CHECK(selinuxSpace->getParamList != NULL, return DAC_RESULT_FORBIDED, "Invalid getParamList");
167 ParamContextsList *node = selinuxSpace->getParamList();
168 int count = 0;
169 while (node != NULL) {
170 PARAM_LOGV("SelinuxGetAllLabel index %d name %s content %s",
171 node->info.index, node->info.paraName, node->info.paraContext);
172 if (node->info.paraContext == NULL || node->info.paraName == NULL) {
173 node = node->next;
174 continue;
175 }
176 handleSelinuxLabel(&node->info, readOnly);
177 count++;
178 node = node->next;
179 }
180 ParameterNode tmpNode = {WORKSPACE_NAME_DEF_SELINUX, WORKSPACE_NAME_DEF_SELINUX, 0};
181 handleSelinuxLabel(&tmpNode, readOnly);
182 PARAM_LOGV("Selinux get all label counts %d.", count);
183 return 0;
184 }
185
HandleSelinuxLabelForPermission(const ParameterNode * paramNode,int readOnly)186 static void HandleSelinuxLabelForPermission(const ParameterNode *paramNode, int readOnly)
187 {
188 uint32_t labelIndex = paramNode->index + WORKSPACE_INDEX_BASE;
189 if (labelIndex == WORKSPACE_INDEX_BASE) {
190 return;
191 }
192 if (*(paramNode->paraName + strlen(paramNode->paraName) - 1) != '.') {
193 return;
194 }
195 // save selinux index
196 ParamWorkSpace *paramWorkspace = GetParamWorkSpace();
197 PARAM_CHECK(paramWorkspace != NULL && paramWorkspace->workSpace != NULL, return, "Invalid workspace");
198 WorkSpace *space = paramWorkspace->workSpace[WORKSPACE_INDEX_DAC];
199 PARAM_CHECK(space != NULL && space->area != NULL, return, "Failed to get dac space %s", paramNode->paraName);
200 uint32_t index = 0;
201 (void)FindTrieNode(space, paramNode->paraName, strlen(paramNode->paraName), &index);
202 ParamSecurityNode *node = (ParamSecurityNode *)GetTrieNode(space, index);
203 PARAM_CHECK(node != NULL, return, "Can not get security label for %s", paramNode->paraName);
204 PARAM_LOGV("HandleSelinuxLabelForPermission %s selinuxIndex [ %u %u] dac %u %s ",
205 paramNode->paraName, labelIndex, node->selinuxIndex, index, paramNode->paraContext);
206 ParamAuditData auditData = {0};
207 auditData.dacData.gid = node->gid;
208 auditData.dacData.uid = node->uid;
209 auditData.dacData.mode = node->mode;
210 auditData.dacData.paramType = node->type;
211 auditData.selinuxIndex = labelIndex;
212 auditData.name = paramNode->paraName;
213 auditData.memberNum = 1;
214 auditData.members[0] = node->gid;
215 AddSecurityLabel(&auditData);
216 }
217
SelinuxGetParamSecurityLabel(const char * cmd,int readOnly)218 static int SelinuxGetParamSecurityLabel(const char *cmd, int readOnly)
219 {
220 if (cmd == NULL || strcmp(cmd, "create") == 0) { // for init and other processor
221 return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForInit);
222 }
223 if ((strcmp(cmd, "init") == 0) && (!readOnly)) { // only for init
224 return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForOpen);
225 }
226 if ((strcmp(cmd, "permission") == 0) && (!readOnly)) { // only for init
227 return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForPermission);
228 }
229 if ((strcmp(cmd, "open") == 0) && readOnly) { // for read only
230 static int loadLabels = 0;
231 if (loadLabels) {
232 return 0;
233 }
234 loadLabels = 1;
235 return SelinuxGetAllLabel(readOnly, HandleSelinuxLabelForOpen);
236 }
237 return 0;
238 }
239
SelinuxGetParamSecurityLabelForInit(const char * path)240 static int SelinuxGetParamSecurityLabelForInit(const char *path)
241 {
242 return SelinuxGetParamSecurityLabel(path, 0);
243 }
244
CheckFilePermission(const ParamSecurityLabel * localLabel,const char * fileName,int flags)245 static int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags)
246 {
247 UNUSED(flags);
248 UNUSED(localLabel);
249 UNUSED(fileName);
250 return 0;
251 }
252
UpdaterCheckParamPermission(const ParamLabelIndex * labelIndex,const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)253 static int UpdaterCheckParamPermission(const ParamLabelIndex *labelIndex,
254 const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
255 {
256 return DAC_RESULT_PERMISSION;
257 }
258
SelinuxGetParamSecurityLabelForOther(const char * path)259 static int SelinuxGetParamSecurityLabelForOther(const char *path)
260 {
261 return SelinuxGetParamSecurityLabel(path, 1);
262 }
263
RegisterSecuritySelinuxOps(ParamSecurityOps * ops,int isInit)264 INIT_LOCAL_API int RegisterSecuritySelinuxOps(ParamSecurityOps *ops, int isInit)
265 {
266 PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace");
267 PARAM_CHECK(ops != NULL, return -1, "Invalid param");
268 int ret = PARAM_STRCPY(ops->name, sizeof(ops->name), "selinux");
269 ops->securityGetLabel = NULL;
270 ops->securityInitLabel = InitLocalSecurityLabel;
271 ops->securityCheckFilePermission = CheckFilePermission;
272 if (GetParamWorkSpace()->ops.updaterMode == 1) {
273 ops->securityCheckParamPermission = UpdaterCheckParamPermission;
274 } else {
275 #ifdef STARTUP_INIT_TEST
276 ops->securityCheckParamPermission = SelinuxCheckParamPermission;
277 #endif
278 }
279 ops->securityFreeLabel = FreeLocalSecurityLabel;
280 if (isInit != 0) {
281 ops->securityGetLabel = SelinuxGetParamSecurityLabelForInit;
282 } else {
283 ops->securityGetLabel = SelinuxGetParamSecurityLabelForOther;
284 }
285 return ret;
286 }
287