作为最广为人知的开源项目之一,Linux已经被全世界的成千上万的研究人员进行研究、***、以及打补丁等,并被证明确实是一款安全的、可靠性高的、可信的、稳定的操作系统。因此,Android的操作系统基于Linux内核也就一点也不奇怪了。Android不仅在进程、内存、以及文件系统管理上依赖于Linux,也是Android安全架构的核心组件。在Android操作系统中Linux内核负责应用软件运行时的沙盒环境以及一些权限的管理。
Android沙盒
让我们仔细的考虑下Android应用程序安装过程时的具体细节吧。话说安卓应用程序呀,总是以安卓包(.apk为后缀名)的形式进行发布的。
而这个包呢,由Dalvik可执行文件、资源、本地库文件、以及一个配置文件构成滴,并且呢,会附带有开发者的签名。在Android设备上可以通过三种方法来安装一个应用程序:
1. Google play
2.打包安装程序Packege Installer
3.adb install
Google Play是一个比较特别的应用程序,第三方的开发者们上传到市场中,用户可以通过这个Google Play找到并进行安装。尽管呢,尽管Google Play也是个第三方的应用程序,但是其具有访问Android受保护的组件(因为与Android操作系统具有相同的签名),这是其他三方程序不具备的。如果用户安装的程序是其他的来源呢,就会显示的使用打包安装程序(Packege Installer)了。这个系统程序会为开始安卓包的安装过程提供一个界面。而由安卓提供的adb install,主要是给第三方的开发者使用的。前面的两种方式在安装过程中,需要用户同意一个权限列表,最后的那个方法就是比较低调的进行安装咯,这就是为什么其主要作为开发者的工具了,其目的就是为了在设备上做安装测试滴。安装的过程如图1所示:
图 1 安卓安全架构
图 1 安卓安全架构
这幅图展示了安卓安全架构的更为细节的概况,待会我们解释安卓操作系统特性时还会参阅这张图表。
应用层沙盒在Linux内核中的配置过程是如下的步骤:在应用程序安装时,每一个包都会分配一个唯一的用户ID(UIDS)和一个组ID(GID),并且在设备上永远不会被改变。因此,Android上的每一个应用都有一个对应的Linux 用户(user)。用户名的格式是app_x,并且用户的UID等于Process.FIRST_APPLICATION_UID+x,而Process.FIRST_APPLICATION_UID是一个等于1000的常量。图1中exi.apk包在安装时就分配到了app_1的用户名,其UID就等于1001.
在Linux中,所有的文件都是自主访问策略(DAC)的客体,其对三类用户(文件的拥有者、文件拥有者所在组的用户,以及其他用户)访问权限的控制由文件的创建者或是文件拥有者设定。对于每一类型的用户,都有读、写、可执行(r-w-x)三元组的权限被赋值。如图2所示:
图2 Android的文件访问控制
看第一行最左边的,d表示当前是文件是一个目录,即acct是目录,该文件的拥有者具有读、写、可执行的权限,该文件所在的用户组具有执行的权限,而其他用户具有读、可执行的权限。
因此,只要每一个应用拥有自己的UID和GID,Linux内核就能让其在独立的地址空间内执行。另外,内核使用UID和GID实现各类应用程序所用设备资源的隔离(内存、CPU等)。每一个应用程序在安装时都会有一个home目录,举例来说:/data/data/package_name,其中的package_name就是Android安装包的名字,比如图1中的的com.ex.ex3.就Android而言,这个文件夹被称为内部存储(Internal Storage),被用来存放应用程序的私有数据。Linux仅仅给这个应用程序的拥有者赋予对该目录的读和写的权限。也有些例外需要说明,可能存在拥有同样的认证签名的应用程序能够彼此共享数据,这类程序可能含有相同的UID,或是在同一个进程内运行。图3所示中的是使用ps命令列举的一些进程片段。
图3 ps列举进程片段
最左边的就是应用程序的UID,最右边的是程序的安装包名。
以上的架构在Liinux内核层上建立了一个有用并且高效的应用层沙盒。这种类型的沙盒比较简单,基于Linux的自主访问控制模型。幸运的是,由于Linux内核对沙盒的支撑,本地代码以及操作系统应用程序都受本节所述的约束。
Linux内核层的权限管理
在Linux内核层实现权限控制能够限制Linux用户和组对Android系统资源的访问能力,这种限制可运用于如文件、驱动、套接字类的资源。Android使用文件系统权限(FileSystem Permissions)和Android特有的内核补丁(Paranoid Networking)限制诸如对网络套接字、照相机设备、外部存储器这种底层系统的访问,如读取系统日志啥的。
对文件以及设备驱动使用文件系统权限管理,就能够限制进程对设备的功能的访问。例如,系统中会使用某些机制用来限制程序对照相机设备的访问,/dev/cam设备驱动的拥有者是root,分组为camera,其权限设置的值是0660,这就意味着只有root和camera组的进程对该设备驱动能够具有读和写的权限。权限与组的映射关系定义在/etc/permissions/platform.xml文件中。摘录的部分如下图所示:
图4 权限与组的映射关系
比如说对于READ_LOGS的权限,只有在组“log”中的用户才能访问。在程序安装时,如果该程序申请对日志的权限访问,而用户同意的话,该程序就会赋予给“log”组,即分配该程序“log”的GID。这样,程序就能够读取日志的权限了。在Android中还有设置了文件系统权限管理的还有几处:init程序、init.rc配置文件、ueventd.rc配置文件和系统的ROM配置文件。
在传统的Linux发布版中,所有的进程都能够被允许发起网络连接。而在手机操作系统内对网络的访问能力必须受到限制。为了在Android中实现这样的机制,一类内核补丁被加入到内核中,只允许特定的组有访问网络的权限,这样就对程序网络访问进行了控制。Android系统中这样的补丁被称为Paranoid networking。比如,负责网络连接的套接字AF_INET地址家族,内核就会进行检查,代码是在/kernel/net/ipv4/af_inet.c内,图5给出了代码片段:
图5 创建套接字的代码片段
从代码中可以看出,在创建套接字时,会调用current_has_network函数检查该用户否具有访问网络的权限。
Linux对网络访问权限标签以及用户组的映射也是在platform.xml,代码为:
<permission name="android.permission.NET_ADMIN" >
<group gid="net_admin" />
</permission>
另外,Paranoid networking补丁也实现对IPv6和蓝牙的访问控制。而检查使用的常数,在Linux内核中以硬编码的形式存在,位于 kernel/include/linux/android_aid.h文件中:
#ifndef _LINUX_ANDROID_AID_H
#define _LINUX_ANDROID_AID_H
/* AIDs that the kernel treats differently */
#define AID_NET_BT_ADMIN 3001
#define AID_NET_BT 3002
#define AID_INET 3003
#define AID_NET_RAW 3004
#endif
这个常数其实是AID—Android ID,Android实现的一个补充组,与应用层的用户组存在相应的映射。比如AID_INET与用户组inet映射,AID_SDCARD_RW与用户组SDCARD_RW映射。通过补充组AID,能够授予访问权限。如AID_INET就能打开创建套接字.
在Linux内核层次上权限的检查时判断当前用户是不是在特定的组内,只有在组内的成员才有能力去访问被保护的功能与资源。在程序安装时,如果用户同意程序所需要的权限,应用程序就会被加入到相应的Linux组内,因而,获得改组拥有的访问权限
https://blog.51cto.com/2950319/1586171