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标识。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
