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