• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "contexts_trie.h"
16 #include <ctype.h>
17 #include <stdbool.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include "selinux_error.h"
21 #include "selinux_share_mem.h"
22 
23 static const char DEFAULT_CONTEXT[] = "u:object_r:default_param:s0";
24 static const int32_t DEFAULT_CONTEXT_INDEX = 0;
25 static const int32_t INIT_INDEX = 1;
26 static const size_t CONTEXTS_LENGTH_MIN = 16; // sizeof("x u:object_r:x:s0")
27 static const size_t CONTEXTS_LENGTH_MAX = 1024;
28 static const uint32_t SELINUX_PARAM_SPACE = 1024 * 80;
29 static const uint32_t MAX_LEN = 255;
30 static const char SYSTEM_PARAMETER_CONTEXTS[] = "/system/etc/selinux/targeted/contexts/parameter_contexts";
31 static const char VENDOR_PARAMETER_CONTEXTS[] = "/vendor/etc/selinux/targeted/contexts/parameter_contexts";
32 
GetGroupNode(ParamContextsTrie * root,const char * name,uint32_t len)33 static ParamHashNode *GetGroupNode(ParamContextsTrie *root, const char *name, uint32_t len)
34 {
35     HashNode *node = HashMapGet(root->handle, name, len);
36     if (node == NULL) {
37         return NULL;
38     }
39     return HASHMAP_ENTRY(node, ParamHashNode, hashNode);
40 }
41 
AddGroupNode(ParamContextsTrie * root,const char * name,ParamContextsTrie * child)42 static ParamHashNode *AddGroupNode(ParamContextsTrie *root, const char *name, ParamContextsTrie *child)
43 {
44     uint32_t nameLen = (uint32_t)strlen(name);
45     ParamHashNode *groupNode = GetGroupNode(root, name, nameLen);
46     if (groupNode != NULL) {
47         return groupNode;
48     }
49 
50     groupNode = (ParamHashNode *)calloc(1, sizeof(ParamHashNode));
51     if (groupNode == NULL) {
52         return NULL;
53     }
54     groupNode->nameLen = nameLen;
55     groupNode->name = (char *)calloc(1, nameLen + 1);
56     if (groupNode->name == NULL) {
57         free(groupNode);
58         return NULL;
59     }
60     memcpy(groupNode->name, name, nameLen + 1);
61     groupNode->childPtr = child;
62 
63     HashMapAdd(root->handle, &groupNode->hashNode);
64     return groupNode;
65 }
66 
ReleaseParamContextsTrieNode(ParamContextsTrie ** node)67 static void ReleaseParamContextsTrieNode(ParamContextsTrie **node)
68 {
69     if (*node == NULL) {
70         return;
71     }
72     if ((*node)->handle != NULL) {
73         HashMapDestroy((*node)->handle);
74     }
75     free(*node);
76     *node = NULL;
77 }
78 
InsertElementToTrie(ParamContextsTrie * root,const char * element,ParamContextsTrie ** child)79 static bool InsertElementToTrie(ParamContextsTrie *root, const char *element, ParamContextsTrie **child)
80 {
81     uint32_t nameLen = (uint32_t)strlen(element);
82     ParamHashNode *childNode = GetGroupNode(root, element, nameLen);
83     if (childNode != NULL) {
84         *child = childNode->childPtr;
85         return true;
86     }
87     ParamContextsTrie *childPtr = (ParamContextsTrie *)calloc(1, sizeof(ParamContextsTrie));
88     if (childPtr == NULL) {
89         return false;
90     }
91     childPtr->prefixLabel = DEFAULT_CONTEXT;
92     childPtr->matchLabel = DEFAULT_CONTEXT;
93     childPtr->labeled = UNLABELED;
94     childPtr->index = DEFAULT_CONTEXT_INDEX;
95     if (HashMapCreate(&childPtr->handle) != 0) {
96         ReleaseParamContextsTrieNode(&childPtr);
97         return false;
98     }
99     if (AddGroupNode(root, element, childPtr) == NULL) {
100         ReleaseParamContextsTrieNode(&childPtr);
101         return false;
102     }
103     *child = childPtr;
104     return true;
105 }
106 
InsertParamToTrie(ParamContextsTrie * root,const char * paramPrefix,const char * contexts,int index)107 static bool InsertParamToTrie(ParamContextsTrie *root, const char *paramPrefix, const char *contexts, int index)
108 {
109     if (root == NULL || paramPrefix == NULL || contexts == NULL) {
110         return false;
111     }
112     char *tmpPrefix = strdup(paramPrefix);
113     if (tmpPrefix == NULL) {
114         return false;
115     }
116     char *rest = NULL;
117     char *element = strtok_r(tmpPrefix, ".", &rest);
118     while (element != NULL) {
119         ParamContextsTrie *child = NULL;
120         if (!InsertElementToTrie(root, element, &child)) {
121             free(tmpPrefix);
122             return false;
123         }
124         root = child;
125         element = strtok_r(NULL, ".", &rest);
126     }
127     if (paramPrefix[strlen(paramPrefix) - 1] == '.') {
128         root->prefixLabel = contexts;
129         root->labeled = PREFIX_LABELED;
130     } else {
131         root->matchLabel = contexts;
132         root->labeled = MATCH_LABELED;
133     }
134     root->index = index;
135     free(tmpPrefix);
136     return true;
137 }
138 
SearchFromParamTrie(ParamContextsTrie * root,const char * paraName)139 const char *SearchFromParamTrie(ParamContextsTrie *root, const char *paraName)
140 {
141     const char *updateCurLabel = DEFAULT_CONTEXT;
142     const char *tmpName = paraName;
143     ParamHashNode *childNode = NULL;
144 
145     const char *bar = strchr(tmpName, '.');
146     while (bar != NULL) {
147         childNode = GetGroupNode(root, tmpName, bar - tmpName);
148         if (childNode == NULL) {
149             goto nomatch;
150         }
151         if (root->labeled == PREFIX_LABELED) {
152             updateCurLabel = root->prefixLabel;
153         }
154 
155         root = childNode->childPtr;
156         tmpName = bar + 1;
157         bar = strchr(tmpName, '.');
158     }
159 
160     childNode = GetGroupNode(root, tmpName, strlen(tmpName));
161     if (childNode != NULL) {
162         ParamContextsTrie *match = childNode->childPtr;
163         if (match->labeled == MATCH_LABELED) {
164             return match->matchLabel;
165         }
166     }
167 
168 nomatch:
169     if (root->labeled == PREFIX_LABELED) {
170         return root->prefixLabel;
171     }
172     return updateCurLabel;
173 }
174 
GetLabelIndex(ParamContextsTrie * root,const char * paraName)175 int GetLabelIndex(ParamContextsTrie *root, const char *paraName)
176 {
177     int updateCurIndex = DEFAULT_CONTEXT_INDEX;
178     const char *tmpName = paraName;
179     ParamHashNode *childNode = NULL;
180 
181     const char *bar = strchr(tmpName, '.');
182     while (bar != NULL) {
183         childNode = GetGroupNode(root, tmpName, bar - tmpName);
184         if (childNode == NULL) {
185             goto nomatch;
186         }
187         if (root->labeled == PREFIX_LABELED) {
188             updateCurIndex = root->index;
189         }
190 
191         root = childNode->childPtr;
192         tmpName = bar + 1;
193         bar = strchr(tmpName, '.');
194     }
195 
196     childNode = GetGroupNode(root, tmpName, strlen(tmpName));
197     if (childNode != NULL) {
198         ParamContextsTrie *match = childNode->childPtr;
199         if (match->labeled == MATCH_LABELED) {
200             return match->index;
201         }
202     }
203 
204 nomatch:
205     if (root->labeled == PREFIX_LABELED) {
206         return root->index;
207     }
208     return updateCurIndex;
209 }
210 
CouldSkip(const char * line)211 static bool CouldSkip(const char *line)
212 {
213     size_t len = strlen(line);
214     if (len < CONTEXTS_LENGTH_MIN || len > CONTEXTS_LENGTH_MAX) {
215         return true;
216     }
217     int i = 0;
218     while (isspace(line[i])) {
219         i++;
220     }
221     if (line[i] == '#') {
222         return true;
223     }
224     return false;
225 }
226 
InsertContextsList(ParamContextsList ** head,const char * param,const char * context,int index)227 static bool InsertContextsList(ParamContextsList **head, const char *param, const char *context, int index)
228 {
229     if (head == NULL || param == NULL || context == NULL) {
230         return false;
231     }
232     ParamContextsList *node = (ParamContextsList *)calloc(1, sizeof(ParamContextsList));
233     if (node == NULL) {
234         return false;
235     }
236 
237     node->info.paraName = param;
238     node->info.paraContext = context;
239     node->next = NULL;
240     node->info.index = index;
241     (*head)->next = node;
242     *head = (*head)->next;
243     return true;
244 }
245 
FindContextFromList(const char * context,ParamContextsList * listHead)246 static int FindContextFromList(const char *context, ParamContextsList *listHead)
247 {
248     if ((context == NULL) || (listHead == NULL)) {
249         return DEFAULT_CONTEXT_INDEX;
250     }
251     ParamContextsList *tmpHead = listHead;
252     while (tmpHead != NULL) {
253         if (strcmp(tmpHead->info.paraContext, context) == 0) {
254             return tmpHead->info.index;
255         }
256         tmpHead = tmpHead->next;
257     }
258     return DEFAULT_CONTEXT_INDEX;
259 }
260 
ReadParamFromSharedMemInit(ParamContextsTrie ** root,ParamContextsList ** listPtr,SharedMem ** memPtr)261 static bool ReadParamFromSharedMemInit(ParamContextsTrie **root, ParamContextsList **listPtr, SharedMem **memPtr)
262 {
263     SharedMem *tmpMemPtr = (SharedMem *)InitSharedMem("/dev/__parameters__/param_selinux", SELINUX_PARAM_SPACE, true);
264     if (tmpMemPtr == NULL) {
265         return false;
266     }
267     SharedMem *memHead = tmpMemPtr;
268     ParamContextsTrie *tmpRoot = (ParamContextsTrie *)calloc(1, sizeof(ParamContextsTrie));
269     if (tmpRoot == NULL) {
270         UnmapSharedMem((char *)memHead, SELINUX_PARAM_SPACE);
271         return false;
272     }
273     tmpRoot->prefixLabel = DEFAULT_CONTEXT;
274     tmpRoot->matchLabel = DEFAULT_CONTEXT;
275     tmpRoot->index = DEFAULT_CONTEXT_INDEX;
276     if (HashMapCreate(&tmpRoot->handle) != 0) {
277         ReleaseParamContextsTrieNode(&tmpRoot);
278         UnmapSharedMem((char *)memHead, SELINUX_PARAM_SPACE);
279         return false;
280     }
281     ParamContextsList *tmpListPtr = (ParamContextsList *)calloc(1, sizeof(ParamContextsList));
282     if (tmpListPtr == NULL) {
283         ReleaseParamContextsTrieNode(&tmpRoot);
284         UnmapSharedMem((char *)memHead, SELINUX_PARAM_SPACE);
285         return false;
286     }
287     *root = tmpRoot;
288     *listPtr = tmpListPtr;
289     *memPtr = memHead;
290     return true;
291 }
292 
ReadParamFromSharedMem(ParamContextsTrie ** trieRoot,ParamContextsList ** listHead)293 bool ReadParamFromSharedMem(ParamContextsTrie **trieRoot, ParamContextsList **listHead)
294 {
295     SharedMem *memPtr = NULL;
296     ParamContextsTrie *root = NULL;
297     ParamContextsList *listPtr = NULL;
298     if (!ReadParamFromSharedMemInit(&root, &listPtr, &memPtr)) {
299         return false;
300     }
301     uint32_t currentPos = 0;
302     ParamContextsList *tmpHead = listPtr;
303     int index = INIT_INDEX;
304     while (memPtr != NULL && memPtr->paramNameSize > 0) {
305         char *paramName = ReadSharedMem(memPtr->data, memPtr->paramNameSize);
306         char *context = ReadSharedMem(memPtr->data + memPtr->paramNameSize + 1, memPtr->paramLabelSize);
307         int tmpIndex = FindContextFromList(context, tmpHead->next);
308         tmpIndex = (tmpIndex == DEFAULT_CONTEXT_INDEX) ? index : tmpIndex;
309         if ((!InsertParamToTrie(root, paramName, context, tmpIndex)) ||
310             (!InsertContextsList(&listPtr, paramName, context, tmpIndex))) {
311             continue;
312         }
313         index++;
314         uint32_t dataLen = memPtr->paramNameSize + memPtr->paramLabelSize + 2; // 2 bytes for '\0'
315         uint32_t readSize = dataLen + sizeof(SharedMem);                       // space used for read SharedMem struct
316         currentPos += readSize;
317         if (currentPos > SELINUX_PARAM_SPACE) { // no space to read
318             break;
319         }
320         memPtr = (SharedMem *)((char *)memPtr + readSize);
321     }
322     listPtr = tmpHead->next;
323     free(tmpHead);
324     *listHead = listPtr;
325     *trieRoot = root;
326     return true;
327 }
328 
WriteParamToSharedMem(char * paramName,char * context,uint32_t * currentPos,SharedMem ** memPtr)329 static int WriteParamToSharedMem(char *paramName, char *context, uint32_t *currentPos, SharedMem **memPtr)
330 {
331     uint32_t paramLen = strlen(paramName);
332     uint32_t contextLen = strlen(context);
333     if (paramLen > MAX_LEN || contextLen > MAX_LEN) { // too long, ignore
334         return 0;
335     }
336     uint32_t dataLen = paramLen + contextLen + 2;        // 2 bytes for write '\0'
337     uint32_t writeSize = dataLen + sizeof(SharedMem);    // space used for write SharedMem struct
338     if (*currentPos + writeSize > SELINUX_PARAM_SPACE) { // no space to write
339         return -1;
340     }
341     *currentPos += writeSize;
342 
343     SharedMem *tmPtr = *memPtr;
344     tmPtr->paramNameSize = paramLen;
345     tmPtr->paramLabelSize = contextLen;
346     char *writePtr = tmPtr->data;
347     WriteSharedMem(writePtr, paramName, paramLen);
348     writePtr[paramLen] = '\0';
349     writePtr = tmPtr->data + paramLen + 1;
350     WriteSharedMem(writePtr, context, contextLen);
351     writePtr[contextLen] = '\0';
352     *memPtr = (SharedMem *)((char *)tmPtr + writeSize); // get the next SharedMem ptr
353     return 0;
354 }
355 
LoadParameterContexts(const char * fileName,uint32_t * currentPos,SharedMem ** memPtr)356 static void LoadParameterContexts(const char* fileName, uint32_t *currentPos, SharedMem **memPtr)
357 {
358     char buffer[512] = {0};
359     FILE *fp = fopen(fileName, "r");
360     if (fp == NULL) {
361         return;
362     }
363     while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) {
364         size_t n = strlen(buffer);
365         if (n == 0) {
366             continue;
367         }
368         if (buffer[n - 1] == '\n') {
369             buffer[n - 1] = '\0';
370         }
371         if (CouldSkip(buffer)) {
372             continue;
373         }
374         char *rest = NULL;
375         char split[] = " \t";
376         char *paramName = strtok_r(buffer, split, &rest);
377         if (paramName == NULL) {
378             continue;
379         }
380         char *context = strtok_r(NULL, split, &rest);
381         if (context == NULL) {
382             continue;
383         }
384         if (WriteParamToSharedMem(paramName, context, currentPos, memPtr) != 0) {
385             break;
386         }
387     }
388     (void)fclose(fp);
389 }
390 
LoadParameterContextsToSharedMem(void)391 int LoadParameterContextsToSharedMem(void)
392 {
393     SharedMem *memPtr = (SharedMem *)InitSharedMem("/dev/__parameters__/param_selinux", SELINUX_PARAM_SPACE, false);
394     if (memPtr == NULL) {
395         return -SELINUX_PTR_NULL;
396     }
397     SharedMem *head = memPtr;
398     uint32_t currentPos = 0;
399     LoadParameterContexts(SYSTEM_PARAMETER_CONTEXTS, &currentPos, &memPtr);
400     LoadParameterContexts(VENDOR_PARAMETER_CONTEXTS, &currentPos, &memPtr);
401     UnmapSharedMem((char *)head, SELINUX_PARAM_SPACE);
402     return currentPos > 0 ? 0 : -SELINUX_CONTEXTS_FILE_LOAD_ERROR;
403 }
404