selinux label的初始化过程
selinux的架构中主要分为:subject和object。subject可以认为是进程,object可以认为是文件(linux中一切皆文件)。在系统代码中,通过撰写sepolicy规则文件(.te),在编译阶段预先为每个关键(subject)进程设置了security context,也为object(文件)设置了security context。那么这些文件是如何生效的呢?
第一步:静态sepolicy文件之间不存在冲突,能正常编译通过; 第二步:编译阶段把sepolicy文件编译成binary文件,并传入到内核; 第三步:内核在启动后以传入的sepolicy文件为原材料,构建起selinux在kernel层的工作框架。 默认第一步已经完成的情况下,重点讨论第二步和第三步的工作流程。 system/core/init/init.cpp 545int main(int argc,char** argv) { 546 ... 564 bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr); 565 566 if (is_first_stage) { 567 ... 586 mount("sysfs","/sys","sysfs",NULL); 587 mount("selinuxfs","/sys/fs/selinux","selinuxfs",NULL); 588 ... 618 // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote). 619 global_seccomp(); 620 621 // Set up SELinux,loading the SELinux policy. 622 SelinuxSetupKernelLogging(); 623 SelinuxInitialize(); 624 625 // We‘re in the kernel domain,so re-exec init to transition to the init domain now 626 // that the SELinux policy has been loaded. 627 if (selinux_android_restorecon("/init",0) == -1) { 628 PLOG(FATAL) << "restorecon failed of /init failed"; 629 } 630 631 setenv("INIT_SECOND_STAGE","true",1); 632 ... 644 } 645 646 ... 683 // Now set up SELinux for second stage. 684 SelinuxSetupKernelLogging(); 685 SelabelInitialize(); 686 SelinuxRestoreContext(); 687 ... 其中上述代码中 201bool FindPrecompiledSplitPolicy(std::string* file) { 202 file->clear(); 203 // If there is an odm partition,precompiled_sepolicy will be in 204 // odm/etc/selinux. Otherwise it will be in vendor/etc/selinux. 205 static constexpr const char vendor_precompiled_sepolicy[] = 206 "/vendor/etc/selinux/precompiled_sepolicy"; 207 static constexpr const char odm_precompiled_sepolicy[] = 208 "/odm/etc/selinux/precompiled_sepolicy"; 209 if (access(odm_precompiled_sepolicy,R_OK) == 0) { 210 *file = odm_precompiled_sepolicy; 211 } else if (access(vendor_precompiled_sepolicy,R_OK) == 0) { 212 *file = vendor_precompiled_sepolicy; 213 } else { 214 PLOG(INFO) << "No precompiled sepolicy"; 215 return false; 216 } 217 std::string actual_plat_id; 218 if (!ReadFirstLine("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256",&actual_plat_id)) { 219 PLOG(INFO) << "Failed to read " 220 "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256"; 221 return false; 222 } 223 224 std::string precompiled_plat_id; 225 std::string precompiled_sha256 = *file + ".plat_and_mapping.sha256"; 226 if (!ReadFirstLine(precompiled_sha256.c_str(),&precompiled_plat_id)) { 227 PLOG(INFO) << "Failed to read " << precompiled_sha256; 228 file->clear(); 229 return false; 230 } 231 if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) { 232 file->clear(); 233 return false; 234 } 235 return true; 236} ... 252bool IsSplitPolicyDevice() { 253 return access(plat_policy_cil_file,R_OK) != -1; 254} 255 256bool LoadSplitPolicy() { 257 // IMPLEMENTATION NOTE: Split policy consists of three CIL files: 258 // * platform -- policy needed due to logic contained in the system image,259 // * non-platform -- policy needed due to logic contained in the vendor image,260 // * mapping -- mapping policy which helps preserve forward-compatibility of non-platform policy 261 // with newer versions of platform policy. 262 // 263 // secilc is invoked to compile the above three policy files into a single monolithic policy 264 // file. This file is then loaded into the kernel. 265 266 // Load precompiled policy from vendor image,if a matching policy is found there. The policy 267 // must match the platform policy on the system image. 268 std::string precompiled_sepolicy_file; 269 if (FindPrecompiledSplitPolicy(&precompiled_sepolicy_file)) { 270 unique_fd fd(open(precompiled_sepolicy_file.c_str(),O_RDONLY | O_CLOEXEC | O_BINARY)); 271 if (fd != -1) { 272 if (selinux_android_load_policy_from_fd(fd,precompiled_sepolicy_file.c_str()) < 0) { 273 LOG(ERROR) << "Failed to load SELinux policy from " << precompiled_sepolicy_file; 274 return false; 275 } 276 return true; 277 } 278 } 367} ... 378bool LoadPolicy() { 379 return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy(); 380} ... 384void SelinuxInitialize() { 385 Timer t; 386 387 LOG(INFO) << "Loading SELinux policy"; 388 if (!LoadPolicy()) { 389 LOG(FATAL) << "Unable to load SELinux policy"; 390 } 391 ... 400 if (auto result = WriteFile("/sys/fs/selinux/checkreqprot","0"); !result) { 401 LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error(); 402 } 403} 然后通过SelabelInitialize()和SelinuxRestoreContext()把系统中的selinux context文件,加载其中定义的object(文件)的security context。 其中函数SelabelInitialize()的定义如下: 483// selinux_android_file_context_handle() takes on the order of 10+ms to run,so we want to cache 484// its value. selinux_android_restorecon() also needs an sehandle for file context look up. It 485// will create and store its own copy,but selinux_android_set_sehandle() can be used to provide 486// one,thus eliminating an extra call to selinux_android_file_context_handle(). 487void SelabelInitialize() { 488 sehandle = selinux_android_file_context_handle(); 489 selinux_android_set_sehandle(sehandle); 490} 其中 9static const struct selinux_opt SEOpts_file_plat[] = { 10 { SELABEL_OPT_PATH,"/system/etc/selinux/plat_file_contexts" },11 { SELABEL_OPT_PATH,"/plat_file_contexts" } 12}; 13static const struct selinux_opt SEOpts_file_vendor[] = { 14 { SELABEL_OPT_PATH,"/vendor/etc/selinux/vendor_file_contexts" },15 { SELABEL_OPT_PATH,"/vendor_file_contexts" },16 // TODO: remove nonplat* when no need to retain backward compatibility. 17 { SELABEL_OPT_PATH,"/vendor/etc/selinux/nonplat_file_contexts" },18 { SELABEL_OPT_PATH,"/nonplat_file_contexts" } 19}; 20static const struct selinux_opt SEOpts_file_odm[] = { 21 { SELABEL_OPT_PATH,"/odm/etc/selinux/odm_file_contexts" },22 { SELABEL_OPT_PATH,"/odm_file_contexts" } ... 133static struct selabel_handle* selinux_android_file_context(const struct selinux_opt *opts,134 unsigned nopts) 135{ 136 struct selabel_handle *sehandle; 137 struct selinux_opt fc_opts[nopts + 1]; 138 139 memcpy(fc_opts,opts,nopts*sizeof(struct selinux_opt)); 140 fc_opts[nopts].type = SELABEL_OPT_BASEONLY; 141 fc_opts[nopts].value = (char *)1; 142 143 sehandle = selabel_open(SELABEL_CTX_FILE,fc_opts,ARRAY_SIZE(fc_opts)); 144 if (!sehandle) { 145 selinux_log(SELINUX_ERROR,"%s: Error getting file context handle (%s)n",146 __FUNCTION__,strerror(errno)); 147 return NULL; 148 } 149 if (!compute_file_contexts_hash(fc_digest,nopts)) { 150 selabel_close(sehandle); 151 return NULL; 152 } 153 154 selinux_log(SELINUX_INFO,"SELinux: Loaded file_contextsn"); 155 156 return sehandle; 157} 158 159struct selabel_handle* selinux_android_file_context_handle(void) 160{ 161 struct selinux_opt SEOpts_file[MAX_FILE_CONTEXT_SIZE]; 162 int size = 0; 163 unsigned int i; 164 for (i = 0; i < ARRAY_SIZE(SEOpts_file_plat); i++) { 165 if (access(SEOpts_file_plat[i].value,R_OK) != -1) { 166 SEOpts_file[size++] = SEOpts_file_plat[i]; 167 break; 168 } 169 } 170 for (i = 0; i < ARRAY_SIZE(SEOpts_file_vendor); i++) { 171 if (access(SEOpts_file_vendor[i].value,R_OK) != -1) { 172 SEOpts_file[size++] = SEOpts_file_vendor[i]; 173 break; 174 } 175 } 176 for (i = 0; i < ARRAY_SIZE(SEOpts_file_odm); i++) { 177 if (access(SEOpts_file_odm[i].value,R_OK) != -1) { 178 SEOpts_file[size++] = SEOpts_file_odm[i]; 179 break; 180 } 181 } 182 return selinux_android_file_context(SEOpts_file,size); 183} 其中对 external/selinux/libselinux/src/label.c 50typedef int (*selabel_initfunc)(struct selabel_handle *rec,51 const struct selinux_opt *opts,52 unsigned nopts); 53 54static selabel_initfunc initfuncs[] = { 55 CONFIG_FILE_BACKEND(selabel_file_init),56 CONFIG_MEDIA_BACKEND(selabel_media_init),57 CONFIG_X_BACKEND(selabel_x_init),58 CONFIG_DB_BACKEND(selabel_db_init),59 CONFIG_ANDROID_BACKEND(selabel_property_init),60 CONFIG_ANDROID_BACKEND(selabel_service_init),61}; ... 212struct selabel_handle *selabel_open(unsigned int backend,213 const struct selinux_opt *opts,214 unsigned nopts) 215{ 216 struct selabel_handle *rec = NULL; 217 218 if (backend >= ARRAY_SIZE(initfuncs)) { 219 errno = EINVAL; 220 goto out; 221 } 222 223 if (!initfuncs[backend]) { 224 errno = ENOTSUP; 225 goto out; 226 } 227 228 rec = (struct selabel_handle *)malloc(sizeof(*rec)); 229 if (!rec) 230 goto out; 231 232 memset(rec,sizeof(*rec)); 233 rec->backend = backend; 234 rec->validating = selabel_is_validate_set(opts,nopts); 235 236 rec->digest = selabel_is_digest_set(opts,nopts,rec->digest); 237 238 if ((*initfuncs[backend])(rec,nopts)) { 239 selabel_close(rec); 240 rec = NULL; 241 } 242out: 243 return rec; 244} 其中 987static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,988 const char *key,int type) 989{ 990 struct spec *spec; 991 992 spec = lookup_common(rec,key,type,false); 993 if (spec) 994 return &spec->lr; 995 return NULL; 996} ... 1168int selabel_file_init(struct selabel_handle *rec,1169 const struct selinux_opt *opts,1170 unsigned nopts) 1171{ 1172 struct saved_data *data; 1173 1174 data = (struct saved_data *)malloc(sizeof(*data)); 1175 if (!data) 1176 return -1; 1177 memset(data,sizeof(*data)); 1178 1179 rec->data = data; 1180 rec->func_close = &closef; 1181 rec->func_stats = &stats; 1182 rec->func_lookup = &lookup; 1183 rec->func_partial_match = &partial_match; 1184 rec->func_lookup_best_match = &lookup_best_match; 1185 rec->func_cmp = &cmp; 1186 1187 return init(rec,nopts); 1188} 当完成 1661void selinux_android_set_sehandle(const struct selabel_handle *hndl) 1662{ 1663 fc_sehandle = (struct selabel_handle *) hndl; 1664} 至此完成了 那么在完成文件(File Object)security context导入后,而在kernel mode中尚未对这部分内存做任何处理,当在用户态用某个binary文件作为entry pointer启动一个进程的时候,内核中无法对这个进程做selinux context标识。所以还需要在kernel中利用这部分内存的内容,方便以后在内核态对新建进程进行selinux context标识,以及文件访问时进行内核态的约束。 system/core/init/ueventd.cpp 165void ColdBoot::DoRestoreCon() { 166 selinux_android_restorecon("/sys",SELINUX_ANDROID_RESTORECON_RECURSE); 167 device_handler_.set_skip_restorecon(false); 168} ... 203void ColdBoot::Run() { 204 android::base::Timer cold_boot_timer; 205 206 RegenerateUevents(); 207 208 ForkSubProcesses(); 209 210 DoRestoreCon(); 211 212 WaitForSubProcesses(); 213 214 close(open(COLDBOOT_DONE,O_WRONLY | O_CREAT | O_CLOEXEC,0000)); 215 LOG(INFO) << "Coldboot took " << cold_boot_timer.duration().count() / 1000.0f << " seconds"; 216} ... 260int ueventd_main(int argc,char** argv) { ... 273 SelabelInitialize(); 274 275 DeviceHandler device_handler = CreateDeviceHandler(); 276 UeventListener uevent_listener; 277 278 if (access(COLDBOOT_DONE,F_OK) != 0) { 279 ColdBoot cold_boot(uevent_listener,device_handler); 280 cold_boot.Run(); 281 } ... 289 290 uevent_listener.Poll([&device_handler](const Uevent& uevent) { 291 HandleFirmwareEvent(uevent); 292 device_handler.HandleDeviceEvent(uevent); 293 return ListenerAction::kContinue; 294 }); 295 296 return 0; 297} 根据上述代码可以看到代码逻辑如下: 至此完成了对各个分区内部各个文件(File Object)的进行security context标识所需要的所有准备工作,一旦有uevent事件触发,会进入DeviceHandler::HandleDeviceEvent处理该事件。处理uevent事件的代码逻辑如下: system/core/init/devices.cpp 192void DeviceHandler::FixupSysPermissions(const std::string& upath,193 const std::string& subsystem) const { 194 // upaths omit the "/sys" that paths in this list 195 // contain,so we prepend it... 196 std::string path = "/sys" + upath; 197 198 for (const auto& s : sysfs_permissions_) { 199 if (s.MatchWithSubsystem(path,subsystem)) s.SetPermissions(path); 200 } 201 202 if (!skip_restorecon_ && access(path.c_str(),F_OK) == 0) { 203 LOG(VERBOSE) << "restorecon_recursive: " << path; 204 if (selinux_android_restorecon(path.c_str(),SELINUX_ANDROID_RESTORECON_RECURSE) != 0) { 205 PLOG(ERROR) << "selinux_android_restorecon(" << path << ") failed"; 206 } 207 } 208} ... 376void DeviceHandler::HandleDeviceEvent(const Uevent& uevent) { 377 if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") { 378 FixupSysPermissions(uevent.path,uevent.subsystem); 379 } 380 381 // if it‘s not a /dev device,nothing to do 382 if (uevent.major < 0 || uevent.minor < 0) return; 383 384 std::string devpath; 385 std::vector<std::string> links; 386 bool block = false; 387 388 if (uevent.subsystem == "block") { 389 block = true; 390 devpath = "/dev/block/" + Basename(uevent.path); 391 392 if (StartsWith(uevent.path,"/devices")) { 393 links = GetBlockDeviceSymlinks(uevent); 394 } 395 } else if (const auto subsystem = 396 std::find(subsystems_.cbegin(),subsystems_.cend(),uevent.subsystem); 397 subsystem != subsystems_.cend()) { 398 devpath = subsystem->ParseDevPath(uevent); 399 } else if (uevent.subsystem == "usb") { 400 if (!uevent.device_name.empty()) { 401 devpath = "/dev/" + uevent.device_name; 402 } else { 403 // This imitates the file system that would be created 404 // if we were using devfs instead. 405 // Minors are broken up into groups of 128,starting at "001" 406 int bus_id = uevent.minor / 128 + 1; 407 int device_id = uevent.minor % 128 + 1; 408 devpath = StringPrintf("/dev/bus/usb/%03d/%03d",bus_id,device_id); 409 } 410 } else if (StartsWith(uevent.subsystem,"usb")) { 411 // ignore other USB events 412 return; 413 } else { 414 devpath = "/dev/" + Basename(uevent.path); 415 } 416 417 mkdir_recursive(Dirname(devpath),0755); 418 419 HandleDevice(uevent.action,devpath,block,uevent.major,uevent.minor,links); 420} 如上述代码中的system/core/init/devices.cpp:204行进入selinux_android_restorecon函数对该分区下的所有文件(File Object)进行security context标识。selinux_android_restorecon的函数调用流程如下: 1393static int restorecon_sb(const char *pathname,const struct stat *sb,1394 bool nochange,bool verbose,1395 const char *seinfo,uid_t uid) 1396{ 1397 char *secontext = NULL; 1398 char *oldsecontext = NULL; 1399 int rc = 0; 1400 1401 if (selabel_lookup(fc_sehandle,&secontext,pathname,sb->st_mode) < 0) 1402 return 0; /* no match,but not an error */ 1403 1404 if (lgetfilecon(pathname,&oldsecontext) < 0) 1405 goto err; ... 1413 if (!strncmp(pathname,DATA_DATA_PREFIX,sizeof(DATA_DATA_PREFIX)-1) || 1414 !strncmp(pathname,DATA_USER_PREFIX,sizeof(DATA_USER_PREFIX)-1) || 1415 !strncmp(pathname,DATA_USER_DE_PREFIX,sizeof(DATA_USER_DE_PREFIX)-1) || 1416 !fnmatch(EXPAND_USER_PATH,FNM_LEADING_DIR|FNM_PATHNAME) || 1417 !fnmatch(EXPAND_USER_DE_PATH,FNM_LEADING_DIR|FNM_PATHNAME)) { 1418 if (pkgdir_selabel_lookup(pathname,seinfo,uid,&secontext) < 0) 1419 goto err; 1420 } 1421 1422 if (strcmp(oldsecontext,secontext) != 0) { 1423 if (verbose) 1424 selinux_log(SELINUX_INFO,1425 "SELinux: Relabeling %s from %s to %s.n",oldsecontext,secontext); 1426 if (!nochange) { 1427 if (lsetfilecon(pathname,secontext) < 0) 1428 goto err; 1429 } 1430 } ... 1445} 1447#define SYS_PATH "/sys" 1448#define SYS_PREFIX SYS_PATH "/" 1449 1450static int selinux_android_restorecon_common(const char* pathname_orig,1451 const char *seinfo,1452 uid_t uid,1453 unsigned int flags) 1454{ 1455 bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false; 1456 bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false; 1457 bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false; 1458 bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false; 1459 bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false; 1460 bool skipce = (flags & SELINUX_ANDROID_RESTORECON_SKIPCE) ? true : false; 1461 bool cross_filesystems = (flags & SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS) ? true : false; 1462 bool issys; 1463 bool setrestoreconlast = true; 1464 struct stat sb; 1465 struct statfs sfsb; 1466 FTS *fts; 1467 FTSENT *ftsent; 1468 char *pathname = NULL,*pathdnamer = NULL,*pathdname,*pathbname; 1469 char * paths[2] = { NULL,NULL }; 1470 int ftsflags = FTS_NOCHDIR | FTS_PHYSICAL; 1471 int error,sverrno; 1472 char xattr_value[FC_DIGEST_SIZE]; 1473 ssize_t size; 1474 1475 if (!cross_filesystems) { 1476 ftsflags |= FTS_XDEV; 1477 } 1478 1479 if (is_selinux_enabled() <= 0) 1480 return 0; 1481 1482 __selinux_once(fc_once,file_context_init); 1483 1484 if (!fc_sehandle) 1485 return 0; ... 1556 1557 fts = fts_open(paths,ftsflags,NULL); 1558 if (!fts) { 1559 error = -1; 1560 goto cleanup; 1561 } 1562 1563 error = 0; 1564 while ((ftsent = fts_read(fts)) != NULL) { 1565 switch (ftsent->fts_info) { 1566 case FTS_DC: 1567 selinux_log(SELINUX_ERROR,1568 "SELinux: Directory cycle on %s.n",ftsent->fts_path); 1569 errno = ELOOP; 1570 error = -1; 1571 goto out; 1572 case FTS_DP: 1573 continue; 1574 case FTS_DNR: 1575 selinux_log(SELINUX_ERROR,1576 "SELinux: Could not read %s: %s.n",ftsent->fts_path,strerror(errno)); 1577 fts_set(fts,ftsent,FTS_SKIP); 1578 continue; 1579 case FTS_NS: 1580 selinux_log(SELINUX_ERROR,1581 "SELinux: Could not stat %s: %s.n",strerror(errno)); 1582 fts_set(fts,FTS_SKIP); 1583 continue; 1584 case FTS_ERR: 1585 selinux_log(SELINUX_ERROR,1586 "SELinux: Error on %s: %s.n",strerror(errno)); 1587 fts_set(fts,FTS_SKIP); 1588 continue; 1589 case FTS_D: 1590 if (issys && !selabel_partial_match(fc_sehandle,ftsent->fts_path)) { 1591 fts_set(fts,FTS_SKIP); 1592 continue; 1593 } 1594 1595 if (skipce && 1596 (!strncmp(ftsent->fts_path,DATA_SYSTEM_CE_PREFIX,sizeof(DATA_SYSTEM_CE_PREFIX)-1) || 1597 !strncmp(ftsent->fts_path,DATA_MISC_CE_PREFIX,sizeof(DATA_MISC_CE_PREFIX)-1))) { 1598 // Don‘t label anything below this directory. 1599 fts_set(fts,FTS_SKIP); 1600 // but fall through and make sure we label the directory itself 1601 } 1602 1603 if (!datadata && 1604 (!strcmp(ftsent->fts_path,DATA_DATA_PATH) || 1605 !strncmp(ftsent->fts_path,sizeof(DATA_USER_PREFIX)-1) || 1606 !strncmp(ftsent->fts_path,sizeof(DATA_USER_DE_PREFIX)-1) || 1607 !fnmatch(EXPAND_USER_PATH,FNM_LEADING_DIR|FNM_PATHNAME) || 1608 !fnmatch(EXPAND_USER_DE_PATH,FNM_LEADING_DIR|FNM_PATHNAME))) { 1609 // Don‘t label anything below this directory. 1610 fts_set(fts,FTS_SKIP); 1611 // but fall through and make sure we label the directory itself 1612 } 1613 /* fall through */ 1614 default: 1615 error |= restorecon_sb(ftsent->fts_path,ftsent->fts_statp,nochange,verbose,uid); 1616 break; 1617 } 1618 } 1619 1620 // Labeling successful. Mark the top level directory as completed. 1621 if (setrestoreconlast && !nochange && !error) 1622 setxattr(pathname,RESTORECON_LAST,fc_digest,sizeof fc_digest,0); ... 1645} 1646 1647int selinux_android_restorecon(const char *file,unsigned int flags) 1648{ 1649 return selinux_android_restorecon_common(file,NULL,-1,flags); 1650} 由上述代码可以看到,当进入到selinux_android_restorecon函数以后,会通过restorecon_sb=>selabel_lookup=>selabel_lookup_common=>selabel_handle::func_lookup,而selabel_handle::func_lookup被初始化为一个静态函数,其函数定义如下: 894static struct spec *lookup_common(struct selabel_handle *rec,895 const char *key,896 int type,897 bool partial) 898{ 899 struct saved_data *data = (struct saved_data *)rec->data; 900 struct spec *spec_arr = data->spec_arr; 901 int i,rc,file_stem; 902 mode_t mode = (mode_t)type; 903 const char *buf; 904 struct spec *ret = NULL; 905 char *clean_key = NULL; 906 const char *prev_slash,*next_slash; 907 unsigned int sofar = 0; 908 char *sub = NULL; 909 910 if (!data->nspec) { 911 errno = ENOENT; 912 goto finish; 913 } 914 915 /* Remove duplicate slashes */ 916 if ((next_slash = strstr(key,"//"))) { 917 clean_key = (char *) malloc(strlen(key) + 1); 918 if (!clean_key) 919 goto finish; 920 prev_slash = key; 921 while (next_slash) { 922 memcpy(clean_key + sofar,prev_slash,next_slash - prev_slash); 923 sofar += next_slash - prev_slash; 924 prev_slash = next_slash + 1; 925 next_slash = strstr(prev_slash,"//"); 926 } 927 strcpy(clean_key + sofar,prev_slash); 928 key = clean_key; 929 } 930 931 sub = selabel_sub_key(data,key); 932 if (sub) 933 key = sub; 934 935 buf = key; 936 file_stem = find_stem_from_file(data,&buf); 937 mode &= S_IFMT; 938 939 /* 940 * Check for matching specifications in reverse order,so that 941 * the last matching specification is used. 942 */ 943 for (i = data->nspec - 1; i >= 0; i--) { 944 struct spec *spec = &spec_arr[i]; 945 /* if the spec in question matches no stem or has the same 946 * stem as the file AND if the spec in question has no mode 947 * specified or if the mode matches the file mode then we do 948 * a regex check */ 949 if ((spec->stem_id == -1 || spec->stem_id == file_stem) && 950 (!mode || !spec->mode || mode == spec->mode)) { 951 if (compile_regex(data,spec,NULL) < 0) 952 goto finish; 953 if (spec->stem_id == -1) 954 rc = regex_match(spec->regex,partial); 955 else 956 rc = regex_match(spec->regex,buf,partial); 957 if (rc == REGEX_MATCH) { 958 spec->matches++; 959 break; 960 } else if (partial && rc == REGEX_MATCH_PARTIAL) 961 break; 970 } ... 985} 987static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,false); 993 if (spec) 994 return &spec->lr; 995 return NULL; 996} 从上述代码可以看到,对分区内文件(File Object)进行security context标识时,最终会查询selabel_handle::data中的数据,这些数据是之前通过SelabelInitialize函数调用时,遍历系统中的对文件(File Object)的selinux security context定义的file_contxt文件得到结果。最终返回的是file_context文件中为一些文件(File Object)定义的security context(一个字符串)。 在得到这个security context以后,然后通过lsetfilecon调用将这个security context和文件路径相关联。对lsetfilecon的函数定义如下: 10int lsetfilecon_raw(const char *path,const char * context) 11{ 12 int rc = lsetxattr(path,XATTR_NAME_SELINUX,context,strlen(context) + 1,13 0); 14 if (rc < 0 && errno == ENOTSUP) { 15 char * ccontext = NULL; 16 int err = errno; 17 if ((lgetfilecon_raw(path,&ccontext) >= 0) && 18 (strcmp(context,ccontext) == 0)) { 19 rc = 0; 20 } else { 21 errno = err; 22 } 23 freecon(ccontext); 24 } 25 return rc; 26} 27 28hidden_def(lsetfilecon_raw) 29 30int lsetfilecon(const char *path,const char *context) 31{ 32 int ret; 33 char * rcontext; 34 35 if (selinux_trans_to_raw_context(context,&rcontext)) 36 return -1; 37 38 ret = lsetfilecon_raw(path,rcontext); 39 40 freecon(rcontext); 41 42 return ret; 43} 由上述代码可见,最终是通过lsetxattr系统调用进入kernel mode完成了对具体文件的security context的初始化。调用流程如下: 当以该文件作为entry point启动进程时,会以该security id作为新建进程的的security domain id。 至此完成了在系统启动过程中对各个分区中的每个文件(File Object)的security context标识。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |