android 开机启动流程分析(05)SE Android 的解读

    xiaoxiao2022-07-05  186

    该系列文章总纲链接:专题分纲目录 android 开机启动流程分析


    本章关键点总结 & 说明:

    说明:思维导图是基于之前文章不断迭代的,本章内容我们关注➕android SELinux 部分即可

    init中SELinux的源码分析,Android平台中,SEAndroid的初始化由进程的祖先init的main函数完成,相关代码如下所示:

    int main(int argc, char **argv) { ... //说明:init中对SElinux的控制主要依赖于使用了libselinux库(android的SEAndroid库) //向SELinux设置两个回调函数,主要是打印log union selinux_callback cb; cb.func_log = log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); selinux_initialize(); //SELinux初始化 //restore context:就是根据XXX_contexts中的内容给一些目录做labeling{打SELinux标签}。 restorecon("/dev"); restorecon("/dev/socket"); restorecon("/dev/__properties__"); restorecon_recursive("/sys"); ... }

    1 selinux_initialize实现如下:

    static void selinux_initialize(void) { /**判断selinux功能是否启用。方法是: /sys/fs/selinux 是否存在。或者ro.boot.selinux 属性不为disabled */ if (selinux_is_disabled()) { return; } if (selinux_android_load_policy() < 0) {//加载sepolicy文件 ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n"); android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); while (1) { pause(); } // never reached } //初始化file_context,seapp_context及property_context相关内容 selinux_init_all_handles(); /** selinux有两种工作模式, “permissive”:所有操作都被允许(即没有MAC),但是如果有违反权限的话,会记录日志 “enforcing”:所有操作都会进行权限检查 */ bool is_enforcing = selinux_is_enforcing(); //设置SELinux的模式,向"/sys/fs/selinux"/enforce文件中写入is_enforcing值 security_setenforce(is_enforcing); }

    这里关注核心的2个方法,selinux_android_load_policy和selinux_init_all_handles

    1.1 selinux_android_load_policy的实现

    int selinux_android_load_policy(void) { const char *mnt = SELINUXMNT; int rc; //挂载/sys/fs/selinux,SELINUXFS值为"selinuxfs" rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL); ...//rc<0容错处理 /** 说明:/sys/fs/selinux为userpace和kernel中的SELinux模块交互的通道 */ set_selinuxmnt(mnt); return selinux_android_load_policy_helper(false); }

    继续分析selinux_android_load_policy_helper的实现,如下: 

    static int selinux_android_load_policy_helper(bool reload) { int fd = -1, rc; struct stat sb; void *map = NULL; ...//根据文件存在与否确定policy_index的值 //根据policy_index的不同0/1来确定,注意sepolicy文件的位置: /data/security/current/sepolicy:自定义的策略文件一般放在这里,init优先使用它。 /sepolicy:root根目录下的sepolicy:如果data目录下没有sepolicy,则使用系统默认的sepolicy。 fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW); ... fstat(fd, &sb); ... map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); //这里通过mmap的方式,将sepolicy文件映射到map中 ... //该函数由selinux.h定义,它将此map、即sepolicy文件加载到内核中 rc = security_load_policy(map, sb.st_size); ... munmap(map, sb.st_size); close(fd); return 0; }

    特殊说明:

    libselinux库通过操作/sys/fs/selinux下的文件来完成和Kernel中SELinux模块的交互。 同时将sepolicy文件传递给Kernel,这样Kernel就有了安全策略配置文件,后续的MAC才能开展起来。

    1.2 selinux_init_all_handles的实现如下:

    /** 创建两个handler,主要为后续做labeling{打SELinux的系统标签}控制 通过调用libselinux的函数来打开前面分析file_contexts和property_contexts文件 以便可以用来查询系统文件和系统属性的安全上下文。 */ void selinux_init_all_handles(void) { sehandle = selinux_android_file_context_handle();//文件上下文handle selinux_android_set_sehandle(sehandle); sehandle_prop = selinux_android_prop_context_handle();//属性上下文handle }

     restorecon分析如下:

    static int selinux_android_restorecon_common(...){ if (is_selinux_enabled() <= 0) return 0; ... return restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid); //->最后会调用lsetfilecon->核心就是调用lsetxattr来设置文件系统属性 } }

    2 property权限检查的分析

    /** 在init的handle_property_set_fd中获取property_set发送的消息 处理时会执行check_perms或check_control_mac_perms,2个方法最后都会调用check_mac_perms 因此属性服务设置的SELinux权限检测是在init中,方法check_mac_perms的实现如下: */ static int check_mac_perms(const char *name, char *sctx) { if (is_selinux_enabled() <= 0) return 1; ...//容错处理 //检查property_context中是否定义了目标SContext,即tctx。 if (selabel_lookup(sehandle_prop, &tctx, name, 1) != 0) goto err; /** 将源SContext和目标SContext进行比较,判断是否有相关权限。 name是属性的名字 源SContext是调用setprop进程的SContext。调用setprop的进程的SContext 目标SContext是property_context文件中定义的SContext。不同的属性有不同的SContext 操作名称(perm,由access vector定义。对Property这种Object class而言,其唯一需要做权限检查的操作就是set。 要检查的Object class(系统所支持的类在external/sepolicy/security_classes文件中定义, 参考external/sepolicy/access_vectors这个文件)。 具体的哪一个属性(name参数指定,就是具体指明哪一文件)。 */ if (selinux_check_access(sctx, tctx, class, perm, (void*) name) == 0) result = 1; freecon(tctx); err: return result; }

     说明:这里仅仅是从init中的代码来分析SELinux的机制,实际上SElinux也要专门开一个专题来讲才会清楚。目前这里仅作简介

    最新回复(0)