在说android selinux之前,我们先来问一个问题,selinux究竟在解决什么问题?
我看到网上文章一上来就是各种概念,却不曾讲本质,任何事物的出现都是在解决问题。首先我们抛开所有安全相关策略,在一个裸内核上来讨论。
没有DAC(linux用户权限系统)的内核系统:
从手机上电启动,arm芯片中的boot程序被加载,它将手机中的uboot引导程序载入内存执行 ,uboot又将linux最小内核载入内存执行,直到小内核将完整的linux内核镜像载入并执行,此时init进程被启动,内核引入虚拟内存管理,将进程映射到不同的物理内存中去,这个时候不同进程是使用不同的物理内存页的。看似进程间的的确确是隔离了内存,但是内存是隔离了,文件系统中的文件呢?一切数据总不能在内存中一直呆着吧,进程总得把数据持久化才有意义吧?而现在所有进程都能通过文件系统访问到所有文件,那我们只要写段程序可以胡乱修改文件了,系统不崩才怪。
引入DAC(linux用户权限系统)的内核系统:
DAC自主访问控制模型,这名词相当别扭,DAC的本质就是引入用户的概念,称为主体,还有客体(文件),操作(读写执行),首先内核提供创建用户接口,并且程序执行期间有了用户概念,操作系统有了在哪个用户环境下执行的感知能力,内核默认会自建一个root身份来启动用户态的一号进程,至于内核要进入其他用户,那就只要创建即可,当切入哪个环境,就以哪个身份执行程序,首先程序在没有运行之前就是一个文件,它在磁盘中保存着,是文件就有规则,它是谁创建的,有哪些权限,所以root用户可以直接启动任意程序,只要授予他执行权限,当程序被载入内存就变成了一个进程,这个进程以什么用户来启动的就标志着它的权限范围由多大。不过只要我保护好root的密码,那么进程我可以通过创建新的用户来启动,这样权限范围就自然缩小了,这解决了上面没有DAC系统带来的所有进程可以修改所有文件的问题,但也带来了新的问题,假如一个程序通过某个漏洞修改了进程的用户,直接进入root身份,那么这个程序就能无法无天了。
引入MAC(selinux)的内核系统:
针对上面DAC没有解决的问题,selinux给出了解决方案,它引入的一套粒度更细的权限系统 ,包含上篇提到的用户、角色、类型、等级,它脱离于DAC的用户系统,给每个文件又标上了一个规则,然后又给进程套上了一把枷锁,也就是哪个进程允许访问哪个文件,事先已经规定好了。比如http_t进程只能访问http_file_t这个类型所对应的目录,它在selinux的用户身份是user_t,http_t进程即使被提权到root用户,此时selinux中的域的身份并未改变还是user_t,它还是无法访问其他文件。
为什么android adb shell 权限很大,因为adb shell 是在adbd域中,为了调试方便,它的selinux权限自然会很大,但并不是为所欲为的,因为它不是dac中的root身份,也不是selinux中的无限制身份。userdebug和eng模式下,adb shell 默认临时关闭selinux,同时它也能切换为dac的root身份,所以他能做几乎所有事。
所以selinux所做的事是将进程套上了一把锁,dac是第一把锁,mac是第二把锁,root提权只开了第一把锁,第二把锁只要没开就是安全的。
android中的selinux
android 的selinux 本质上还是使用的linux内核的selinux,不过在其基础上做了扩展。
在linux selinux中基本的规则是针对文件、端口、套接字的,而android扩展了对binder、server_manager、app进程的支持。
android为什么要扩展呢?直接使用selinux对文件的操作行吗?
如果只针对文件,那么app进程想要使用某个服务,那必然要添加对那个服务进程的文件目录授权,这不乱套了吗?每个进程都直接访问服务进程的文件无疑是危险操作。而android系统中使用某个功能都是跨进程调用服务来实现的。所以android增加了对服务、binder、系统属性的上下文。比如某个系统服务要调用另一个系统服务,那么我只要申明对目标服务的权限即可。而访问目标服务基本都是通过binder实现的,因此能否获取服务又是一个权限。所以android在内核层增加了一些钩子对binder和server_manager的支持。而对于应用,android又内置了几套规则,分别来对应系统应用和普通应用等。应用是未知的,而selinux的规则却是定死的,那必然应用进程在启动后要和对应的规则绑定起来,android系统中有个特殊的上下文配置seapp_contexts,它指定了用什么签名的文件适用哪些规则,这个很特殊的上下文是由zygote进程来处理的,它根据应用的seinfo(签名信息),和uid来将应用进程映射到具体的规则中,这是动态的匹配。
有了上面的特殊扩展就够了吗?那我普通应用要访问相机,就能访问吗?虽然应用selinux中有对camera_service的允许,但直接让它获取,显然是有问题的,下面的工作就是android中另一套权限系统,做android开发的都知道要在清单文件中声明权限,敏感权限还需要动态获取,这都是PMS来授权的。对于camera_service服务,它的selinux规则已经写死,它被允许访问相机,而普通应用在selinux层面允许访问camera_service服务,但是camera_service服务不是随随便便提供服务的,它要去询问pms,这个应用有没有权限访问相机服务,如果有,那么camera_service才会将相机数据通过非特权资源fd方式返回给应用程序,这弥补了android权限中的最后一环。