• 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 
16 #include "hap_restorecon.h"
17 
18 #include <cctype>
19 #include <cerrno>
20 #include <climits>
21 #include <clocale>
22 #include <cstdlib>
23 #include <fstream>
24 #include <istream>
25 #include <regex>
26 #include <sstream>
27 #include <streambuf>
28 #include <string>
29 #include <sys/stat.h>
30 #include <type_traits>
31 #include <unordered_map>
32 #include <utility>
33 #include <vector>
34 
35 #include <include/fts.h>
36 #include <pthread.h>
37 #include "selinux/context.h"
38 #include "selinux/selinux.h"
39 
40 #include "src/callbacks.h"
41 #include "selinux_error.h"
42 #include "selinux_log.h"
43 
44 using namespace Selinux;
45 
46 namespace {
47 #ifdef SELINUX_TEST
48 static const std::string SEHAP_CONTEXTS_FILE = "/data/test/sehap_contexts";
49 #else
50 static const std::string SEHAP_CONTEXTS_FILE = "/system/etc/selinux/targeted/contexts/sehap_contexts";
51 #endif // STARTUP_INIT_TEST
52 
53 static const std::string APL_PREFIX = "apl=";
54 static const std::string NAME_PREFIX = "name=";
55 static const std::string DOMAIN_PREFIX = "domain=";
56 static const std::string TYPE_PREFIX = "type=";
57 static const std::string DEBUGGABLE_PREFIX = "debuggable=";
58 static const std::string EXTRA_PREFIX = "extra=";
59 static const std::string EXTENSION_PREFIX = "extension=";
60 static const std::string LEVEL_PREFIX = "levelFrom=";
61 static const std::string USER_PREFIX = "user=";
62 static const std::string DEBUGGABLE = "debuggable";
63 static const std::string DLPSANDBOX = "dlp_sandbox";
64 static const std::string INPUT_ISOLATE = "input_isolate";
65 static const std::string CUSTOMSANDBOX = "custom_sandbox";
66 static const char *DEFAULT_CONTEXT = "u:object_r:unlabeled:s0";
67 static const int CONTEXTS_LENGTH_MIN = 20; // sizeof("apl=x domain= type=")
68 static const int CONTEXTS_LENGTH_MAX = 1024;
69 #ifdef MCS_ENABLE
70 static const uint32_t UID_BASE = 200000;
71 static const uint32_t USER_BASE = 100;
72 static const int CATEGORY_SEG0_OFFSET = 0;
73 static const int CATEGORY_SEG1_OFFSET = 256;
74 static const int CATEGORY_SEG2_OFFSET = 512;
75 static const int CATEGORY_SEG3_OFFSET = 768;
76 static const int CATEGORY_SEG4_OFFSET = 1024;
77 static const int CATEGORY_MASK = 0xff;
78 static const int SHIFT_8 = 8;
79 static const int SHIFT_16 = 16;
80 static const std::string PRODUCT_CONFIG_FILE = "/version/etc/selinux/product_config";
81 static const std::string DEFAULT_LEVEL_PREFIX = "defaultLevelFrom=";
82 static const std::string DEFAULT_USER_PREFIX = "defaultUser=";
83 static const std::string DEFAULT_MCS_HAP_FILE_PREFIX = "mcsHapFileEnabled=";
84 static LevelFrom g_defaultLevelFrom = LEVELFROM_NONE;
85 static std::string g_defaultUser = "u";
86 static bool g_mcsHapFileEnabled = false;
87 #endif
88 static pthread_once_t g_fcOnce = PTHREAD_ONCE_INIT;
89 static std::unique_ptr<SehapContextsTrie> g_sehapContextsTrie = nullptr;
90 std::mutex g_loadContextsLock;
91 } // namespace
92 
SelinuxSetCallback()93 static void SelinuxSetCallback()
94 {
95     SetSelinuxHilogLevel(SELINUX_HILOG_ERROR);
96     union selinux_callback cb;
97     cb.func_log = SelinuxHilog;
98     selinux_set_callback(SELINUX_CB_LOG, cb);
99 }
100 
CouldSkip(const std::string & line)101 static bool CouldSkip(const std::string &line)
102 {
103     if (line.size() <= CONTEXTS_LENGTH_MIN || line.size() > CONTEXTS_LENGTH_MAX) {
104         return true;
105     }
106     int i = 0;
107     while (isspace(line[i])) {
108         i++;
109     }
110     if (line[i] == '#') {
111         return true;
112     }
113     if (line.find(APL_PREFIX) == line.npos) {
114         return true;
115     }
116     return false;
117 }
118 
119 #ifdef MCS_ENABLE
GetLevelFrom(const std::string & level)120 static LevelFrom GetLevelFrom(const std::string &level)
121 {
122     LevelFrom levelFrom = LEVELFROM_NONE;
123     if (level == "all") {
124         levelFrom = LEVELFROM_ALL;
125     } else if (level == "user") {
126         levelFrom = LEVELFROM_USER;
127     } else if (level == "app") {
128         levelFrom = LEVELFROM_APP;
129     } else {
130         levelFrom = g_defaultLevelFrom;
131     }
132     return levelFrom;
133 }
134 
DeleteNonLetter(std::string str)135 static std::string DeleteNonLetter(std::string str)
136 {
137     str.erase(std::remove_if(str.begin(), str.end(), [](char c) { return !std::isalpha(c); }), str.end());
138     return str;
139 }
140 
SetDefaultConfig()141 static void SetDefaultConfig()
142 {
143     std::ifstream configFile(PRODUCT_CONFIG_FILE);
144     if (!configFile) {
145         selinux_log(SELINUX_ERROR, "Read %s failed, errno: %s\n", PRODUCT_CONFIG_FILE.c_str(), strerror(errno));
146         return;
147     }
148     std::string line;
149     bool levelVisited = false;
150     bool userVisited = false;
151     bool hapFileMcsVisited = false;
152     while (getline(configFile, line) && !(levelVisited && userVisited && hapFileMcsVisited)) {
153         size_t pos;
154         if (!levelVisited) {
155             pos = line.find(DEFAULT_LEVEL_PREFIX);
156             if (pos == 0) {
157                 g_defaultLevelFrom = GetLevelFrom(DeleteNonLetter(line.substr(DEFAULT_LEVEL_PREFIX.size())));
158                 levelVisited = true;
159                 continue;
160             }
161         }
162         if (!userVisited) {
163             pos = line.find(DEFAULT_USER_PREFIX);
164             if (pos == 0) {
165                 g_defaultUser = DeleteNonLetter(line.substr(DEFAULT_USER_PREFIX.size()));
166                 userVisited = true;
167                 continue;
168             }
169         }
170         if (!hapFileMcsVisited) {
171             pos = line.find(DEFAULT_MCS_HAP_FILE_PREFIX);
172             if (pos == 0) {
173                 g_mcsHapFileEnabled =
174                     !strcmp(DeleteNonLetter(line.substr(DEFAULT_MCS_HAP_FILE_PREFIX.size())).c_str(), "true");
175                 hapFileMcsVisited = true;
176             }
177         }
178     }
179     configFile.close();
180 }
181 #endif
182 
DecodeString(const std::string & line,bool & isValid)183 static struct SehapInfo DecodeString(const std::string &line, bool &isValid)
184 {
185     std::stringstream input(line);
186     std::string tmp;
187     struct SehapInfo contextBuff;
188     bool aplVisit = false;
189     bool nameVisit = false;
190     bool domainVisit = false;
191     bool typeVisit = false;
192     bool debuggableVisit = false;
193     bool extraVisit = false;
194     bool extensionVisit = false;
195 #ifdef MCS_ENABLE
196     bool levelVisit = false;
197     bool userVisit = false;
198     contextBuff.levelFrom = g_defaultLevelFrom;
199     contextBuff.user = g_defaultUser;
200 #endif
201     while (input >> tmp) {
202         size_t pos;
203         if (!aplVisit && (pos = tmp.find(APL_PREFIX)) != tmp.npos) {
204             contextBuff.apl = tmp.substr(pos + APL_PREFIX.size());
205             aplVisit = true;
206         } else if (!nameVisit && (pos = tmp.find(NAME_PREFIX)) != tmp.npos) {
207             contextBuff.name = tmp.substr(pos + NAME_PREFIX.size());
208             nameVisit = true;
209         } else if (!domainVisit && (pos = tmp.find(DOMAIN_PREFIX)) != tmp.npos) {
210             contextBuff.domain = tmp.substr(pos + DOMAIN_PREFIX.size());
211             domainVisit = true;
212         } else if (!typeVisit && (pos = tmp.find(TYPE_PREFIX)) != tmp.npos) {
213             contextBuff.type = tmp.substr(pos + TYPE_PREFIX.size());
214             typeVisit = true;
215         } else if (!debuggableVisit && (pos = tmp.find(DEBUGGABLE_PREFIX)) != tmp.npos) {
216             std::string debuggable = tmp.substr(pos + DEBUGGABLE_PREFIX.size());
217             contextBuff.debuggable = !strcmp(debuggable.c_str(), "true");
218             debuggableVisit = true;
219         } else if (!extensionVisit && (pos = tmp.find(EXTENSION_PREFIX)) != tmp.npos) {
220             contextBuff.extension = tmp.substr(pos + EXTENSION_PREFIX.size());
221             extensionVisit = true;
222 #ifdef MCS_ENABLE
223         } else if (!levelVisit && (pos = tmp.find(LEVEL_PREFIX)) != tmp.npos) {
224             contextBuff.levelFrom = GetLevelFrom(tmp.substr(pos + LEVEL_PREFIX.size()));
225             levelVisit = true;
226         } else if (!userVisit && (pos = tmp.find(USER_PREFIX)) != tmp.npos) {
227             contextBuff.user = tmp.substr(pos + USER_PREFIX.size());
228             userVisit = true;
229 #endif
230         } else if (!extraVisit && (pos = tmp.find(EXTRA_PREFIX)) != tmp.npos) {
231             std::string extra = tmp.substr(pos + EXTRA_PREFIX.size());
232             if (extra == DLPSANDBOX) {
233                 contextBuff.extra |= SELINUX_HAP_DLP;
234             } else if (extra == INPUT_ISOLATE) {
235                 contextBuff.extra |= SELINUX_HAP_INPUT_ISOLATE;
236             } else if (extra == CUSTOMSANDBOX) {
237                 contextBuff.extra |= SELINUX_HAP_CUSTOM_SANDBOX;
238             } else {
239                 selinux_log(SELINUX_ERROR, "invalid extra %s\n", extra.c_str());
240                 isValid = false;
241                 break;
242             }
243             extraVisit = true;
244         }
245     }
246     return contextBuff;
247 }
248 
CheckPath(const std::string & path)249 static bool CheckPath(const std::string &path)
250 {
251     std::regex pathPrefix1("^/data/app/el[1-5]/[0-9]+/(base|database|sharefiles)/.*");
252     std::regex pathPrefix2("^/data/accounts/account_0/appdata/.*");
253     std::regex pathPrefix3("^/data/service/el[1-5]/[0-9]+/backup/bundles/.*");
254     if (std::regex_match(path, pathPrefix1) || std::regex_match(path, pathPrefix2) ||
255         std::regex_match(path, pathPrefix3)) {
256         return true;
257     }
258     return false;
259 }
260 
CheckApl(const std::string & apl)261 static bool CheckApl(const std::string &apl)
262 {
263     if (apl == "system_core" || apl == "system_basic" || apl == "normal") {
264         return true;
265     }
266     return false;
267 }
268 
GetHapContextKey(const struct SehapInfo * hapInfo)269 static std::string GetHapContextKey(const struct SehapInfo *hapInfo)
270 {
271     std::string keyPara;
272 
273     if (hapInfo->extra & SELINUX_HAP_INPUT_ISOLATE) {
274         if (hapInfo->debuggable) {
275             keyPara = hapInfo->apl + "." + DEBUGGABLE + "." + INPUT_ISOLATE;
276         } else {
277             keyPara = hapInfo->apl + "." + INPUT_ISOLATE;
278         }
279     } else if (hapInfo->extra & SELINUX_HAP_DLP) {
280         keyPara = hapInfo->apl + "." + DLPSANDBOX;
281     } else if (hapInfo->extra & SELINUX_HAP_CUSTOM_SANDBOX) {
282         if (hapInfo->debuggable) {
283             keyPara = hapInfo->apl + "." + DEBUGGABLE + "." + CUSTOMSANDBOX + "." + hapInfo->name;
284         } else {
285             keyPara = hapInfo->apl + "." + CUSTOMSANDBOX + "." + hapInfo->name;
286         }
287     } else if (hapInfo->debuggable) {
288         keyPara = hapInfo->apl + "." + DEBUGGABLE;
289     } else if (!hapInfo->name.empty()) {
290         keyPara = hapInfo->apl + "." + hapInfo->name;
291     } else {
292         keyPara = hapInfo->apl;
293     }
294 
295     return keyPara;
296 }
297 
HapContextsInsert(const SehapInfo & tmpInfo,int lineNum)298 static bool HapContextsInsert(const SehapInfo &tmpInfo, int lineNum)
299 {
300     std::string keyPara = GetHapContextKey(&tmpInfo);
301     if (keyPara.empty()) {
302         selinux_log(SELINUX_ERROR, "hap_contexts read fail in line %d\n", lineNum);
303         return false;
304     }
305 
306     selinux_log(SELINUX_INFO, "insert keyPara %s\n", keyPara.c_str());
307     SehapInsertParamInfo tmpInsertInfo = {
308 #ifdef MCS_ENABLE
309         tmpInfo.levelFrom,
310         tmpInfo.user,
311 #endif
312         tmpInfo.domain,
313         tmpInfo.type,
314         tmpInfo.extension
315     };
316     bool ret = g_sehapContextsTrie->Insert(keyPara, tmpInsertInfo);
317     if (!ret) {
318         selinux_log(SELINUX_ERROR, "sehap contexts trie insert fail %s\n", keyPara.c_str());
319         return false;
320     }
321     if (tmpInfo.name.empty() && !tmpInfo.debuggable && !tmpInfo.extra) {
322         keyPara = tmpInfo.apl + ".";
323         ret = g_sehapContextsTrie->Insert(keyPara, tmpInsertInfo);
324     }
325     return ret;
326 }
327 
HapContextsLoad()328 static bool HapContextsLoad()
329 {
330 #ifdef MCS_ENABLE
331     SetDefaultConfig();
332 #endif
333     // load sehap_contexts file
334     std::ifstream contextsFile(SEHAP_CONTEXTS_FILE);
335     if (contextsFile) {
336         g_sehapContextsTrie = std::make_unique<SehapContextsTrie>();
337         if (g_sehapContextsTrie == nullptr) {
338             selinux_log(SELINUX_ERROR, "malloc g_sehapContextsTrie fail");
339             return false;
340         }
341         int lineNum = 0;
342         std::string line;
343         while (getline(contextsFile, line)) {
344             lineNum++;
345             if (CouldSkip(line)) {
346                 continue;
347             }
348             bool isValid = true;
349             struct SehapInfo tmpInfo = DecodeString(line, isValid);
350             if (!isValid) {
351                 continue;
352             }
353             if (!HapContextsInsert(tmpInfo, lineNum)) {
354                 g_sehapContextsTrie->Clear();
355                 g_sehapContextsTrie = nullptr;
356                 return false;
357             }
358         }
359     } else {
360         selinux_log(SELINUX_ERROR, "Load hap_contexts fail, no such file: %s\n", SEHAP_CONTEXTS_FILE.c_str());
361         return false;
362     }
363     selinux_log(SELINUX_INFO, "Load hap_contexts succes: %s\n", SEHAP_CONTEXTS_FILE.c_str());
364     contextsFile.close();
365     return true;
366 }
367 
CheckValidCmp(char * oldSecontext,char * newSecontext)368 static bool CheckValidCmp(char *oldSecontext, char *newSecontext)
369 {
370     if (oldSecontext == nullptr || newSecontext == nullptr) {
371         if (oldSecontext != nullptr) {
372             freecon(oldSecontext);
373         }
374         if (newSecontext != nullptr) {
375             freecon(newSecontext);
376         }
377         return false;
378     }
379     return true;
380 }
381 
FreeContext(char * oldTypeContext,context_t con)382 static void FreeContext(char *oldTypeContext, context_t con)
383 {
384     if (oldTypeContext != nullptr) {
385         freecon(oldTypeContext);
386     }
387     if (con != nullptr) {
388         context_free(con);
389     }
390 }
391 
HapContext()392 HapContext::HapContext()
393 {
394     __selinux_once(g_fcOnce, SelinuxSetCallback);
395 }
396 
~HapContext()397 HapContext::~HapContext() {}
398 
HapFileRestorecon(HapFileInfo & hapFileInfo)399 int HapContext::HapFileRestorecon(HapFileInfo& hapFileInfo)
400 {
401     if (hapFileInfo.apl.empty() || hapFileInfo.pathNameOrig.empty() || !CheckApl(hapFileInfo.apl)) {
402         return -SELINUX_ARG_INVALID;
403     }
404     bool failFlag = false;
405     for (auto pathname : hapFileInfo.pathNameOrig) {
406         int res = HapFileRestorecon(pathname.c_str(), hapFileInfo);
407         if (res != SELINUX_SUCC) {
408             failFlag = true;
409             selinux_log(SELINUX_ERROR, "HapFileRestorecon fail for path: %s, errorNo: %d", pathname.c_str(), res);
410         }
411     }
412     return failFlag ? -SELINUX_RESTORECON_ERROR : SELINUX_SUCC;
413 }
414 
HapFileRestorecon(const std::string & pathNameOrig,HapFileInfo & hapFileInfo)415 int HapContext::HapFileRestorecon(const std::string &pathNameOrig, HapFileInfo& hapFileInfo)
416 {
417     if (hapFileInfo.apl.empty() || pathNameOrig.empty() || !CheckApl(hapFileInfo.apl)) {
418         return -SELINUX_ARG_INVALID;
419     }
420     if (is_selinux_enabled() < 1) {
421         selinux_log(SELINUX_INFO, "Selinux not enbaled");
422         return SELINUX_SUCC;
423     }
424 
425     char realPath[PATH_MAX];
426     if (realpath(pathNameOrig.c_str(), realPath) == nullptr) {
427         return -SELINUX_PATH_INVALID;
428     }
429 
430     if (!CheckPath(realPath)) {
431         return -SELINUX_PATH_INVALID;
432     }
433 
434     char *newSecontext = nullptr;
435     char *oldSecontext = nullptr;
436     int res = GetSecontext(hapFileInfo, pathNameOrig, &newSecontext, &oldSecontext);
437     if (res < 0) {
438         return res;
439     }
440     if (!CheckValidCmp(oldSecontext, newSecontext)) {
441         selinux_log(SELINUX_ERROR, "oldSecontext or newSecontext is null");
442         return -SELINUX_PTR_NULL;
443     }
444     if (strcmp(oldSecontext, newSecontext) == 0) {
445         freecon(newSecontext);
446         freecon(oldSecontext);
447         return SELINUX_SUCC;
448     }
449     freecon(newSecontext);
450     freecon(oldSecontext);
451     // determine whether needs recurse
452     bool recurse = (hapFileInfo.flags & SELINUX_HAP_RESTORECON_RECURSE) ? true : false;
453     if (!recurse) {
454         int ret = RestoreconSb(realPath, hapFileInfo);
455         if (ret < 0) {
456             selinux_log(SELINUX_ERROR, "RestoreconSb failed");
457         }
458         return ret;
459     }
460     return HapFileRecurseRestorecon(realPath, hapFileInfo);
461 }
462 
HapFileRecurseRestorecon(const std::string & realPath,HapFileInfo & hapFileInfo)463 int HapContext::HapFileRecurseRestorecon(const std::string &realPath, HapFileInfo& hapFileInfo)
464 {
465     char *paths[2] = {nullptr, nullptr};
466     paths[0] = strdup(realPath.c_str());
467     if (paths[0] == nullptr) {
468         return -SELINUX_PTR_NULL;
469     }
470 
471     int ftsFlags = FTS_PHYSICAL | FTS_NOCHDIR;
472     FTS *fts = fts_open(paths, ftsFlags, nullptr);
473     if (fts == nullptr) {
474         selinux_log(SELINUX_ERROR, "%s on %s: %s\n", GetErrStr(SELINUX_FTS_OPEN_ERROR), paths[0], strerror(errno));
475         free(paths[0]);
476         return -SELINUX_FTS_OPEN_ERROR;
477     }
478 
479     FTSENT *ftsent = nullptr;
480     int error = 0;
481     while ((ftsent = fts_read(fts)) != nullptr) {
482         switch (ftsent->fts_info) {
483             case FTS_DC:
484                 (void)fts_close(fts);
485                 free(paths[0]);
486                 return -SELINUX_FTS_ELOOP;
487             case FTS_DP:
488                 continue;
489             case FTS_DNR:
490                 fts_set(fts, ftsent, FTS_SKIP);
491                 continue;
492             case FTS_ERR:
493                 fts_set(fts, ftsent, FTS_SKIP);
494                 continue;
495             case FTS_NS:
496                 fts_set(fts, ftsent, FTS_SKIP);
497                 continue;
498             case FTS_D:
499             default:
500                 if (RestoreconSb(ftsent->fts_path, hapFileInfo) != 0) {
501                     error = -SELINUX_RESTORECON_ERROR;
502                 }
503                 break;
504         }
505     }
506     (void)fts_close(fts);
507     free(paths[0]);
508     return error;
509 }
510 
RestoreconSb(const std::string & pathNameOrig,HapFileInfo & hapFileInfo)511 int HapContext::RestoreconSb(const std::string &pathNameOrig, HapFileInfo& hapFileInfo)
512 {
513     char *newSecontext = nullptr;
514     char *oldSecontext = nullptr;
515     int res = GetSecontext(hapFileInfo, pathNameOrig, &newSecontext, &oldSecontext);
516     if (res < 0) {
517         return res;
518     }
519 
520     if (!CheckValidCmp(oldSecontext, newSecontext)) {
521         selinux_log(SELINUX_ERROR, "oldSecontext or newSecontext is null");
522         return -SELINUX_PTR_NULL;
523     }
524 
525     if (strcmp(oldSecontext, newSecontext)) {
526         if (lsetfilecon(pathNameOrig.c_str(), newSecontext) < 0) {
527             freecon(newSecontext);
528             freecon(oldSecontext);
529             return -SELINUX_SET_CONTEXT_ERROR;
530         }
531     }
532     freecon(newSecontext);
533     freecon(oldSecontext);
534     return SELINUX_SUCC;
535 }
536 
GetSecontext(HapFileInfo & hapFileInfo,const std::string & pathNameOrig,char ** newSecontext,char ** oldSecontext)537 int HapContext::GetSecontext(HapFileInfo& hapFileInfo, const std::string &pathNameOrig,
538     char **newSecontext, char **oldSecontext)
539 {
540     if (lgetfilecon(pathNameOrig.c_str(), oldSecontext) < 0) {
541         return -SELINUX_GET_CONTEXT_ERROR;
542     }
543 
544     HapContextParams params = {hapFileInfo.apl, hapFileInfo.packageName, hapFileInfo.hapFlags};
545     params.uid = hapFileInfo.uid;
546     int res = HapLabelLookup(params, newSecontext);
547     if (res < 0) {
548         freecon(*oldSecontext);
549         return res;
550     }
551     return SELINUX_SUCC;
552 }
553 
HapLabelLookup(const HapContextParams & params,char ** secontextPtr)554 int HapContext::HapLabelLookup(const HapContextParams &params, char **secontextPtr)
555 {
556     *secontextPtr = strdup(DEFAULT_CONTEXT);
557     if (*secontextPtr == nullptr) {
558         return -SELINUX_PTR_NULL;
559     }
560     const char *secontext = *secontextPtr;
561     context_t con = context_new(secontext);
562     if (con == nullptr) {
563         freecon(*secontextPtr);
564         *secontextPtr = nullptr;
565         return -SELINUX_PTR_NULL;
566     }
567     int res = HapContextsLookup(params, con);
568     if (res < 0) {
569         freecon(*secontextPtr);
570         *secontextPtr = nullptr;
571         context_free(con);
572         return res;
573     }
574     secontext = context_str(con);
575     if (secontext == nullptr) {
576         freecon(*secontextPtr);
577         *secontextPtr = nullptr;
578         context_free(con);
579         return -SELINUX_PTR_NULL;
580     }
581     // if new contexts is same as old
582     if (!strcmp(secontext, *secontextPtr)) {
583         freecon(*secontextPtr);
584         *secontextPtr = nullptr;
585         context_free(con);
586         return SELINUX_SUCC;
587     }
588     // check whether the context is valid
589     if (security_check_context(secontext) < 0) {
590         selinux_log(SELINUX_ERROR, "context: %s, %s\n", secontext, GetErrStr(SELINUX_CHECK_CONTEXT_ERROR));
591         freecon(*secontextPtr);
592         *secontextPtr = nullptr;
593         context_free(con);
594         return -SELINUX_CHECK_CONTEXT_ERROR;
595     }
596     freecon(*secontextPtr);
597     *secontextPtr = strdup(secontext);
598     if (*secontextPtr == nullptr) {
599         context_free(con);
600         return -SELINUX_PTR_NULL;
601     }
602     context_free(con);
603     return SELINUX_SUCC;
604 }
605 
HapDomainSetcontext(HapDomainInfo & hapDomainInfo)606 int HapContext::HapDomainSetcontext(HapDomainInfo& hapDomainInfo)
607 {
608     if (hapDomainInfo.apl.empty() || !CheckApl(hapDomainInfo.apl)) {
609         return -SELINUX_ARG_INVALID;
610     }
611 
612     if (is_selinux_enabled() < 1) {
613         selinux_log(SELINUX_INFO, "Selinux not enabled");
614         return SELINUX_SUCC;
615     }
616 
617     char *oldTypeContext = nullptr;
618     if (getcon(&oldTypeContext)) {
619         return -SELINUX_GET_CONTEXT_ERROR;
620     }
621 
622     context_t con = nullptr;
623     con = context_new(oldTypeContext);
624     if (con == nullptr) {
625         FreeContext(oldTypeContext, con);
626         return -SELINUX_PTR_NULL;
627     }
628 
629     HapContextParams params = {hapDomainInfo.apl, hapDomainInfo.packageName,
630         hapDomainInfo.hapFlags, hapDomainInfo.extensionType, true, hapDomainInfo.uid};
631     int res = HapContextsLookup(params, con);
632     if (res < 0) {
633         FreeContext(oldTypeContext, con);
634         return res;
635     }
636 
637     const char *typeContext = context_str(con);
638     if (typeContext == nullptr) {
639         FreeContext(oldTypeContext, con);
640         return -SELINUX_PTR_NULL;
641     }
642 
643     selinux_log(SELINUX_INFO, "Hap type for %s is changing from %s to %s\n",
644         hapDomainInfo.packageName.c_str(), oldTypeContext, typeContext);
645 
646     if (security_check_context(typeContext) < 0) {
647         selinux_log(SELINUX_ERROR, "context: %s, %s\n", typeContext, GetErrStr(SELINUX_CHECK_CONTEXT_ERROR));
648         FreeContext(oldTypeContext, con);
649         return -SELINUX_CHECK_CONTEXT_ERROR;
650     }
651 
652     if (strcmp(typeContext, oldTypeContext)) {
653         if (setcon(typeContext) < 0) {
654             FreeContext(oldTypeContext, con);
655             return -SELINUX_SET_CONTEXT_ERROR;
656         }
657     }
658     selinux_log(SELINUX_INFO, "Hap setcon finish for %s\n", hapDomainInfo.packageName.c_str());
659 
660     FreeContext(oldTypeContext, con);
661     return SELINUX_SUCC;
662 }
663 
GetKeyParams(const HapContextParams & params)664 static std::string GetKeyParams(const HapContextParams &params)
665 {
666     std::string keyPara;
667     if (params.hapFlags & SELINUX_HAP_INPUT_ISOLATE) {
668         if (params.hapFlags & SELINUX_HAP_DEBUGGABLE) {
669             keyPara = params.apl + "." + DEBUGGABLE + "." + INPUT_ISOLATE;
670             selinux_log(SELINUX_INFO, "input_isolate debug hap, keyPara: %s", keyPara.c_str());
671         } else {
672             keyPara = params.apl + "." + INPUT_ISOLATE;
673             selinux_log(SELINUX_INFO, "input_isolate isolate hap, keyPara: %s", keyPara.c_str());
674         }
675     } else if (params.hapFlags & SELINUX_HAP_DLP) {
676         keyPara = params.apl + "." + DLPSANDBOX;
677         selinux_log(SELINUX_INFO, "dlpsandbox hap, keyPara: %s", keyPara.c_str());
678     } else if (params.hapFlags & SELINUX_HAP_CUSTOM_SANDBOX) {
679         if (params.hapFlags & SELINUX_HAP_DEBUGGABLE) {
680             keyPara = params.apl + "." + DEBUGGABLE + "." + CUSTOMSANDBOX + "." + params.packageName;
681             selinux_log(SELINUX_INFO, "customsandbox debug hap, keyPara: %s", keyPara.c_str());
682         } else {
683             keyPara = params.apl + "." + CUSTOMSANDBOX + "." + params.packageName;
684             selinux_log(SELINUX_INFO, "customsandbox hap, keyPara: %s", keyPara.c_str());
685         }
686     } else if (params.hapFlags & SELINUX_HAP_RESTORECON_PREINSTALLED_APP) {
687         keyPara = params.apl + "." + params.packageName;
688         selinux_log(SELINUX_INFO, "preinstall hap, keyPara: %s", keyPara.c_str());
689     } else if (params.hapFlags & SELINUX_HAP_DEBUGGABLE) {
690         keyPara = params.apl + "." + DEBUGGABLE;
691         selinux_log(SELINUX_INFO, "debuggable hap, keyPara: %s", keyPara.c_str());
692     } else {
693         selinux_log(SELINUX_INFO, "not a preinstall hap, apl: %s", params.apl.c_str());
694         keyPara = params.apl;
695     }
696     return keyPara;
697 }
698 
HapContextsLookup(const HapContextParams & params,context_t con)699 int HapContext::HapContextsLookup(const HapContextParams &params, context_t con)
700 {
701     {
702         std::lock_guard<std::mutex> lock(g_loadContextsLock);
703         if (g_sehapContextsTrie == nullptr) {
704             if (!HapContextsLoad()) {
705                 return -SELINUX_CONTEXTS_FILE_LOAD_ERROR;
706             }
707         }
708     }
709 
710     std::string keyPara = GetKeyParams(params);
711     SehapContextInfo contextInfo = g_sehapContextsTrie->Search(keyPara, params.isDomain, params.extension);
712     if (contextInfo.context.empty()) {
713         return -SELINUX_KEY_NOT_FOUND;
714     }
715     int res = TypeSet(contextInfo.context, con);
716     if (res < 0) {
717         return res;
718     }
719 #ifdef MCS_ENABLE
720     if (contextInfo.levelFrom != LEVELFROM_NONE && (params.isDomain || g_mcsHapFileEnabled)) {
721         return UserAndMCSRangeSet(params.uid, con, contextInfo.levelFrom, contextInfo.user);
722     }
723 #endif
724     return SELINUX_SUCC;
725 }
726 
TypeSet(const std::string & type,context_t con)727 int HapContext::TypeSet(const std::string &type, context_t con)
728 {
729     if (type.empty()) {
730         selinux_log(SELINUX_ERROR, "type is empty in contexts file");
731         return -SELINUX_ARG_INVALID;
732     }
733     if (context_type_set(con, type.c_str())) {
734         selinux_log(SELINUX_ERROR, "%s %s\n", GetErrStr(SELINUX_SET_CONTEXT_TYPE_ERROR), type.c_str());
735         return -SELINUX_SET_CONTEXT_TYPE_ERROR;
736     }
737     return SELINUX_SUCC;
738 }
739 
740 #ifdef MCS_ENABLE
GetMCSLevel(const LevelFrom & levelFrom,uint32_t userId,uint32_t appId)741 static std::string GetMCSLevel(const LevelFrom &levelFrom, uint32_t userId, uint32_t appId)
742 {
743     std::string level = "s0";
744     switch (levelFrom) {
745         case LEVELFROM_APP:
746             level = "s0:x" + std::to_string(CATEGORY_SEG0_OFFSET + (appId & CATEGORY_MASK)) +
747                 ",x" + std::to_string(CATEGORY_SEG1_OFFSET + ((appId >> SHIFT_8) & CATEGORY_MASK)) +
748                 ",x" + std::to_string(CATEGORY_SEG2_OFFSET + ((appId >> SHIFT_16) & CATEGORY_MASK));
749             break;
750         case LEVELFROM_USER:
751             level = "s0:x" + std::to_string(CATEGORY_SEG3_OFFSET + (userId & CATEGORY_MASK)) +
752                 ",x" + std::to_string(CATEGORY_SEG4_OFFSET + ((userId >> SHIFT_8) & CATEGORY_MASK));
753             break;
754         case LEVELFROM_ALL:
755             level = "s0:x" + std::to_string(CATEGORY_SEG0_OFFSET + (appId & CATEGORY_MASK)) +
756                 ",x" + std::to_string(CATEGORY_SEG1_OFFSET + ((appId >> SHIFT_8) & CATEGORY_MASK)) +
757                 ",x" + std::to_string(CATEGORY_SEG2_OFFSET + ((appId >> SHIFT_16) & CATEGORY_MASK)) +
758                 ",x" + std::to_string(CATEGORY_SEG3_OFFSET + (userId & CATEGORY_MASK)) +
759                 ",x" + std::to_string(CATEGORY_SEG4_OFFSET + ((userId >> SHIFT_8) & CATEGORY_MASK));
760             break;
761         default:
762             break;
763     }
764     return level;
765 }
766 
UserAndMCSRangeSet(uint32_t uid,context_t con,const LevelFrom & levelFrom,const std::string & user)767 int HapContext::UserAndMCSRangeSet(uint32_t uid, context_t con, const LevelFrom &levelFrom, const std::string &user)
768 {
769     if (uid < UID_BASE) {
770         return SELINUX_SUCC;
771     }
772     uint32_t userId = uid / UID_BASE;
773     uint32_t appId = uid % UID_BASE;
774     if (userId < USER_BASE) {
775         return SELINUX_SUCC;
776     }
777     int ret = context_user_set(con, user.c_str());
778     if (ret != 0) {
779         selinux_log(SELINUX_ERROR, "Failed to set context user %s\n", user.c_str());
780         return -SELINUX_SET_CONTEXT_USER_ERROR;
781     }
782     std::string level = GetMCSLevel(levelFrom, userId, appId);
783     ret = context_range_set(con, level.c_str());
784     if (ret != 0) {
785         selinux_log(SELINUX_ERROR, "Failed to set context range %s\n", level.c_str());
786         return -SELINUX_SET_CONTEXT_RANGE_ERROR;
787     }
788     return SELINUX_SUCC;
789 }
790 #endif
791