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 #ifdef __aarch64__
29 #define CHECKER_LIB_NAME "/system/lib64/libparaperm_checker.z.so"
30 #define CHECKER_UPDATER_LIB_NAME "/lib64/libparaperm_checker.z.so"
31 #else
32 #define CHECKER_LIB_NAME "/system/lib/libparaperm_checker.z.so"
33 #define CHECKER_UPDATER_LIB_NAME "/lib/libparaperm_checker.z.so"
34 #endif
35 typedef int (*SelinuxSetParamCheck)(const char *paraName, const char *destContext, const SrcInfo *info);
36
InitSelinuxOpsForInit(SelinuxSpace * selinuxSpace)37 static int InitSelinuxOpsForInit(SelinuxSpace *selinuxSpace)
38 {
39 if (selinuxSpace->selinuxHandle == NULL) {
40 const char *libname = (GetParamWorkSpace()->ops.updaterMode == 1) ? CHECKER_UPDATER_LIB_NAME : 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 (*)())dlsym(handle, "InitParamSelinux");
60 PARAM_CHECK(selinuxSpace->initParamSelinux != NULL, return -1, "Failed to dlsym initParamSelinux ");
61 }
62 if (selinuxSpace->readParamCheck == NULL) {
63 selinuxSpace->readParamCheck = (int (*)(const char *))dlsym(handle, "ReadParamCheck");
64 }
65 if (selinuxSpace->setSelinuxLogCallback == NULL) {
66 selinuxSpace->setSelinuxLogCallback = (void (*)())dlsym(handle, "SetInitSelinuxLog");
67 }
68 if (selinuxSpace->destroyParamList == NULL) {
69 selinuxSpace->destroyParamList =
70 (void (*)(ParamContextsList **))dlsym(handle, "DestroyParamList");
71 PARAM_CHECK(selinuxSpace->destroyParamList != NULL,
72 return -1, "Failed to dlsym destroyParamList %s", dlerror());
73 }
74
75 // init and open avc log
76 int ret = selinuxSpace->initParamSelinux();
77 if (selinuxSpace->setSelinuxLogCallback != NULL) {
78 selinuxSpace->setSelinuxLogCallback();
79 }
80 return ret;
81 }
82
InitLocalSecurityLabel(ParamSecurityLabel * security,int isInit)83 static int InitLocalSecurityLabel(ParamSecurityLabel *security, int isInit)
84 {
85 PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace");
86 UNUSED(isInit);
87 PARAM_CHECK(security != NULL, return -1, "Invalid security");
88 security->cred.pid = getpid();
89 security->cred.uid = geteuid();
90 security->cred.gid = getegid();
91 security->flags[PARAM_SECURITY_SELINUX] = 0;
92 PARAM_LOGV("InitLocalSecurityLabel");
93 #if !(defined STARTUP_INIT_TEST || defined LOCAL_TEST)
94 if ((bool)isInit) {
95 int ret = InitSelinuxOpsForInit(&GetParamWorkSpace()->selinuxSpace);
96 PARAM_CHECK(ret == 0, return -1, "Failed to init selinux ops");
97 } else {
98 SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
99 selinuxSpace->initParamSelinux = InitParamSelinux;
100 selinuxSpace->getParamList = GetParamList;
101 selinuxSpace->getParamLabel = GetParamLabel;
102 selinuxSpace->destroyParamList = DestroyParamList;
103 // init
104 selinuxSpace->initParamSelinux();
105 }
106 #endif
107 PARAM_LOGI("Load selinux lib success.");
108 return 0;
109 }
110
FreeLocalSecurityLabel(ParamSecurityLabel * srcLabel)111 static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
112 {
113 return 0;
114 }
115
SetSelinuxFileCon(const char * name,const char * context)116 static void SetSelinuxFileCon(const char *name, const char *context)
117 {
118 PARAM_CHECK(GetParamWorkSpace() != NULL && GetParamWorkSpace()->ops.setfilecon != NULL,
119 return, "Invalid workspace or setfilecon");
120 static char buffer[FILENAME_LEN_MAX] = {0};
121 int len = ParamSprintf(buffer, sizeof(buffer), "%s/%s", PARAM_STORAGE_PATH, context);
122 if (len > 0) {
123 buffer[len] = '\0';
124 PARAM_LOGV("setfilecon name %s path: %s %s ", name, context, buffer);
125 if (GetParamWorkSpace()->ops.setfilecon(buffer, context) < 0) {
126 PARAM_LOGE("Failed to setfilecon %s ", context);
127 }
128 }
129 }
130
GetWorkSpaceSize(const char * content)131 static uint32_t GetWorkSpaceSize(const char *content)
132 {
133 if (strcmp(content, WORKSPACE_NAME_DEF_SELINUX) == 0) {
134 return PARAM_WORKSPACE_MAX;
135 }
136 char name[PARAM_NAME_LEN_MAX] = {0};
137 size_t len = strlen(content);
138 int index = 0;
139 for (size_t i = strlen("u:object_r:"); i < len; i++) {
140 if (*(content + i) == ':') {
141 break;
142 }
143 name[index++] = *(content + i);
144 }
145 if (index == 0) {
146 #ifdef STARTUP_INIT_TEST
147 return PARAM_WORKSPACE_DEF;
148 #else
149 return PARAM_WORKSPACE_MIN;
150 #endif
151 }
152 ParamNode *node = GetParamNode(WORKSPACE_NAME_DAC, name);
153 if (node == NULL) {
154 #ifdef STARTUP_INIT_TEST
155 return PARAM_WORKSPACE_DEF;
156 #else
157 return PARAM_WORKSPACE_MIN;
158 #endif
159 }
160 int ret = ParamMemcpy(name, sizeof(name) - 1, node->data + node->keyLength + 1, node->valueLength);
161 if (ret == 0) {
162 name[node->valueLength] = '\0';
163 errno = 0;
164 uint32_t value = (uint32_t)strtoul(name, NULL, DECIMAL_BASE);
165 return (errno != 0) ? PARAM_WORKSPACE_MIN : value;
166 }
167 return PARAM_WORKSPACE_MIN;
168 }
169
SelinuxGetAllLabel(int readOnly)170 static int SelinuxGetAllLabel(int readOnly)
171 {
172 SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
173 PARAM_CHECK(selinuxSpace->getParamList != NULL, return DAC_RESULT_FORBIDED, "Invalid getParamList");
174 ParamContextsList *head = selinuxSpace->getParamList();
175 ParamContextsList *node = head;
176
177 int count = 0;
178 while (node != NULL) {
179 PARAM_LOGV("SelinuxGetAllLabel name %s content %s", node->info.paraName, node->info.paraContext);
180 if (node->info.paraContext == NULL || node->info.paraName == NULL) {
181 node = node->next;
182 continue;
183 }
184 int ret = AddWorkSpace(node->info.paraContext, readOnly, GetWorkSpaceSize(node->info.paraContext));
185 if (ret != 0) {
186 PARAM_LOGE("Forbid to add selinux workspace %s %s", node->info.paraName, node->info.paraContext);
187 node = node->next;
188 continue;
189 }
190 count++;
191 if (readOnly != 0) {
192 node = node->next;
193 continue;
194 }
195 // set selinux label
196 SetSelinuxFileCon(node->info.paraName, node->info.paraContext);
197 node = node->next;
198 }
199
200 int ret = AddWorkSpace(WORKSPACE_NAME_DEF_SELINUX, readOnly, GetWorkSpaceSize(WORKSPACE_NAME_DEF_SELINUX));
201 PARAM_CHECK(ret == 0, return -1,
202 "Failed to add selinux workspace %s", WORKSPACE_NAME_DEF_SELINUX);
203 if (readOnly == 0) {
204 SetSelinuxFileCon(WORKSPACE_NAME_DEF_SELINUX, WORKSPACE_NAME_DEF_SELINUX);
205 }
206 PARAM_LOGV("Selinux get all label counts %d.", count);
207 return 0;
208 }
209
SelinuxGetParamSecurityLabel(const char * path)210 static int SelinuxGetParamSecurityLabel(const char *path)
211 {
212 UNUSED(path);
213 return SelinuxGetAllLabel(0);
214 }
215
CheckFilePermission(const ParamSecurityLabel * localLabel,const char * fileName,int flags)216 static int CheckFilePermission(const ParamSecurityLabel *localLabel, const char *fileName, int flags)
217 {
218 UNUSED(flags);
219 PARAM_CHECK(localLabel != NULL && fileName != NULL, return -1, "Invalid param");
220 return 0;
221 }
222
GetSelinuxContent(const char * name)223 static const char *GetSelinuxContent(const char *name)
224 {
225 SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
226 if (selinuxSpace->getParamLabel != NULL) {
227 return selinuxSpace->getParamLabel(name);
228 } else {
229 PARAM_LOGE("Can not init selinux");
230 return WORKSPACE_NAME_DEF_SELINUX;
231 }
232 }
233
CheckContentPermission(const char * name,const char * label)234 static int CheckContentPermission(const char *name, const char *label)
235 {
236 PARAM_CHECK(name != NULL && label != NULL, return DAC_RESULT_FORBIDED, "The label is null");
237 int ret = DAC_RESULT_FORBIDED;
238 char buffer[FILENAME_LEN_MAX] = {0};
239 int size = ParamSprintf(buffer, sizeof(buffer), "%s/%s", PARAM_STORAGE_PATH, label);
240 PARAM_CHECK(size > 0, return -1, "Failed to format file name %s", label);
241 buffer[size] = '\0';
242 if (access(buffer, R_OK) == 0) {
243 ret = AddWorkSpace(label, 1, PARAM_WORKSPACE_MAX);
244 }
245 if (ret != 0) {
246 PARAM_LOGE("SelinuxReadParamCheck name %s label %s ", name, label);
247 return DAC_RESULT_FORBIDED;
248 }
249 return DAC_RESULT_PERMISSION;
250 }
251
SelinuxReadParamCheck(const char * name)252 static int SelinuxReadParamCheck(const char *name)
253 {
254 const char *label = GetSelinuxContent(name);
255 if (label == NULL) {
256 return CheckContentPermission(name, WORKSPACE_NAME_DEF_SELINUX);
257 }
258 return CheckContentPermission(name, label);
259 }
260
SelinuxCheckParamPermission(const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)261 static int SelinuxCheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
262 {
263 SelinuxSpace *selinuxSpace = &GetParamWorkSpace()->selinuxSpace;
264 int ret = DAC_RESULT_FORBIDED;
265 // check
266 SrcInfo info;
267 info.uc.pid = srcLabel->cred.pid;
268 info.uc.uid = srcLabel->cred.uid;
269 info.uc.gid = srcLabel->cred.gid;
270 info.sockFd = srcLabel->sockFd;
271 if (mode == DAC_WRITE) {
272 PARAM_CHECK(selinuxSpace->setParamCheck != NULL, return ret, "Invalid setParamCheck");
273 const char *context = GetSelinuxContent(name);
274 ret = selinuxSpace->setParamCheck(name, context, &info);
275 } else {
276 #ifndef STARTUP_INIT_TEST
277 ret = SelinuxReadParamCheck(name);
278 #else
279 ret = selinuxSpace->readParamCheck(name);
280 #endif
281 }
282 if (ret != 0) {
283 PARAM_LOGW("Selinux check name %s in %s info [%d %d %d] result %d",
284 name, GetSelinuxContent(name), info.uc.pid, info.uc.uid, info.uc.gid, ret);
285 ret = DAC_RESULT_FORBIDED;
286 } else {
287 ret = DAC_RESULT_PERMISSION;
288 }
289 return ret;
290 }
291
UpdaterCheckParamPermission(const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)292 static int UpdaterCheckParamPermission(const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
293 {
294 return DAC_RESULT_PERMISSION;
295 }
296
OpenPermissionWorkSpace(const char * path)297 static int OpenPermissionWorkSpace(const char *path)
298 {
299 static int loadLabels = 0;
300 UNUSED(path);
301 int ret = 0;
302 if (loadLabels == 0) {
303 // open workspace by readonly
304 ret = SelinuxGetAllLabel(1);
305 }
306 loadLabels = 1;
307 return ret;
308 }
309
RegisterSecuritySelinuxOps(ParamSecurityOps * ops,int isInit)310 INIT_LOCAL_API int RegisterSecuritySelinuxOps(ParamSecurityOps *ops, int isInit)
311 {
312 PARAM_CHECK(GetParamWorkSpace() != NULL, return -1, "Invalid workspace");
313 PARAM_CHECK(ops != NULL, return -1, "Invalid param");
314 int ret = ParamStrCpy(ops->name, sizeof(ops->name), "selinux");
315 ops->securityGetLabel = NULL;
316 ops->securityInitLabel = InitLocalSecurityLabel;
317 ops->securityCheckFilePermission = CheckFilePermission;
318 if (GetParamWorkSpace()->ops.updaterMode == 1) {
319 ops->securityCheckParamPermission = UpdaterCheckParamPermission;
320 } else {
321 ops->securityCheckParamPermission = SelinuxCheckParamPermission;
322 }
323 ops->securityFreeLabel = FreeLocalSecurityLabel;
324 if (isInit != 0) {
325 ops->securityGetLabel = SelinuxGetParamSecurityLabel;
326 } else {
327 ops->securityGetLabel = OpenPermissionWorkSpace;
328 }
329 return ret;
330 }
331