前面一节咱们已经讲解了init进程对目录生成和挂载、日志初始化和设置,接下来init进程将初始化SELinux[1]并设置policy文件,以下面代码所示。若要详细了解SELinux的设计原理和工做机制,须要用一整本书来说解,因为篇幅所限,在此咱们不过多涉及这方面的内容。init进程运行在用户空间,主要涉及对SELinux的挂载和配置,下面咱们把重点放在这个过程上。linux
static void selinux_initialize(bool in_kernel_domain) { selinux_callback cb; cb.func_log = selinux_klog_callback; selinux_set_callback(SELINUX_CB_LOG, cb); <---(1) cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); if (in_kernel_domain) { INFO("Loading SELinux policy...\n"); if (selinux_android_load_policy() < 0) { <--- (2) ERROR("failed to load policy: %s\n", strerror(errno)); security_failure(); } bool kernel_enforcing = (security_getenforce() == 1); bool is_enforcing = selinux_is_enforcing(); if (kernel_enforcing != is_enforcing) { <--- (3) if (security_setenforce(is_enforcing)) { ERROR("security_setenforce(%s) failed: %s\n", is_enforcing ? "true" : "false", strerror(errno)); security_failure(); } } if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) { <--- (4) security_failure(); } ... } int main(int argc, char** argv) { ... selinux_initialize(is_first_stage); ... }
(1) selinux_initialize()函数调用selinux_set_callback()函数设置两个全局的回调函数指针“selinux_log”和“selinux_audit”。android
(2) 调用selinux_android_load_policy()[2]函数加载并向内核设置策略,selinux_initialize()函数的主要做用就是从文件中读取SELinux的配置文件,而后把它设置到内核中,这样SELinux才能开始工做。数组
(3) 检查是否强制使用用SELinux,有两种方法能够配置,一是SELinux挂载目录下的enforce文件,其中只有一个数字值表示SELinux的当前状态,0表示不强制使用(permissive[3]),1则表示强制使用(enforcing);其次是/proc/cmdline文件,在其中加入“androidboot.selinux= permissive”字段表示不强制使用(permissive),不然强制使用(enforcing),这种方法主要用于开发或调试版本。安全
(4) 在“/sys/fs/selinux/checkreqprot”文件中写入校验结果,若是写入成功,则SELinux设置完毕,可正常使用。dom
上述代码的(2)所示selinux_android_load_policy()函数是加载SELinux的主要逻辑代码,以下面的代码所示,selinux_android_load_policy()函数尝试将SELinux的虚拟文件系统selinuxfs挂载到“/sys/fs/selinux”节点上,造成下面的图所示的层次结构。函数
rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
若是内核没有启用SELinux,则“/sys/fs/selinux”挂载失败,selinux_android_load_policy()函数继续尝试在根目录下建立“/selinux”节点并挂载,若是再次失败则SELinux初始化失败。工具
在SELinux挂载成功后,调用selinux_android_load_policy_helper()函数装载policy文件。selinux_android_load_policy_helper()函数首先调用set_policy_index()函数设置policy文件的索引,目的是为了打开在sepolicy_file数组中定义的policy文件,而后调用mmap()函数把它映射到内存中,最后调用函数security_load_policy()把policy设置到内核中。policy文件的文件名保存在数组sepolicy_file中,定义以下面的代码所示。测试
static const char *const sepolicy_file[] = { "/sepolicy", "/data/security/current/sepolicy", NULL };
至此,SELinux的初始化就讲解完了。如前一篇鸟人的Android揭秘(10)——Init进程源代码分析(一)所说,init进程将切换到第二阶段的初始化过程。下一节咱们将讲解init进程对属性的初始化和属性服务的启动。.net
[1] SELinux(Security-Enhanced Linux)是由美国国家安全局(NSA)实现的一种基于“域-类型”模型(domain-type)的强制访问控制(MAC)安全系统,在这种访问控制体系的限制下,进程只能访问它的任务中所须要文件。Linux内核在2.6版本中引入了SELinux,并提供一个可定制的安全策略,同时也提供了不少用户层的库和工具。SELinux是目前为止功能最全面、测试最充分的Linux安全模块,相应的某些安全相关的应用也被打了SELinux的补丁。设计
[2] 该函数定义在external/libselinux/src/android.c中。
[3] permissive模式表示即便违反了安全策略,也只是会发出警告,而不会真的拒绝执行。