SEAndroid使用两种方式为进程设置安全上下文
1.为独立进程静态的设置安全上下文
这和传统的LInux系统很像。android系统中的每个独立进程都对应着一个可执行文件。
以init为例,查看init进程的启动脚本system/core/rootdir/init.rc,部分内容如下:
on early-init
...........
# Set thesecurity context for the init process.
# Thisshould occur before anything else (e.g. ueventd) is started.
setconu:r:init:s0
这一行的作用是让init进程将自己的安全上下文设为u:r:init:s0。
查看external/sepolicy/init.te中,init这个domain的规则:
# init switches to init domain (via init.rc).
type init, domain;
# init is unconfined.
unconfined_domain(init)
tmpfs_domain(init)
allow init self:capability { sys_rawio mknod };
.........
domain_trans(init, rootfs, adbd)
.........
neverallow { domain -kernel} init:process dyntransition;
..........
首先(除注释以外)第一行,type init, domain;声明init具有domain的属性。这样它就可以和u,r一起,组成合法的安全上下文。
第二行unconfined_domain(init) unconfined_domain是一个宏,定义在external/sepolicy/te_macros文件中,声明init是一个不受限制的domain,它可以访问系统中的大部分资源。宏定义如下:
#####################################
# unconfined_domain(domain)
# Allow the specified domain to perform more privilegedoperations
# than would be typically allowed. Please see the comments atthe
# top of unconfined.te.
#
define(`unconfined_domain', `
typeattribute $1 mlstrustedsubject;
typeattribute $1 unconfineddomain;
')
第三行tmpfs_domain(init) 也是一个宏,也定义在external/sepolicy/te_macros文件中。声明当domain为init的进程在type为tmpfs的目录中创建文件时,该新建文件的type为init_tmpfs,并允许domain为init的进程对这些文件进行读写操作。宏定义如下:
#####################################
# tmpfs_domain(domain)
# Define and allow access to a unique type for
# this domain when creating tmpfs / shmem / ashmem files.
define(`tmpfs_domain', `
type $1_tmpfs, file_type;
type_transition $1 tmpfs:file $1_tmpfs;
allow $1 $1_tmpfs:file { read write };
')
第四行是一个allow语句,关于allow语句的含义,之前写过,这里不重复了。
第五行domain_trans(init, rootfs, adbd) 也是宏,位置也在te_macros文件中。声明domain为init的进程,可以通过执行type为rootfs的文件,进入名为adbd的domain。也就是说init进程可以执行/sbin/adbd(该文件type为rootfs),从而进入adbd。这个过程中涉及到多个许可,具体宏定义如下:
#####################################
# domain_trans(olddomain, type, newdomain)
# Allow a transition from olddomain to newdomain
# upon executing a file labeled with type.
# This only allows the transition; it does not
# cause it to occur automatically - use domain_auto_trans
# if that is what you want.
#
define(`domain_trans', `
# Old domain may exec the file and transition to the newdomain.
allow $1 $2:file { getattr open read execute };
allow $1 $3:process transition;
# New domain is entered by executing the file.
allow $3 $2:file { entrypoint open read execute getattr };
# New domain can send SIGCHLD to its caller.
allow $3 $1:process sigchld;
# Enable AT_SECURE, i.e. libc secure mode.
dontaudit $1 $3:process noatsecure;
# XXX dontaudit candidate but requires further study.
allow $1 $3:process { siginh rlimitinh };
')
第六行neverallow { domain -kernel} init:process dyntransition,neverallow规则主要作用是确保allow规则的正确性。具体含义之前也写过,不重复了。
再看zygote进程,与init进程类似。在system/core/rootdir/init.zygote32.rc中(类似的还有三个文件32,64之类的,应该和处理器有关):
service zygote /system/bin/app_process -Xzygote /system/bin--zygote --start-system-server
classmain
socketzygote stream 660 root system
onrestartwrite /sys/android_power/request_state wake
onrestartwrite /sys/power/state on
onrestartrestart media
onrestartrestart netd
说明zygote进程对应的可执行文件为/system/bin/app_process,查看external/sepolicy/file_contexts,发现/system/bin/app_process的安全上下文是u:object_r:zygote_exec:s0 如下:
/system/bin/app_process32 u:object_r:zygote_exec:s0
/system/bin/app_process64 u:object_r:zygote_exec:s0
查看zygote.te,其中大部分规则都很熟悉,剩下不熟悉的:
第一个,init_daemon_domain(zygote) 是一个宏,声明当一个domain为init的进程创建一个子进程执行一个type为zygote_exec的文件时,将该子进程的domain设置为zygote,而不是继承父进程的domain。并且给与zygote这个domain,所有定义在tmpfs_domain宏中的权限。
第二个,typeattribute zygote mlstrustedsubject; typeattribute和type很类似,都是通过声明属性的方式来获取权限。不过type是得到其他domain的权限。而typeattribute之后跟的mlstrustedsubject,是一个属性,而非domain。另外,所有的attribute都在attributes文件中定义。
第三组,三个跟selinux相关的宏:
# Check validity of SELinux context before use.
selinux_check_context(zygote)
# Check SELinux permissions.
selinux_check_access(zygote)
# Read /seapp_contexts and /data/security/seapp_contexts
security_access_policy(zygote)
宏定义如下:
#####################################
# selinux_check_context(domain)
# Allow domain to check SELinux contexts via selinuxfs.
define(`selinux_check_context', `
allow $1 selinuxfs:file rw_file_perms;
allow $1 kernel:security check_context;
')
#####################################
# selinux_check_access(domain)
# Allow domain to check SELinux permissions via selinuxfs.
define(`selinux_check_access', `
allow $1 selinuxfs:file rw_file_perms;
allow $1 kernel:security compute_av;
allow $1 self:netlink_selinux_socket *;
')
#####################################
# security_access_policy(domain)
# Read only access to all policy files and
# selinuxfs
define(`security_access_policy', `
allow $1 security_file:dir r_dir_perms;
allow $1 security_file:file r_file_perms;
')
2.为应用程序进程设置安全上下文
按照前面提过的,每个APP都会在mac_permissions.xml中找到一个对应的seinfo,然后在seapp_contexts中找到对应的domain和type。其中,domain就用来给应用程序进程当作安全上下文了。
详细地说,在android5.x中,为支持多用户,应用程序的UID由两部分组成,User Id和App Id。赋值方法:
userid = uid/ AID_USER;
appid = uid% AID_USER;
其中,AID_USER是一个常量,值为100000。
AppId小于AID_APP(10000)是保留给系统使用的,它们对应的username保存在数组android_ids中,具体可以参考文件system/core/include/private/android_filesystem_config.h。
AppId大于等于AID_APP(10000)并且小于AID_ISOLATED_START(99000)是分配给应用程序使用的,它们对应的username统一设置为“_app”。
AppId大于等于AID_ISOLATED_START(99000)是分配给运行在独立沙箱(没有任何自己的Permission)的应用程序使用的,它们对应的username统一设置为“_isolated”
再查看external/sepolicy/seapp_contexts文件:
- isSystemServer=true domain=system_server
- user=system domain=system_app type=system_app_data_file
- user=bluetooth domain=bluetooth type=bluetooth_data_file
- user=nfc domain=nfc type=nfc_data_file
- user=radio domain=radio type=radio_data_file
- user=shared_relro domain=shared_relro
- user=shell domain=shell type=shell_data_file
- user=_isolated domain=isolated_app
- user=_app seinfo=platform domain=platform_apptype=app_data_file
- user=_app domain=untrusted_app type=app_data_file
第一行到第七行的user都是系统预设的,可以在android_filesystem_config.h中找到。
第八行,将运行在独立沙箱的应用程序的domain设为isolated_app。
第九行的seinfo对应着mac_pernissions.xml文件中设置的seinfo。APP通过签名和包名得到对应的seinfo,并进而得到domain和type。
第十行对应着那些seinfo是default的APP。他们的domain都是untrusted_app,type都是app_data_file。所有第三方APP和部分系统APP,都会被分到这一部分。
又有一个地方可以动手脚,为访客用户设置一个新的domain用。
在external/libselinux/src/android.c的seapp_context_lookup中,可以根据userid来改变访客用户的username为anrom_app。再配合external/sepolicy/seapp_contexts中增加新的条目:
user=anrom_app domain=anrom_app type=anrom_app_data_file
就可以将所有访客用户的app的domain和type改变。