鸟人的Android揭秘(11)——Init进程源代码分析(二)

      前面一节我们已经讲解了init进程对目录生成和挂载、日志初始化和设置,接下来init进程将初始化SELinux[1]并设置policy文件,如下面代码所示。若要详细了解SELinux的设计原理和工作机制,需要用一整本书来讲解,由于篇幅所限,在此我们不过多涉及这方面的内容。init进程运行在用户空间,主要涉及对SELinux的挂载和配置,下面我们把重点放在这个过程上。

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”。

(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设置完毕,可正常使用。

      上述代码的(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进程对属性的初始化和属性服务的启动。

 

[1] SELinux(Security-Enhanced Linux)是由美国国家安全局(NSA)实现的一种基于“域-类型”模型(domain-type)的强制访问控制(MAC)安全系统,在这种访问控制体系的限制下,进程只能访问它的任务中所需要文件。Linux内核在2.6版本中引入了SELinux,并提供一个可定制的安全策略,同时也提供了很多用户层的库和工具。SELinux是目前为止功能最全面、测试最充分的Linux安全模块,相应的某些安全相关的应用也被打了SELinux的补丁。

[2] 该函数定义在external/libselinux/src/android.c中。

[3] permissive模式表示即使违反了安全策略,也只是会发出警告,而不会真的拒绝执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值