SEAndroid&SELinux
SELinux
SELinux则是由NSA(美国国安局)在Linux社区的帮助下设计的一个针对Linux的安全强化系统。
在LinuxKernel中,SELinux通过LSM(LinuxSecurity Modules)实现.
SELinux是一种基于域-类型(domain-type)模型的强制访问控制(MAC)安全系统。
-
自主访问控制模型(Discretionary Access Control,DAC)、
进程理论上所拥有的权限与运行它的用户权限相同。比如,以root用户启动shell,那么shell就有root用户的权限 -
强制访问控制模型(Mandatory Access Control,MAC).
任何进程想在SELinux系统中干任何事,都必须先在安全策略的配置文件中赋予权限。凡是没有在安全策略中配置的权限,进程就没有该项操作的权限。
SEAndroid
SEAndroid是Google在Android4.4上正式推出的一套以SELinux为核心的系统安全机制。
image.png
1)LSM提供了一种通用的安全框架,允许将安全模型以模块方式载入内核,
2)AVC是一个策略缓存,当进程试图访问系统资源的时候,kernel中的安全策略服务将会先在AVC中查找策略,如果没有命中,则会到安全服务器中查找,找到了,则权限被缓存,允许访问,如果没找到,则拒绝访问;
3)SecurityPolicy描述系统资源的安全访问策略,系统启动时init进程负责把策略文件加载到内核的LSM模块中;
4)SecurityContext描述系统资源的安全上下文,SELinux的安全访问策略就是在安全上下文的基础上实现的;
5)libselinux为用户空间提供了SELinux文件系统访问接口;
sepolicy中的所有相关文件整合成一个源文件plicy.conf,然后通过checkpolicy 编译器将policy.conf策略源文件编译成root/sepolicy的二进制策略文件,编译完成的二进制策略文件会在系统启动时被加载到内核中在权限检测时使用
模式切换
SELinux支持Disabled,Permissive,Enforce三种模式;
# getenforce
Enforcing
Disabled,此时SELinux的权限检查机制处于关闭状态;
Permissive模式就是SELinux有效,但是即使你违反了它的安全策略,它让你继续运行,但是会把你违反的内容记录下来。在策略开发的时候非常有用,相当于Debug模式;
Enforce模式就是你违反了安全策略的话,就无法继续操作下去。
# setenforce 0
# getenforce
Permissive
在Eng版本使用setenforce命令,可以在Permissive模式和Enforce模式之间切换。
安全属性
user:role:type[:range]
SELinux中,每种东西都会被赋予一个安全属性,它就是SecurityContext
Security Context是一个字符串,主要由三部分组成。
进程的SContext
ps -Z
u:r:servicemanager:s0 system 134 1 /system/bin/servicemanager
u:r:surfaceflinger:s0 system 135 1 /system/bin/surfaceflinger
u:r:sayeye:s0 system 136 1 /system/bin/sayeye
u:r:zygote:s0 root 137 1 zygote
u:r:shell:s0 shell 138 1 /system/bin/sh
u:r:netd:s0 root 139 1 /system/bin/netd
u:r:init:s0 root 1 0 /init
u:r:kernel:s0 root 2 0 kthreadd
SContext "u:r:servicemanager:s0"
1)u为user的意思:SEAndroid中定义了一个SELinux用户,值为u;
2)r为role的意思:role是角色之意,一个user可以属于多个role,不同的role具有不同的权限。
3)init代表进程在init域(Doamin)中。 init这个Domain有什么权限,都需要在策略文件(init.te)中定义。
- s0 Multi-LevelSecurity(MLS)机制.
文件的SContext
ls -Z
drwxrwx--- system cache u:object_r:cache_file:s0 cache
drwxrwx--x system system u:object_r:system_data_file:s0 data
lrwxrwxrwx root root u:object_r:rootfs:s0 etc -> /system/etc
drwxrwx--x system system u:object_r:rootfs:s0 firmware
drwxrwx--- system system u:object_r:logger_file:s0 logger
drwxr-xr-x root system u:object_r:tmpfs:s0 mnt
dr-xr-x--- system system u:object_r:rootfs:s0 oem
drwxrwx--x system system u:object_r:rootfs:s0 persist
drwxr-xr-x root system u:object_r:tmpfs:s0 sensors_cache
drwxr-xr-x root root u:object_r:system_file:s0 system
1)u还是user的意思;
2)object_r:在SELinux中,文件用object_r来表示它的role;
3)rootfs代表文件的类型(Type),和进程的Domain其实是一个意思。它表示root目录对应的Type是rootfs;
4)s0:MLS的级别;
安全策略
rule_name source_type target_type:class perm_set;
allow netd sysfs:file write;
rule_name
allow:允许某个进程执行某个动作
auditallow:audit含义就是记录某项操作。默认SELinux只记录那些权限检查失败的操作。 auditallow则使得权限检查成功的操作也被记录。注意,allowaudit只是允许记录,它和赋予权限没关系。赋予权限必须且只能使用allow语句。
dontaudit:对那些权限检查失败的操作不做记录。
neverallow:没有被allow到的动作默认就不允许执行的。neverallow只是显式地写出某个动作不被允许,如果添加了该动作的allow,则会编译错误
sourcetype
也叫Domain,Subject。
1)type:类型声明,type命令的完整格式为:
type type_id [attribute_id][attribute_id] …;
type shell, domain;
type sysfs, fs_type, sysfs_type;
一个type可以关联多个attribute;
2)attribute:属性由attribute关键字声明,属性其实是一个特殊的type
attribute fs_type; # 声明fs_type属性
- typeattribute:可以在定义type的时候,直接将其和某个attribute关联起来
Typeattribute system mlstrustedsubject;
targettype,
它代表其后的class所对应的Type。
class,它代表能够给Domain操作的对象。例如file、dir、socket等,Android中SecurityClass的定义在security_classes中。在Android系统中,有一些特殊的Class,如property_service,binder等。
class file # 文件
class dir # 目录
class fd # 文件描述符
class lnk_file # 链接文件
class chr_file # 字符设备文件
class blk_file # 块设备文件
class socket
class tcp_socket
class udp_socket
class binder # Android平台特有的binder
class zygote # Android平台特有的zygote
class property_service # Android平台特有的属性服务
perm_set
在该类objectclass中所定义的操作,例如file类支持ioctl,read,write等操作。access_vectors中定义了所有objectclass支持的操作。
common file {
ioctl read write create getattr setattr lock relabelfrom relabelto
append unlink link rename execute swapon quotaon mounton }
class dir inherits file { //继承
add_name remove_name reparent search rmdir open audit_access
execmod }
- 如果有多个source_type,target_type,class或perm_set,可以用”{}”括起来
- ””号,表示除了””以外;
- “-”号,表示去除某项内容;
- ”*”号,表示所有内容
打标签
Android系统启动后,init进程会调用selinux_android_load_policy接口,将一个编译完的安全策略文件传递给内核,内核可根据其中的相关信息来初始化SELinux相关模块;接着init进程会调用selinux_android_restorecon接口,根据context文件中的信息为系统打标签;
context文件 file_contexts
# Block labeling
/dev/block/mmcblk0 u:object_r:root_block_device:s0
/dev/block/by-name/boot u:object_r:boot_block_device:s0
/dev/block/by-name/system u:object_r:system_block_device:s0
/dev/block/by-name/recovery u:object_r:recovery_block_device:s0
#/dev/block/by-name/userdata u:object_r:userdata_block_device:s0
/dev/block/by-name/UDISK u:object_r:userdata_block_device:s0
/system/bin/bootclone.sh u:object_r:preinstall_exec:s0
/system/bin/precopy.sh u:object_r:preinstall_exec:s0
/system/bin/preinstall.sh u:object_r:preinstall_exec:s0
/system/bin/sensors.sh u:object_r:sensors_exec:s0
# /logger
/logger(/.*)? u:object_r:logger_file:s0
# allwinner auto log
/system/bin/logger.sh u:object_r:logger_exec:s0
/system/bin/log_service u:object_r:logger_exec:s0
文件系统打标签 /external/sepolicy/fs_use genfs_contexts
fs_use_xattr yaffs2 u:object_r:labeledfs:s0;
fs_use_xattr jffs2 u:object_r:labeledfs:s0;
fs_use_xattr ext2 u:object_r:labeledfs:s0;
fs_use_xattr ext3 u:object_r:labeledfs:s0;
fs_use_xattr ext4 u:object_r:labeledfs:s0;
fs_use_xattr xfs u:object_r:labeledfs:s0;
fs_use_xattr btrfs u:object_r:labeledfs:s0;
fs_use_xattr f2fs u:object_r:labeledfs:s0;
./external/sepolicy/genfs_contexts
# Label inodes with the fs label.
genfscon rootfs / u:object_r:rootfs:s0
# proc labeling can be further refined (longest matching prefix).
genfscon proc / u:object_r:proc:s0
genfscon proc /net u:object_r:proc_net:s0
genfscon proc /net/xt_qtaguid/ctrl u:object_r:qtaguid_proc:s0
genfscon proc /cpuinfo u:object_r:proc_cpuinfo:s0
genfscon proc /sysrq-trigger u:object_r:proc_sysrq:s0
genfscon proc /sys/fs/protected_hardlinks u:object_r:proc_security:s0
genfscon proc /sys/fs/protected_symlinks u:object_r:proc_security:s0
genfscon proc /sys/fs/suid_dumpable u:object_r:proc_security:s0
genfscon proc /sys/kernel/core_pattern u:object_r:usermodehelper:s0
genfscon proc /sys/kernel/dmesg_restrict u:object_r:proc_security:s0
property 打标签 property_contexts
net.rmnet u:object_r:net_radio_prop:s0
net.gprs u:object_r:net_radio_prop:s0
net.ppp u:object_r:net_radio_prop:s0
net.qmi u:object_r:net_radio_prop:s0
net.lte u:object_r:net_radio_prop:s0
net.cdma u:object_r:net_radio_prop:s0
net.dns u:object_r:net_radio_prop:s0
sys.usb.config u:object_r:system_radio_prop:s0
ril. u:object_r:radio_prop:s0
gsm. u:object_r:radio_prop:s0
persist.radio u:object_r:radio_prop:s0
service 打标签 service_contexts
accessibility u:object_r:accessibility_service:s0
account u:object_r:account_service:s0
activity u:object_r:activity_service:s0
alarm u:object_r:alarm_service:s0
android.security.keystore u:object_r:keystore_service:s0
android.service.gatekeeper.IGateKeeperService u:object_r:gatekeeper_service:s0
appops u:object_r:appops_service:s0
appwidget u:object_r:appwidget_service:s0
app打标签
mac_permissions.xml根据apk签名设置app的seinfo
isSystemServer=true domain=system_server
user=system seinfo=platform domain=system_app type=system_app_data_file
user=bluetooth seinfo=platform domain=bluetooth type=bluetooth_data_file
user=nfc seinfo=platform domain=nfc type=nfc_data_file
user=radio seinfo=platform domain=radio type=radio_data_file
user=shared_relro domain=shared_relro
user=shell seinfo=platform domain=shell type=shell_data_file
user=_isolated domain=isolated_app levelFrom=user
user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user
user=_app domain=untrusted_app type=app_data_file levelFrom=user
域转换 DomainTransition
init进程的SContext为u:r:init:s0,而init创建的子进程显然不会也不可能拥有和init进程一样的SContext
domain_trans(init, rootfs, healthd)
domain_trans(init, rootfs, slideshow)
domain_trans(init, shell_exec, shell)
domain_trans(init, init_exec, ueventd)
domain_trans(init, init_exec, watchdogd)
domain_trans($1,$2,$3)
# Make the transition occur by default.
type_transition $1 $2:process $3;
')
type_transition init shell_exec:process init_shell
当init域的进程执行(process)shell_exec类型的可执行文件时,进程会从**init**域切换到**init_shell**域。从file_contexts文件能看到,/system/bin/sh的安全属性是u:object_r:shell_exec:s0,也就是说init域的进程如果运行shell脚本的话,进程所在的域就会切换到init_shell域,这就是DomainTransition(简称DT)。
新设备增加安全属性
在domain.te中有如下定义:
[external/sepolicy/domain.te]
# Don't allow raw read/write/open access to generic devices.
# Rather force a relabel to a more specific type.
# init is exempt from this as there are character devices that only it uses.
# ueventd is exempt from this, as it is managing these devices.
neverallow { domain -init -ueventd } device:chr_file { open read write };
也就是说除了init和uevented域外,所有在domain域中的进程都不能对device类型的字符设备文件执行open,read,write操作。
在file_context中设置/dev/XXX的安全属性
添加权限后的neverallowed冲突
新添加的sepolicy项目违反了domain.te 中规定的的总策略原则
neverallow { domain -init -ueventd } device:chr_file { open read write };
neverallow {
domain
-system_server
-system_app
-init
-installd # for relabelfrom and unlink, check for this in explicit neverallow
} system_data_file:file no_w_file_perms;
- 在init.xxx.rc 的on post-fs-data 段 创建目录
mkdir /data/demorw 0770 root system
- . 在/device/xxxx/sepolicy/file.te 里面添加定义:
type demorw_data_file, file_type, data_file_type;
- /device/xxx/sepolicy/file_contexts 里面添加目录属性:
/data/demorw(/.*)? ubject_r:demorw_data_file:s0
- 给进程添加权限
allow xxxx demorw_data_file:dir create dir_perms;
allow xxxx demorw_data_file:file create_file_perms;
命令
ls -Z
ps -Z
chcon
restorecon
id
getenforce
setenforce