• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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