安全策略基本概念
首先看一张Linux权限检测流程图
如图所示:Linux系统先做DAC检查。如果没有通过DAC权限检查,则操作直接失败。通过DAC检查之后,再做MAC权限检查。
DAC:全称是Discretionary Access Control,翻译为自主访问控制。即普通的 owner:group:other 文件权限机制。
MAC:强制访问控制,SELinux就是一种MAC机制。任何进程想在SELinux系统中干任何事情,都必须先在安全策略配置文件中赋予权限。凡是没有出现在安全策略配置文件中的权限,进程就没有该权限。
SELinux中也有用户的概念,但它和Linux中原有的user概念不是同一个东西。什么意思呢?比如,Linux中的超级用户root在SELinux中可能就是一个没权限,没地位,打打酱油的”路人甲“。当然,这一切都由SELinux安全策略的制定者来决定。
SELinux System Property 语法
Security Context:
SELinux中,每种东西都会被赋予一个安全属性,官方说法叫Security Context。Security Context是一个字符串,查看命令:文件–> ls -Z 进程–>ps -Z
根据SELinux规范,完整的Security Context字符串,主要由三部分组成,格式如下:
user:role:type[:range]
方括号中的内容表示可选项。s0属于range中的一部分,如:
u:r:init:s0
- u为user的意思。SEAndroid中定义了一个SELinux用户,值为u。
- r为role的意思。role是角色之意,它是SELinux中一种比较高层次,更方便的权限管理思路,简单点说,一个u可以属于多个role,不同的role具有不同的权限。另外文件为死的东西,无法扮演角色,所以通常用object_r来表示它的role。
- init,代表该进程所属的Domain,也可叫type为init。另外文件通常设置type为rootfs
- s0是SELinux为了满足军用和教育行业而设计的Multi-Level Security(MLS)机制。简单点说,MLS将系统的进程和文件进行了分级,不同级别的资源需要对应级别的进程才能访问。
te介绍:
te,即安全策略配置文件。是SELinux权限管理的核心。通常可以在如下路径找到他们:
- device/xx/sepolicy/ xx.te
- external/selinux/sepolicy/ xx.te
- system/sepolicy
根据SELinux规范,定义一条完整的配置,语句格式为:
rule_name source_type target_type:object_class perm_set
rule_name
可用选项:
allow:允许
neverallow:绝不允许,没有声明权限时默认就没有权限。原理上neverallow语句没必要存在,但可以起到限制allow的作用。
allowaudit:记录某项操作,
dontaudit:忽略某项操作。
object_class
需要通过class语句申明,这些申明一般放在一个叫security_class的文件中,class和kernel中相关模块紧密结合。
file-related classes
class filesystem
class file #代表普通文件
class dir #代表目录
class fd #代表文件描述符
class lnk_file #代表链接文件
class chr_file #代表字符设备文件
……
network-related classes
class socket #socket
class tcp_socket
class udp_socket
……
Android平台特有的class
class binder
class zygote
class property_service #userspace和用户空间中的SELinux权限检查有关
Perm set
Perm set指的是某种Object class所拥有的操作。SELinux规范中,定义perm set有两种方式,一种是使用下面的common命令,其格式为:
common common_name { permission_name ... }
common定义的perm set能被另外一种perm set命令class所继承
以下是Android平台中,file对应的权限(perm set)。
common file {ioctl read write create getattr setattr lock relabelfrom relabelto append unlink link rename execute swapon quotaon mounton }
除了common外,还有一种class命令也可定义perm set,语法为:
class class_name [ inherits common_name ] { permission_name ... }
如下面的例子:
class dir inherits file { add_name remove_name reparent search rmdir open audit_access execmod }
inherits表示继承了某个common定义的权限,但它不能被其他class继承。
type
type定义命令的完整格式为
type type_id [alias alias_id,] [attribute_id]
其中,方括号中的内容为可选。alias指定了type的别名,可以指定多个别名。下面这个例子定义了一个名为shell的type,它和一个名为domain的属性(attribute)关联。
type shell, domain; #本例来自shell.te
可理解为shell为domain的一员。
属性由attribute关键字定义,如attributes文件中定义的SEAndroid使用的属性有:
attribute domain; attribute file_type;
另外,可以关联多个attribute:
type shell, domain; type shell, file_type;
案例:
allow netd proc:file write;
允许netd域中的进程向proc type的file进行写操作。
allow zygote init:process sigchld;
允许zygote域中的进程向init type的进程(Object Class为process)发送sigchld信号
allow zygote appdomain:dir { getattr search };
允许zygote域中的进程search或getattr类型为appdomain的dir。注意,多个perm_set可用{}括起来
allow from_role_id to_role_id;
允许from_role_id切换到to_role_id。
allow unconfineddomain {fs_type dev_type file_type}:{ chr_file file } ~{entrypoint relabelto};
perm_set语法比较奇特,前面有一个~号。它表示除了{entrypoint relabelto}之外,{chr_file file}这两个object_class拥有的其他所有操作。
-号表示去除某项内容。
*号表示所有内容。
实现基于Role或User的权限控制
SELinux提供了一个新的关键词,叫constrain,constrain标准格式为
constrain object_classs perm_set expression ;
下面这句话表示只有source和target的user相同,并且role也相同,才允许进行写操作。
constrain file write (u1 == u2 and r1 == r2);
SELinux中,设置或分配SContext给进程或文件的工作叫Security Labeling
如何确认问题是否与SELinux有关
注意:在 USER 版本中无法设置!如需在USER版中设置,转到源码中设置。
ENG 版本设置方法:
adb shell setenforce 0 //设置成 permissive 模式 adb shell setenforce 1 //设置成 enforce 模式
如果设置成 permissive 模式还能复现问题,则与 SELinux 无关, 如果原本很容易复现, 而 Permissive mode 不能再复现, 那么就可能关系比较大,使用
adb shell getenforce
可以确认SELinux模式。
在 Kernel LOG / Main Log 中查询关键字 “avc”,看看是否有 SELinux Policy Exception, 并进一
步确认这个异常是否与当时的逻辑相关
源码中设置
开机设置 SELinux 模式
bootable/bootloader/lk/platform/mt6xxx/rules.mk更新配置
# choose one of following value -> 1: disabled/ 2: permissive /3: enforcing SELINUX_STATUS := 3
可直接调整这个 SELINUX_STATUS 这个的值为 2 或者 1
允许 USER 版本 disable SELinux
修改 system/core/init/Android.mk 新增
ifeq ($(strip $(TARGET_BUILD_VARIANT)),user) LOCAL_CFLAGS += -DALLOW_DISABLE_SELINUX=1 endif
LOG分析及调试
SELinux Policy Exception Log 格式:
SELinux Policy Exception 的 LOG 关键字是 “avc: denied” 或者 “avc: denied”, 下面就是一句
典型的 LOG:
<5>[ 27.706805] (3) [304:logd.auditd] type=1400 audit(1420041991.220:17): avc: denied { execute } for pid=2182 comm=”app_process” path=”/data/dalvik-cache/arm64/system@framework@boot.oat” dev=”mmcblk0p18″ ino=15109 scontext=u:r:root_channel:s0 tcontext=u:object_r:dalvikcache_data_file:s0 tclass=file permissive=0
具体说明如下:
[ 27.706805] : kernel time
(3) : cpu number
[304:logd.auditd] : 表示此 LOG 是通过 auditd 打印的.
type=1400 : SYSCALL
type=AVC – for kernel events
type=USER_AVC – for user-space object manager events
audit(1420041991.220:17) : audit(time:serial_number)
avc: denied { execute } : field depend on what type of event is being audited.
pid=2182 comm=”app_process” : If a task, then log the process id (pid) and the name of the executable file (comm).
path=”/data/dalvik-cache/arm64/system@framework@boot.oat” dev=”mmcblk0p18″ ino=15109: The information of target.
subject context : u:r:root_channel:s0
target context : u:object_r:dalvikcache_data_file:s0
tclass : the object class of the target class=system
permissive: permissive (1) or enforcing (0)
基本分析流程
- 将 SELinux 调到 permissive mode, 然后一次性抓取出所有的”avc:” 的 LOG.
* 如果问题与开机流程无关, 并且 eng 版本能够复现.
adb shell setenforce 0
* 如果问题与开机流程相关, 或者只有 user build 能够复现. 按下列 FAQ 设置 permissive mode - 确认访问是否是必须的?是否是违法恶意访问?
- 如果是正常访问, 确认访问的目标类型是否太过广泛,如果太过广泛, 细化具体的文件目标。
- 添加对应的 SELinux Policy 到对应的 Policy 文件。
- 如果是违法恶意访问, 追查上层 feature owner 的责任。
验证 SELinux Policy 问题
快速编译测试.
在已经编译过的版本上, 首先编译出新的 selinux policy, 然后打包 boot image.
KK:
./mk project_name mm external/sepolicy ./mk project_name bootimage
L:
source build/envsetup.sh lunch XXX mmm system/sepolicy make -j8 ramdisk-nodeps make -j8 bootimage-nodeps
然后再重新刷 bootimage 测试.
或者使用
source build/envsetup.sh lunch XXX mma system/sepolicy
然后使用adb push sepolicy规则:
#添加到 tct_sepolicy 目录的 selinux 规则: adb push out/target/product/project/vendor/etc/selinux/ /vendor/etc/ #添加到 plat_public,plat_private 目录的 selinux 规则: adb push out/target/product/project/system/etc/selinux/ /system/etc/ #同时添加了 selinux 规则到 tct_sepolicy 目录以及另外两个目录: adb push out/target/product/project/vendor/etc/selinux/ /vendor/etc/ adb push out/target/product/project/system/etc/selinux/ /system/etc/
注意: 如果更新了 file_contexts, 给 system 下面的文件重新设置了 SELinux Label, 那么你需要将 system image 重新打包, 不然不会起到作用.
make -j8 snod