引言
由于目前关于SE for Android的介绍相对比较缺泛,因此本文的主要目的就是对整个SE for Android进行详细的介绍,同时可以作为相关工具、命令行、策略构建工具以为策略文件格式的使用说明书。
术语
先了解一下三个重要的术语,分别是SE for Android、AOSP和SEAndroid。
SE for Android | 用于描述整套SELinux mandatory accss control(MAC)以及Middle-ware mandatory access control(MMAC)在Android上的实现。 |
AOSP | AOSP即是指Android的源码版本,其下载地址为Google分布(http://source.android.com/source/downloading.html),其中从Release 4.3开始,AOSP源码已经包含SELinux的支持,相关的说明见http://source.android.com/devices/tech/security/se-linux.html。 AOSP中包含SELinux MAC的核心功能以及一些简单的策略,系统上所有的进程domains都是unconfined的状态。而且Install MMAC框架和策略也没有添加过多的限制,详情可以查看“所支持的MAC服务”一节的内容。 AOSP的原则是所有的第三方应用都是平等对待,这意味着第三方的应用不能运行在不同的domains中,也无法为其单独配置MAC/MMAC策略。AOSP只对系统应用进行策略限制。 |
SEAndroid | SEAndroid就是指在AOSP发行版本的基础上添加了一系列功能之后的版本(相当于是SELinux的功能加强版),这些功能如下所列: a) 安全加强的MAC策略,以保证所有进程的domain都是被定义,同时SELinux的默认模式是enfocing; b) 安全加强的MMAC策略; c) 增加了Intent MMAC的支持; d) 增加了Content Provider MMAC的支持; e) 增加了Revoke permissioin(权限吊销) MMAC的支持;
这些功能的详细描述,见“所支持MAC服务”一节
|
SE for Android的项目编译
一共有5种不同的SE for Android的项目构建方式,分别是:
1) 标准的AOSP版本(从4.3版开始),这个版本不需要额外的代码补充,其他四种方式都需要从 https://bitbucket.org/seandroid/manifests获取额外的代码;
2) git checkout master——包含安全加强的SELinux MAC + 安全加强的Intall MMAC;
3) git checkout intent_mac——包含安全加强的SELinux MAC + 安全加强的Intall MMAC + Intent MMAC;
4) git checkout cp_mac ——包含安全加强的SELinux MAC + 安全加强的Intall MMAC + Intent MMAC + Content Provider MMAC;
5) git checkout revoke-perms——包含安全加强的SELinux MAC + 安全加强的Intall MMAC + Revoke permissions策略;
Android源码的git地址是https://android.googlesource.com,SEAndroid enhancements的git地址是https://bibucket.org/seandroid.
有用的链接
关于如何实现和测试集成了SELinux功能的AOSP发行版本:http://source.android.com/devices/tech/security/se-linux.html
关于目前SEforAndroid与跟AOSP的合并情况、如何获取代码、如何安装、有哪些功能: http://selinuxproject.org/page/SEforAndroid
Security Enhanced (SE) Android: Bringing Flexible MAC to Android : http://www.internetsociety.org/sites/default/files/02_4.pdf (强烈推荐阅读)
关于三星的"KNOX"的详细介绍:http://www.samsung.com/global/business/business-images/resource/white-paper/2013/05/Samsung_KNOX_whitepaper_April2013_v1.1-0.pdf
接下来的章节将包含下列内容
- MAC和Middleware MAC的介绍
- 为了支持MAC功能,Android源码上的变化
- 增加kernel LSM/SELinux的支持
- 与SE for Android功能相关的Classes & Permissions
- 为支持SE for Android所增加的SELinux命令和方法
- init为支持SELinux的扩展
- 策略构建和编译
- 编译文件的位置
-
- 策略布尔值
-
- 策略配置文件
-
- Install / run time MMAC 配置文件
-
- Intent MMAC配置文件
-
- Content Provider MMAC配置文件
-
- Revoke permissions MMAC配置文件
- 日志和审计
- libselinux添加的函数
所支持的MAC服务
MAC和MMAC功能概述:
- 标准的SELinux MAC 策略是基于type enforcement(TE,即类型强制访问)/ multi-level security (MLS,即多级别安全机制),也可以理解为是一种白名单机制;
- Install MMAC策略中的package和signature标签支持通过setinfo标签,来指定应用的context(安全上下文,指运行时domain)。该策略只对预装应用生效,而第三方的应用则无法通过这种方式指定,所有的第三方应用都只能由<default>标签匹配,而且seinfo的值为“default”。(译者注,这里会让你看得头晕,建议找到mac_permissions.xml文件对着看)
- SEAndroid Install MMAC策略还能能够检查应用所申请的权限列表是否被允许。如果不允许,那么该应用就不能够安装。另外如果这款应用已经安装在手机上了,后来策略更新并与其产生冲突了,那么这款应用也不能运行。配置文件允许的动作有:allow(允许),deny(拒绝)和allow all permissions(允许所有权限)。 检查流程如下:
- 安装或升级第三方应用时,它的权限列表都被会检查。如果在<default>里存在任意一项不被允许的权限,那么该应用安装或升级过程就会失败;
- 预装的应用,他们的升级过程,系统也会去做一次权限检查。如果在package或者signature标签存在不允许的权限,更升级失败。如果存在某个权限,在package或者signature标签中没有显式声明为allow,而在default标签中声明为deny的话,升级过程同样会失败;
- SEAndroid Install MMAC策略还能能够检查应用所申请的权限列表是否被允许。如果不允许,那么该应用就不能够安装。另外如果这款应用已经安装在手机上了,后来策略更新并与其产生冲突了,那么这款应用也不能运行。配置文件允许的动作有:allow(允许),deny(拒绝)和allow all permissions(允许所有权限)。 检查流程如下:
- Intent MMAC策略的作用是决定Intent是否能够被分发到其他几种组件。策略会屏蔽掉所有没有被定义为允许的Intent分发。这是一个可选的策略,并不需要定制的SELinux策略支持,不过它可以对“主体”的安全上下文进行合法性校验。
- Content Provider MMAC策略作用是决定content provider的访问请求是否被允许。策略会屏蔽掉所有没有被定义为允许的访问请求。目前的版本支持use, read, read/write三种权限。这是一个可选的策略,并不需要定制的SELinux策略支持。
- Revoke permissions策略的作用是决定权限在运行过程中是否会被检查,如果权限被撤消了那么权限就会变成denied状态(也就是说,除了指定的权限会被变成denied,其他的权限都是允许的)。这是一个可选的策略,并不需要定制的SELinux策略支持。
Android为支持MAC所引入的变化
SE for Android为Android的内核增加了SELinux的支持,同时在用户空间也实现了如下几方面的目标:
- 定义所有具有特权守护进程,以防止权限被滥用以及把它们的破坏降到最低;
- 构造沙箱,使应用与应用和系统之间互相隔离;
- 防止应用提权;
- 利用MMAC策略,使应用的权限在安装和运行的过程中变得可控;
- 提供一种集中的、可分析的策略;
- 实现了yaffs2文件系统的安全标注;
- 文件系统镜像文件(yaffs2和ext4)编译时标注;
- 为recovery console和程序更新器提供标注功能;
- 基于内核的Binder IPC权限检测;
- 实现对由init进程所产生的服务端套接字(service sockets)和本地套接字文件(socket files)的标注功能;
- 实现对由ueventd进程所产生的设备节点(device nodes)的标注功能;
- 为应用和应用数据文件夹提供灵活易配置的标注功能;
- 最小化SELinux用户空间的可用端口;
- 提供了JNI方式的SELinux接口;
- 为Zygote socket commands的使用提供了用户空间级别的权限检查;
- 为Android properties的使用提供了用户空间级别的权限检查;
- 专门针对Android编写了TE策略文件;
- 为所有系统服务和应用定义domain;
- 利用MLS类别隔离应用;
- external/libselinux
提供了SELinux用户空间的函数库并集成到设备上。该库在原版本的基本上为适应Android而增加了一列的函数,如下所示:
- selinux_android_setcontext
利用这个函数可以为应用设置正确的domain上下文,它会利用保存在seapp_contexts文件里的信息计算出正确的上下文。如果是在初始化阶段,这个函数也会调用selinux_android_seapp_context_reload加载seapp_contexts文件并对里面的每一项进行排序,详细过程见"seapp_contexts文件"一节。
该函数会被dalvik/vm/native/dalvik-system-Zygote.cpp和system/core/run-as/run-as.c调用。
- selinux_android_setfilecon2
利用这个函数可以为应用文件夹和文件设置正常的上下文,它会利用保存在seapp_contexts文件里的信息计算出正确的上下文。如果是在初始化阶段,这个函数也会调用selinux_android_seapp_context_reload加载seapp_contexts文件并对里面的每一项进行排序,详细过程见"seapp_contexts文件"一节。当安装应用时,该函数会被frameworks/base/cmds/installd/commands.c调用。
- selinux_android_restorecon
利用这个函数可以让文件的上下文恢复成file_contexts文件里初始配置。该函数在初始经和安装等过程过程中会被多处调用。
- selinux_android_load_policy
如果SELinux是开启的话,利用该函数可以加载SELinux文件系统,并通过调用selinux_android_reload_policy把策略文件加载到内核。
- selinux_android_reload_policy
加载策略文件进内核。该函数会被system/core/init.c调用。
- external/libsepol
提供了用户空间的策略工具库。这部分代码跟SELinux是一样的,而且不会集成到设备上。
- external/checkpolicy
提供了策略构造工具。这部分代码跟SELinux是一样的,而且也不会集成到设备上(因此策略的构造必须在主机开发环境中进行)。
- external/sepolicy
这个SE for Android特有的部分,里面包含各种策略模块(*.te文件),class/permissoin文件等等。所有策略模块依据Android.mk文件进行构造的,最终会连同其他配置文件(file_contexts, seapp_contexts和property_contexts)一起集成到设备上(编译成sepolicy文件)。也有一些工具可以根据不同的设备进行策略补充,这部分会在“策略构建”一节详细描述。策略文件的在“SELinux MAC配置文件”一节进行详细描述。相关的工具也会在“策略构建工具”一节有详细的描述。这里也包含了关于SE for Android的类定义,详细可以查看“SE for Android 的类和权限”一节。这个文件夹也包含了Install MMAC、Intent MMAC、Content Permission MMAC策略,如果有配置的话,请参考“ SE for Android 系列之整体概要(一)”中的“ SE for Android的项目编译”一节。
- external/mac-policy
这里包含revoke permission的策略配置文件(revoke_permission.xml),利用这种策略可以让Android的权限动态撤消。 如果项目选项选择revoke_perms的话,就会包含这个文件夹。
- build
针对SE for Android进行修改。
- dalvik
当进程被fork后,会使用selinux_android_setcontext进行domain上下文设置。
- libcore
Zygote.java里添加了setInfo和niceName两种传入参数(译者注,应该是zygote command命令里添加了--setInfo和--niceName两种配置)
- frameworks/base
- JNI——添加了SELlinux的函数支持,如isSELinuxEnabled和setFSCreateCon。
- SELinux 的Java类和方法的定义。
- Zygote连接者的安全上下文检查。
- 为package manager和各种service提供文件权限的管理(译者注,这里不太明白)
- 添加MMAC框架
- system/core
- 支持SELinux的toolbox,比如load_policy, runcon
- 支持SELinux的系统初始化,比如init,init.rc
- 支持SELinux的核审服务(audittd)
- system/extras
支持SELinux的ext4文件系统
- kernel
已经有多个内核增加了LSM和SELinux支持,详细可以查看SEforAndroid - Building for a Device.Android的内核存在多个版本(目前是3.4,模拟器使用的是Goldfish),因此最新版本的SELinux一般还没有集成到SEforAndroid。在“内核LSM和SELinux的支持”一节里,会详细说明内核的变化。
- device
关于支持设备的详情情况,可以查看SEforAndroid - Building for a Device
可以修改设备的配置文件定制策略文件,详细见“构建策略文件”一节
内核LSM和SELinux的支持
文章 Security Enhanced (SE) Android: Bringing Flexible MAC to Android对内核的修改情况做了很好的描述,下面主要讲一下为支持Binder IPC服务所作的变化:
- Linux安全模块(LSM)在binder驱动代码(drivers/staging/android/binder.c和include/linux/security.h)添加了钩子逻辑;
- 在没有其他模块的情况下,默认支持能力("capabilities")(security/capability.c);
- LSM安全模块添加了钩子逻辑;
- 对显示在“SE for Android的类别和权限”一节中所列的客体类别和权限提供支持(security/selinux/include/classmap.h);
binder 类别 - 这是管理内核Binder IPC服务的客体类别 | |
权限 | 描述 |
call | 通过IPC方式访问一个指定的进程(A能否访问B?)。 |
impersonate | 接管IPC通讯(A能否接管B的IPC通讯?)。 目前策略还没有使用,但selinux_binder_transaction调用时内核有做检查。 |
set_context_mgr | 把自身注册成Binder Context Manager。如果A能为把B设置为context manager,就意味着A==B。参考策略文件servicemanager.te |
transfer | 传递binder引用给其他进程 (A能否把binder引用传递给B?)。 |
zygote 类别 – 这是用户空间的客体类别,管理Android应用的装载。参考SELinux.checkSELinuxAccess. In ZygoteConnection.java | |
权限 | 描述 |
specifyids | 指定应用的uid或者gid |
specifyrlimits | 指定应用的资源限制 |
specifycapabilities | 指定应用的capabilities |
specifyinvokewith | 指定应用要使用--invoke-with启动Zygote,这是一种包装命令的使用方式 |
specifyseinfo | 指定seinfo标签决定应用的安全上下文 |
property_service 类别 – 这是用户空间的类别,用于管理Android Property Service | |
权限 | 描述 |
set | 设置一个属性 |
SELinux命令行
命令 | 注释 |
chcon | 修改文件的安全上下文. 只支持第一部分的chcon(1)功能 (目前仅支持context pathname的格式). chcon context pathname |
getenforce | 获取当前的工作模式 getenforce |
getsebool | Get SELinux boolean value(s): getsebool [-a | boolean] |
id | 不带任意选项,如果开启了SELinux,那么安全上下文的信息就会自动显示 |
load_policy | 把新策略加载入内核 load_policy policy-file |
ls | 支持通过-Z选项显示安全上下文信息 |
restorecon | 按file_contexts文件的策略恢复文件的安全上下文。与restorecon(8)相比,有部分选项不支持restorecon [-nrRv] pathname |
runcon | 以指定的安全上下文件运行命令runcon context program args... |
setenforce | 修改SELinux的工作模式setenforce [enforcing|permissive|1|0] |
setsebool | 修改SELinux布尔值(需要注意,这种修改重启后失效)setsebool name [1|true|on|0|false|off] |
boolean isSELinuxEnabled() 获取SELinux开启状态 如果上开启状态,则返回true |
boolean isSELinuxEnforced() 判断SELinux是否处于permissive或enforcing模式 如果是enforcing模式,则返回true |
boolean setSELinuxEnforce(boolean value) 设置SELinux的工作模式(permissive或者enforcing) value为true表示enforcing模式 设置成功返回true |
boolean setFSCreateContext(String context) 设置新建文件对象的安全上下文 context为被指定安全上下文 设置成功返回true |
boolean setFileContext(String path, String context) 修改现有文件的安全上下文 path是被修改的文件路径 context为被指定的安全上下文 设置成功返回true |
String getFileContext(String path) 获取文件的安全上下文 path 文件路径. 返回文件的安全上下文件字符串或者null |
String getPeerContext(FileDescriptor fd) 获取本地socket的安全上下文 FileDescriptor是socket所绑定的文件 返回socket上下文件字符串或者null |
String getContext() 获取当前进程的安全上下文 返回当前进程的安全上下文或者null |
String getPidContext(int pid) 获取指定pid的进程安全上下文 pid 进程pid 返回进程的安全上下文或者null |
String[] getBooleanNames() 获取SELinux的布尔值键名列表 返回包含所有SELinux布尔值键名的字符串数组 |
boolean getBooleanValue(String name) 获取指定键名的布尔值 name 键名. 返回true或false |
boolean setBooleanValue(String name, boolean value) 根据键名设置布尔值。需要注意,重启后会失效。 name 键名 value 重的布尔值 操作成功返回true |
boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm) 判断两个安全上下文之间指定的权限是否被允许 scon 源或宾体安全上下文 tcon 目标或客体安全上下文 tclass 客体类别名称 perm 权限名称 权限允许则返回true |
boolean restorecon(String pathname) 恢复文件为默认的安全上下文。如果系统没有包含SElinux或者处于关闭状态,都会自动返回true pathname 文件路径 操作成功则返回true 如果pathname为null会抛NullPointerException异常 |
boolean restorecon(File file) 恢复文件为默认的安全上下文。如果系统没有包含SElinux或者处于关闭状态,都会自动返回true file 文件对象. 操作成功则返回true 如果file为null会抛NullPointerException异常 |
seclabel <securitycontext> 在服务在运行之前修改其安全上下文,主要用在位于rootfs分区的服务,比如ueventd, adbd。而位于system分区的服务,则可以通过transitions规则进行修改,如果没有指定transition规则,那么默认就是init context |
restorecon <path> 根据file_contexts的配置恢复指定路径的文件安全上下文. |
setcon <securitycontext> 设置当前进程的安全上下文。这一般用在early-init里设置init进程的安全上下文用的(见下面使用示例)。 |
setenforce 0|1 设置SELinux工作模式. 0 代表 permissive , 1 代表 enforcing。 |
setsebool <name> <value> 设置SELinux的布尔值 <value> 可以是 1|true|on 或者 0|false|off |
使用示例见下面init文件的片断:
# system/core/rootdir/init.rc ... on early-init # Set init and its forked children's oom_adj. write /proc/1/oom_adj -16 # Set the security context for the init process. # This should occur before anything else (e.g. ueventd) is started. setcon u:r:init:s0 start ueventd ... on boot ... service ueventd /sbin/ueventd class core critical seclabel u:r:ueventd:s0
# device/generic/goldfish/init.goldfish.rc ... on boot setsebool in_qemu 1 restorecon /sys/qemu_trace/process_name restorecon /sys/qemu_trace/state restorecon /sys/qemu_trace/symbol ...