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 DEBUGGABLE = "debuggable";
60 static const std::string DLPSANDBOX = "dlp_sandbox";
61 static const std::string INPUT_ISOLATE = "input_isolate";
62 static const char *DEFAULT_CONTEXT = "u:object_r:unlabeled:s0";
63 static const int CONTEXTS_LENGTH_MIN = 20; // sizeof("apl=x domain= type=")
64 static const int CONTEXTS_LENGTH_MAX = 1024;
65 static pthread_once_t g_fcOnce = PTHREAD_ONCE_INIT;
66 static std::unique_ptr<SehapContextsTrie> g_sehapContextsTrie = nullptr;
67 std::mutex g_loadContextsLock;
68 } // namespace
69 
SelinuxSetCallback()70 static void SelinuxSetCallback()
71 {
72     SetSelinuxHilogLevel(SELINUX_HILOG_ERROR);
73     union selinux_callback cb;
74     cb.func_log = SelinuxHilog;
75     selinux_set_callback(SELINUX_CB_LOG, cb);
76 }
77 
CouldSkip(const std::string & line)78 static bool CouldSkip(const std::string &line)
79 {
80     if (line.size() <= CONTEXTS_LENGTH_MIN || line.size() > CONTEXTS_LENGTH_MAX) {
81         return true;
82     }
83     int i = 0;
84     while (isspace(line[i])) {
85         i++;
86     }
87     if (line[i] == '#') {
88         return true;
89     }
90     if (line.find(APL_PREFIX) == line.npos) {
91         return true;
92     }
93     return false;
94 }
95 
DecodeString(const std::string & line,bool & isValid)96 static struct SehapInfo DecodeString(const std::string &line, bool &isValid)
97 {
98     std::stringstream input(line);
99     std::string tmp;
100     struct SehapInfo contextBuff;
101     bool aplVisit = false;
102     bool nameVisit = false;
103     bool domainVisit = false;
104     bool typeVisit = false;
105     bool debuggableVisit = false;
106     bool extraVisit = false;
107 
108     while (input >> tmp) {
109         if (!aplVisit && (tmp.find(APL_PREFIX) != tmp.npos)) {
110             contextBuff.apl = tmp.substr(tmp.find(APL_PREFIX) + APL_PREFIX.size());
111             aplVisit = true;
112         } else if (!nameVisit && (tmp.find(NAME_PREFIX) != tmp.npos)) {
113             contextBuff.name = tmp.substr(tmp.find(NAME_PREFIX) + NAME_PREFIX.size());
114             nameVisit = true;
115         } else if (!domainVisit && (tmp.find(DOMAIN_PREFIX) != tmp.npos)) {
116             contextBuff.domain = tmp.substr(tmp.find(DOMAIN_PREFIX) + DOMAIN_PREFIX.size());
117             domainVisit = true;
118         } else if (!typeVisit && (tmp.find(TYPE_PREFIX) != tmp.npos)) {
119             contextBuff.type = tmp.substr(tmp.find(TYPE_PREFIX) + TYPE_PREFIX.size());
120             typeVisit = true;
121         } else if (!debuggableVisit && (tmp.find(DEBUGGABLE_PREFIX) != tmp.npos)) {
122             std::string debuggable = tmp.substr(tmp.find(DEBUGGABLE_PREFIX) + DEBUGGABLE_PREFIX.size());
123             contextBuff.debuggable = !strcmp(debuggable.c_str(), "true");
124             debuggableVisit = true;
125         } else if (!extraVisit && (tmp.find(EXTRA_PREFIX) != tmp.npos)) {
126             std::string extra = tmp.substr(tmp.find(EXTRA_PREFIX) + EXTRA_PREFIX.size());
127             if (extra == DLPSANDBOX) {
128                 contextBuff.extra |= SELINUX_HAP_DLP;
129             } else if (extra == INPUT_ISOLATE) {
130                 contextBuff.extra |= SELINUX_HAP_INPUT_ISOLATE;
131             } else {
132                 selinux_log(SELINUX_ERROR, "invalid extra %s\n", extra.c_str());
133                 isValid = false;
134                 break;
135             }
136             extraVisit = true;
137         }
138     }
139 
140     return contextBuff;
141 }
142 
CheckPath(const std::string & path)143 static bool CheckPath(const std::string &path)
144 {
145     std::regex pathPrefix1("^/data/app/el[1-5]/[0-9]+/(base|database)/.*");
146     std::regex pathPrefix2("^/data/accounts/account_0/appdata/.*");
147     std::regex pathPrefix3("^/data/service/el[1-5]/[0-9]+/backup/bundles/.*");
148     if (std::regex_match(path, pathPrefix1) || std::regex_match(path, pathPrefix2) ||
149         std::regex_match(path, pathPrefix3)) {
150         return true;
151     }
152     return false;
153 }
154 
CheckApl(const std::string & apl)155 static bool CheckApl(const std::string &apl)
156 {
157     if (apl == "system_core" || apl == "system_basic" || apl == "normal") {
158         return true;
159     }
160     return false;
161 }
162 
GetHapContextKey(const struct SehapInfo * hapInfo)163 static std::string GetHapContextKey(const struct SehapInfo *hapInfo)
164 {
165     std::string keyPara;
166 
167     if (hapInfo->extra & SELINUX_HAP_INPUT_ISOLATE) {
168         if (hapInfo->debuggable) {
169             keyPara = hapInfo->apl + "." + DEBUGGABLE + "." + INPUT_ISOLATE;
170         } else {
171             keyPara = hapInfo->apl + "." + INPUT_ISOLATE;
172         }
173     } else if (hapInfo->extra & SELINUX_HAP_DLP) {
174         keyPara = hapInfo->apl + "." + DLPSANDBOX;
175     } else if (hapInfo->debuggable) {
176         keyPara = hapInfo->apl + "." + DEBUGGABLE;
177     } else if (!hapInfo->name.empty()) {
178         keyPara = hapInfo->apl + "." + hapInfo->name;
179     } else {
180         keyPara = hapInfo->apl;
181     }
182 
183     return keyPara;
184 }
185 
HapContextsInsert(const SehapInfo & tmpInfo,int lineNum)186 static bool HapContextsInsert(const SehapInfo &tmpInfo, int lineNum)
187 {
188     std::string keyPara = GetHapContextKey(&tmpInfo);
189     if (keyPara.empty()) {
190         selinux_log(SELINUX_ERROR, "hap_contexts read fail in line %d\n", lineNum);
191         return false;
192     }
193 
194     selinux_log(SELINUX_INFO, "insert keyPara %s\n", keyPara.c_str());
195     bool ret = g_sehapContextsTrie->Insert(keyPara, tmpInfo.domain, tmpInfo.type);
196     if (!ret) {
197         selinux_log(SELINUX_ERROR, "sehap contexts trie insert fail %s\n", keyPara.c_str());
198         return false;
199     }
200 
201     if (tmpInfo.name.empty() && !tmpInfo.debuggable && !tmpInfo.extra) {
202         keyPara = tmpInfo.apl + ".";
203         ret = g_sehapContextsTrie->Insert(keyPara, tmpInfo.domain, tmpInfo.type);
204     }
205 
206     return ret;
207 }
208 
HapContextsLoad()209 static bool HapContextsLoad()
210 {
211     // load sehap_contexts file
212     std::ifstream contextsFile(SEHAP_CONTEXTS_FILE);
213     if (contextsFile) {
214         g_sehapContextsTrie = std::make_unique<SehapContextsTrie>();
215         if (g_sehapContextsTrie == nullptr) {
216             selinux_log(SELINUX_ERROR, "malloc g_sehapContextsTrie fail");
217             return false;
218         }
219         int lineNum = 0;
220         std::string line;
221         while (getline(contextsFile, line)) {
222             lineNum++;
223             if (CouldSkip(line)) {
224                 continue;
225             }
226             bool isValid = true;
227             struct SehapInfo tmpInfo = DecodeString(line, isValid);
228             if (!isValid) {
229                 continue;
230             }
231             if (!HapContextsInsert(tmpInfo, lineNum)) {
232                 g_sehapContextsTrie->Clear();
233                 g_sehapContextsTrie = nullptr;
234                 return false;
235             }
236         }
237     } else {
238         selinux_log(SELINUX_ERROR, "Load hap_contexts fail, no such file: %s\n", SEHAP_CONTEXTS_FILE.c_str());
239         return false;
240     }
241     selinux_log(SELINUX_INFO, "Load hap_contexts succes: %s\n", SEHAP_CONTEXTS_FILE.c_str());
242     contextsFile.close();
243     return true;
244 }
245 
CheckValidCmp(char * oldSecontext,char * newSecontext)246 static bool CheckValidCmp(char *oldSecontext, char *newSecontext)
247 {
248     if (oldSecontext == nullptr || newSecontext == nullptr) {
249         if (oldSecontext != nullptr) {
250             freecon(oldSecontext);
251         }
252         if (newSecontext != nullptr) {
253             freecon(newSecontext);
254         }
255         return false;
256     }
257     return true;
258 }
259 
HapContext()260 HapContext::HapContext()
261 {
262     __selinux_once(g_fcOnce, SelinuxSetCallback);
263 }
264 
~HapContext()265 HapContext::~HapContext() {}
266 
HapFileRestorecon(HapFileInfo & hapFileInfo)267 int HapContext::HapFileRestorecon(HapFileInfo& hapFileInfo)
268 {
269     if (hapFileInfo.apl.empty() || hapFileInfo.pathNameOrig.empty() || !CheckApl(hapFileInfo.apl)) {
270         return -SELINUX_ARG_INVALID;
271     }
272     bool failFlag = false;
273     for (auto pathname : hapFileInfo.pathNameOrig) {
274         int res = HapFileRestorecon(pathname.c_str(), hapFileInfo);
275         if (res != SELINUX_SUCC) {
276             failFlag = true;
277             selinux_log(SELINUX_ERROR, "HapFileRestorecon fail for path: %s, errorNo: %d", pathname.c_str(), res);
278         }
279     }
280     return failFlag ? -SELINUX_RESTORECON_ERROR : SELINUX_SUCC;
281 }
282 
HapFileRestorecon(const std::string & pathNameOrig,HapFileInfo & hapFileInfo)283 int HapContext::HapFileRestorecon(const std::string &pathNameOrig, HapFileInfo& hapFileInfo)
284 {
285     if (hapFileInfo.apl.empty() || pathNameOrig.empty() || !CheckApl(hapFileInfo.apl)) {
286         return -SELINUX_ARG_INVALID;
287     }
288     if (is_selinux_enabled() < 1) {
289         selinux_log(SELINUX_INFO, "Selinux not enbaled");
290         return SELINUX_SUCC;
291     }
292 
293     char realPath[PATH_MAX];
294     if (realpath(pathNameOrig.c_str(), realPath) == nullptr) {
295         return -SELINUX_PATH_INVAILD;
296     }
297 
298     if (!CheckPath(realPath)) {
299         return -SELINUX_PATH_INVAILD;
300     }
301 
302     char *newSecontext = nullptr;
303     char *oldSecontext = nullptr;
304     int res = GetSecontext(hapFileInfo, pathNameOrig, &newSecontext, &oldSecontext);
305     if (res < 0) {
306         return res;
307     }
308     if (!CheckValidCmp(oldSecontext, newSecontext)) {
309         selinux_log(SELINUX_ERROR, "oldSecontext or newSecontext is null");
310         return -SELINUX_PTR_NULL;
311     }
312     if (strcmp(oldSecontext, newSecontext) == 0) {
313         freecon(newSecontext);
314         freecon(oldSecontext);
315         return SELINUX_SUCC;
316     }
317     freecon(newSecontext);
318     freecon(oldSecontext);
319     // determine whether needs recurse
320     bool recurse = (hapFileInfo.flags & SELINUX_HAP_RESTORECON_RECURSE) ? true : false;
321     if (!recurse) {
322         int ret = RestoreconSb(realPath, hapFileInfo);
323         if (ret < 0) {
324             selinux_log(SELINUX_ERROR, "RestoreconSb failed");
325         }
326         return ret;
327     }
328     return HapFileRecurseRestorecon(realPath, hapFileInfo);
329 }
330 
HapFileRecurseRestorecon(const std::string & realPath,HapFileInfo & hapFileInfo)331 int HapContext::HapFileRecurseRestorecon(const std::string &realPath, HapFileInfo& hapFileInfo)
332 {
333     char *paths[2] = {nullptr, nullptr};
334     paths[0] = strdup(realPath.c_str());
335     if (paths[0] == nullptr) {
336         return -SELINUX_PTR_NULL;
337     }
338 
339     int ftsFlags = FTS_PHYSICAL | FTS_NOCHDIR;
340     FTS *fts = fts_open(paths, ftsFlags, nullptr);
341     if (fts == nullptr) {
342         selinux_log(SELINUX_ERROR, "%s on %s: %s\n", GetErrStr(SELINUX_FTS_OPEN_ERROR), paths[0], strerror(errno));
343         free(paths[0]);
344         return -SELINUX_FTS_OPEN_ERROR;
345     }
346 
347     FTSENT *ftsent = nullptr;
348     int error = 0;
349     while ((ftsent = fts_read(fts)) != nullptr) {
350         switch (ftsent->fts_info) {
351             case FTS_DC:
352                 (void)fts_close(fts);
353                 free(paths[0]);
354                 return -SELINUX_FTS_ELOOP;
355             case FTS_DP:
356                 continue;
357             case FTS_DNR:
358                 fts_set(fts, ftsent, FTS_SKIP);
359                 continue;
360             case FTS_ERR:
361                 fts_set(fts, ftsent, FTS_SKIP);
362                 continue;
363             case FTS_NS:
364                 fts_set(fts, ftsent, FTS_SKIP);
365                 continue;
366             case FTS_D:
367             default:
368                 if (RestoreconSb(ftsent->fts_path, hapFileInfo) != 0) {
369                     error = -SELINUX_RESTORECON_ERROR;
370                 }
371                 break;
372         }
373     }
374     (void)fts_close(fts);
375     free(paths[0]);
376     return error;
377 }
378 
RestoreconSb(const std::string & pathNameOrig,HapFileInfo & hapFileInfo)379 int HapContext::RestoreconSb(const std::string &pathNameOrig, HapFileInfo& hapFileInfo)
380 {
381     char *newSecontext = nullptr;
382     char *oldSecontext = nullptr;
383     int res = GetSecontext(hapFileInfo, pathNameOrig, &newSecontext, &oldSecontext);
384     if (res < 0) {
385         return res;
386     }
387 
388     if (!CheckValidCmp(oldSecontext, newSecontext)) {
389         selinux_log(SELINUX_ERROR, "oldSecontext or newSecontext is null");
390         return -SELINUX_PTR_NULL;
391     }
392 
393     if (strcmp(oldSecontext, newSecontext)) {
394         if (lsetfilecon(pathNameOrig.c_str(), newSecontext) < 0) {
395             freecon(newSecontext);
396             freecon(oldSecontext);
397             return -SELINUX_SET_CONTEXT_ERROR;
398         }
399     }
400     freecon(newSecontext);
401     freecon(oldSecontext);
402     return SELINUX_SUCC;
403 }
404 
GetSecontext(HapFileInfo & hapFileInfo,const std::string & pathNameOrig,char ** newSecontext,char ** oldSecontext)405 int HapContext::GetSecontext(HapFileInfo& hapFileInfo, const std::string &pathNameOrig,
406     char **newSecontext, char **oldSecontext)
407 {
408     if (lgetfilecon(pathNameOrig.c_str(), oldSecontext) < 0) {
409         return -SELINUX_GET_CONTEXT_ERROR;
410     }
411 
412     int res = HapLabelLookup(hapFileInfo.apl, hapFileInfo.packageName, newSecontext, hapFileInfo.hapFlags);
413     if (res < 0) {
414         freecon(*oldSecontext);
415         return res;
416     }
417     return SELINUX_SUCC;
418 }
419 
HapLabelLookup(const std::string & apl,const std::string & packageName,char ** secontextPtr,unsigned int hapFlags)420 int HapContext::HapLabelLookup(const std::string &apl, const std::string &packageName,
421     char **secontextPtr, unsigned int hapFlags)
422 {
423     *secontextPtr = strdup(DEFAULT_CONTEXT);
424     if (*secontextPtr == nullptr) {
425         return -SELINUX_PTR_NULL;
426     }
427     const char *secontext = *secontextPtr;
428     context_t con = context_new(secontext);
429     if (con == nullptr) {
430         freecon(*secontextPtr);
431         *secontextPtr = nullptr;
432         return -SELINUX_PTR_NULL;
433     }
434     int res = HapContextsLookup(false, apl, packageName, con, hapFlags);
435     if (res < 0) {
436         freecon(*secontextPtr);
437         *secontextPtr = nullptr;
438         context_free(con);
439         return res;
440     }
441     secontext = context_str(con);
442     if (secontext == nullptr) {
443         freecon(*secontextPtr);
444         *secontextPtr = nullptr;
445         context_free(con);
446         return -SELINUX_PTR_NULL;
447     }
448     // if new contexts is same as old
449     if (!strcmp(secontext, *secontextPtr)) {
450         freecon(*secontextPtr);
451         *secontextPtr = nullptr;
452         context_free(con);
453         return SELINUX_SUCC;
454     }
455     // check whether the context is valid
456     if (security_check_context(secontext) < 0) {
457         selinux_log(SELINUX_ERROR, "context: %s, %s\n", secontext, GetErrStr(SELINUX_CHECK_CONTEXT_ERROR));
458         freecon(*secontextPtr);
459         *secontextPtr = nullptr;
460         context_free(con);
461         return -SELINUX_CHECK_CONTEXT_ERROR;
462     }
463     freecon(*secontextPtr);
464     *secontextPtr = strdup(secontext);
465     if (*secontextPtr == nullptr) {
466         context_free(con);
467         return -SELINUX_PTR_NULL;
468     }
469     context_free(con);
470     return SELINUX_SUCC;
471 }
472 
HapDomainSetcontext(HapDomainInfo & hapDomainInfo)473 int HapContext::HapDomainSetcontext(HapDomainInfo& hapDomainInfo)
474 {
475     if (hapDomainInfo.apl.empty() || !CheckApl(hapDomainInfo.apl)) {
476         return -SELINUX_ARG_INVALID;
477     }
478 
479     if (is_selinux_enabled() < 1) {
480         selinux_log(SELINUX_INFO, "Selinux not enbaled");
481         return SELINUX_SUCC;
482     }
483 
484     char *oldTypeContext = nullptr;
485     if (getcon(&oldTypeContext)) {
486         return -SELINUX_GET_CONTEXT_ERROR;
487     }
488 
489     context_t con = nullptr;
490     con = context_new(oldTypeContext);
491     if (con == nullptr) {
492         return -SELINUX_PTR_NULL;
493     }
494 
495     int res = HapContextsLookup(true, hapDomainInfo.apl, hapDomainInfo.packageName, con, hapDomainInfo.hapFlags);
496     if (res < 0) {
497         freecon(oldTypeContext);
498         context_free(con);
499         return res;
500     }
501 
502     const char *typeContext = context_str(con);
503     if (typeContext == nullptr) {
504         freecon(oldTypeContext);
505         context_free(con);
506         return -SELINUX_PTR_NULL;
507     }
508 
509     selinux_log(SELINUX_INFO, "Hap type for %s is changing from %s to %s\n",
510         hapDomainInfo.packageName.c_str(), oldTypeContext, typeContext);
511 
512     if (security_check_context(typeContext) < 0) {
513         selinux_log(SELINUX_ERROR, "context: %s, %s\n", typeContext, GetErrStr(SELINUX_CHECK_CONTEXT_ERROR));
514         freecon(oldTypeContext);
515         context_free(con);
516         return -SELINUX_CHECK_CONTEXT_ERROR;
517     }
518 
519     if (strcmp(typeContext, oldTypeContext)) {
520         if (setcon(typeContext) < 0) {
521             freecon(oldTypeContext);
522             context_free(con);
523             return -SELINUX_SET_CONTEXT_ERROR;
524         }
525     }
526     selinux_log(SELINUX_INFO, "Hap setcon finish for %s\n", hapDomainInfo.packageName.c_str());
527 
528     freecon(oldTypeContext);
529     context_free(con);
530     return SELINUX_SUCC;
531 }
532 
HapContextsLookup(bool isDomain,const std::string & apl,const std::string & packageName,context_t con,unsigned int hapFlags)533 int HapContext::HapContextsLookup(bool isDomain, const std::string &apl, const std::string &packageName,
534     context_t con, unsigned int hapFlags)
535 {
536     {
537         std::lock_guard<std::mutex> lock(g_loadContextsLock);
538         if (g_sehapContextsTrie == nullptr) {
539             if (!HapContextsLoad()) {
540                 return -SELINUX_CONTEXTS_FILE_LOAD_ERROR;
541             }
542         }
543     }
544 
545     std::string keyPara;
546     if (hapFlags & SELINUX_HAP_INPUT_ISOLATE) {
547         if (hapFlags & SELINUX_HAP_DEBUGGABLE) {
548             keyPara = apl + "." + DEBUGGABLE + "." + INPUT_ISOLATE;
549             selinux_log(SELINUX_INFO, "input_isolate debug  hap, keyPara: %s", keyPara.c_str());
550         } else {
551             keyPara = apl + "." + INPUT_ISOLATE;
552             selinux_log(SELINUX_INFO, "input_isolate isolate hap, keyPara: %s", keyPara.c_str());
553         }
554     } else if (hapFlags & SELINUX_HAP_DLP) {
555         keyPara = apl + "." + DLPSANDBOX;
556         selinux_log(SELINUX_INFO, "dlpsandbox hap, keyPara: %s", keyPara.c_str());
557     } else if (hapFlags & SELINUX_HAP_RESTORECON_PREINSTALLED_APP) {
558         keyPara = apl + "." + packageName;
559         selinux_log(SELINUX_INFO, "preinstall hap, keyPara: %s", keyPara.c_str());
560     } else if (hapFlags & SELINUX_HAP_DEBUGGABLE) {
561         keyPara = apl + "." + DEBUGGABLE;
562         selinux_log(SELINUX_INFO, "debuggable hap, keyPara: %s", keyPara.c_str());
563     } else {
564         selinux_log(SELINUX_INFO, "not a preinstall hap, apl: %s", apl.c_str());
565         keyPara = apl;
566     }
567 
568     std::string type = g_sehapContextsTrie->Search(keyPara, isDomain);
569     if (!type.empty()) {
570         return TypeSet(type, con);
571     }
572     return -SELINUX_KEY_NOT_FOUND;
573 }
574 
TypeSet(const std::string & type,context_t con)575 int HapContext::TypeSet(const std::string &type, context_t con)
576 {
577     if (type.empty()) {
578         selinux_log(SELINUX_ERROR, "type is empty in contexts file");
579         return -SELINUX_ARG_INVALID;
580     }
581     if (context_type_set(con, type.c_str())) {
582         selinux_log(SELINUX_ERROR, "%s %s\n", GetErrStr(SELINUX_SET_CONTEXT_TYPE_ERROR), type.c_str());
583         return -SELINUX_SET_CONTEXT_TYPE_ERROR;
584     }
585     return SELINUX_SUCC;
586 }
587