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 
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 : 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 
InitLocalSecurityLabel(ParamSecurityLabel * security,int isInit)84 static 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 
FreeLocalSecurityLabel(ParamSecurityLabel * srcLabel)113 static int FreeLocalSecurityLabel(ParamSecurityLabel *srcLabel)
114 {
115     return 0;
116 }
117 
SetSelinuxFileCon(const char * name,const char * context)118 static 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 
HandleSelinuxLabelForOpen(const ParameterNode * paramNode,int readOnly)133 static 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 
HandleSelinuxLabelForInit(const ParameterNode * paramNode,int readOnly)147 static 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 
SelinuxGetAllLabel(int readOnly,void (* handleSelinuxLabel)(const ParameterNode * paramNode,int readOnly))160 int 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 
HandleSelinuxLabelForPermission(const ParameterNode * paramNode,int readOnly)184 static 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 
SelinuxGetParamSecurityLabel(const char * cmd,int readOnly)216 static 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 
SelinuxGetParamSecurityLabelForInit(const char * path)238 static int SelinuxGetParamSecurityLabelForInit(const char *path)
239 {
240     return SelinuxGetParamSecurityLabel(path, 0);
241 }
242 
CheckFilePermission(const ParamSecurityLabel * localLabel,const char * fileName,int flags)243 static 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 
UpdaterCheckParamPermission(const ParamLabelIndex * labelIndex,const ParamSecurityLabel * srcLabel,const char * name,uint32_t mode)251 static int UpdaterCheckParamPermission(const ParamLabelIndex *labelIndex,
252     const ParamSecurityLabel *srcLabel, const char *name, uint32_t mode)
253 {
254     return DAC_RESULT_PERMISSION;
255 }
256 
SelinuxGetParamSecurityLabelForOther(const char * path)257 static int SelinuxGetParamSecurityLabelForOther(const char *path)
258 {
259     return SelinuxGetParamSecurityLabel(path, 1);
260 }
261 
RegisterSecuritySelinuxOps(ParamSecurityOps * ops,int isInit)262 INIT_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