进程和文件/目录的标签查看
在支持SELinux的系统中,所有的进程都有一个SELinux的标签,查看进程的标签可以用下面的命令:
adb shell ps -Z
下面是Android 8.1.0模拟器上执行这个命令的结果(去掉了kernel、init等开发中很少有需要修改的进程):
LABEL USER PID PPID VSZ RSS WCHAN ADDR S NAME
u:r:logd:s0 logd 1367 1 16840 6808 sigsuspend ed3c3af0 S logd
u:r:servicemanager:s0 system 1368 1 7268 3436 binder_thread_read f4944af0 S servicemanager
u:r:hwservicemanager:s0 system 1369 1 11840 5956 ep_poll f260baf0 S hwservicemanager
u:r:vndservicemanager:s0 system 1370 1 7036 2916 binder_thread_read f70c4af0 S vndservicemanager
u:r:hal_sensors_default:s0 system 1432 1 11012 4444 goldfish_pipe_wait_event f1a1daf0 S android.hardware.sensors@1.0-service
u:r:hal_wifi_default:s0 wifi 1433 1 13408 7140 binder_thread_read eb6b4af0 S android.hardware.wifi@1.0-service
u:r:surfaceflinger:s0 system 1439 1 95676 14016 ep_poll f2bffaf0 S surfaceflinger
u:r:zygote:s0 root 1521 1 938536 111344 poll_schedule_timeout ece25af0 S zygote
u:r:audioserver:s0 audioserver 1522 1 111216 23716 binder_thread_read ecc8daf0 S audioserver
u:r:cameraserver:s0 cameraserver 1523 1 34264 13024 binder_thread_read f37d6af0 S cameraserver
u:r:installd:s0 root 1525 1 15216 5384 binder_thread_read ebcf0af0 S installd
u:r:mediaserver:s0 media 1530 1 59748 16252 binder_thread_read f210daf0 S mediaserver
u:r:system_server:s0 system 1648 1521 1194488 188812 ep_poll ece25af0 S system_server
u:r:untrusted_app:s0:c512,c768 u0_a60 1771 1521 1129228 162444 ep_poll ece25af0 S com.google.android.inputmethod.latin
u:r:platform_app:s0:c512,c768 u0_a29 1786 1521 1160968 151208 ep_poll ece25af0 S com.android.systemui
u:r:radio:s0 radio 1897 1521 1054988 104428 ep_poll ece25af0 S com.android.phone
u:r:priv_app:s0:c512,c768 u0_a13 2222 1521 1176236 157432 ep_poll ece25af0 S com.google.android.gms.persistent
u:r:priv_app:s0:c512,c768 u0_a13 2594 1521 1279688 165100 ep_poll ece25af0 S com.google.android.gms
u:r:su:s0 root 5396 1 67840 2584 0 edb8caf0 R adbd
u:r:untrusted_app:s0:c512,c768 u0_a80 11407 1521 1027772 64308 ep_poll ece25af0 S personal.jayhou.mydemos
u:r:untrusted_app:s0:c512,c768 u0_a80 11433 1521 1015452 49760 ep_poll ece25af0 S personal.jayhou.mydemos:remote
u:r:untrusted_app:s0:c512,c768 u0_a89 27497 1521 1044488 70976 ep_poll ece25af0 S com.chehejia.car.binderobjectdemo
u:r:untrusted_app:s0:c512,c768 u0_a89 27527 1521 1015420 49684 ep_poll ece25af0 S com.chehejia.car.binderobjectdemo:remote
u:r:untrusted_app:s0:c512,c768 u0_a69 31743 1521 1044024 88188 ep_poll ece25af0 S com.google.android.apps.messaging
u:r:untrusted_app:s0:c512,c768 u0_a69 31770 1521 1085220 92980 ep_poll ece25af0 S com.google.android.apps.messaging:rcs
u:r:priv_app:s0:c512,c768 u0_a13 32075 1521 1077256 101724 ep_poll ece25af0 S com.google.android.gms.unstable
u:r:priv_app:s0:c512,c768 u0_a20 32138 1521 1015476 51544 ep_poll ece25af0 S com.google.android.partnersetup
u:r:untrusted_app:s0:c512,c768 u0_a70 32195 1521 1057228 76832 ep_poll ece25af0 S com.google.android.apps.photos
u:r:untrusted_app:s0:c512,c768 u0_a47 32377 1521 1041400 72796 ep_poll ece25af0 S com.google.android.calendar
u:r:priv_app:s0:c512,c768 u0_a3 32394 1521 1014252 57424 ep_poll ece25af0 S com.android.providers.calendar
u:r:untrusted_app:s0:c512,c768 u0_a68 32425 1521 1030692 67892 ep_poll ece25af0 S com.google.android.deskclock
u:r:mediaprovider:s0:c512,c768 u0_a9 32451 1521 1016188 59392 ep_poll ece25af0 S android.process.media
u:r:priv_app:s0:c512,c768 u0_a31 32490 1521 1019140 57968 ep_poll ece25af0 S com.google.android.apps.wallpaper
可以看到,主要的进程有这么几类
native进程如 logd 其SELinux标签为 u:r:logd:s0,servicemanager 其SELinux标签为 u:r:servicemanager:s0 等
hal服务进程 如android.hardware.sensors@1.0-service 进程的SELinux标签为 u:r:hal_sensors_default:s0,android.hardware.wifi@1.0-service 进程的SELinux标签为 u:r:hal_wifi_default:s0 等。
native 服务 如surfaceflinger 其SELinux标签为u:r:surfaceflinger:s0 以及zygote、audioserver、cameraserver、mediaserver等
java服务进程 system_server 其SELinux标签为 u:r:system_server:s0
有platform签名的app 如com.android.systemui 的SELinux标签为 u:r:platform_app:s0:c512,c768
priv-app 如 com.google.android.gms.persistent 的SELinux标签是 u:r:priv_app:s0:c512,c768
普通三方app 我自己写的demo app personal.jayhou.mydemos 的SELinux标签为 u:r:untrusted_app:s0:c512,c768
然后去/data/data目录下看看文件/目录的SELinux标签:
adb shell进入设备,在/data/data/目录下执行 ls -Z
u:object_r:system_app_data_file:s0 android
u:object_r:app_data_file:s0:c512,c768 personal.jayhou.mydemos
基本上就是这么两类,一些特殊的目录有特殊的标签。(其他目录的标签很多,看这个目录下的标签主要是app目录带有c512,c768不同于其他目录的标签段)
标签字段及含义如下:
[user]:[role]:[type]:[sec-level]
user:表示selinux中定义的用户名,android中只有一个用户定义为u
role:表示selinux中定义的角色名,android中进程都定义为r,文件都定义为object_r
domain:文件/进程所属的域,file_contexts定义了文件/目录所属的域,进程所属的域Android中分为了几个文件来定义
seapp_contexts定义了大部分android app 根据各种条件以及签名来确定进程所属的域类型
sec-level:安全等级
注意到三方app目录、进程都有c512,c768的额外标签字段,这个是SELinux的MCS(多类别强制执行模型)参考这个文章的第二部分。
SEAndroid中标签的定义
这些标签都是由SELinux安全上下文文件定义,在如下文件中,定义了相关文件、设备、服务(名)等非进程类的对象标签
file_contexts、property_contexts、service_contexts、hwservice_contexts等
java世界进程的SELinux标签由seapp_contexts文件定义,zygote根据启动java进程的相关信息,结合seapp_contexts中的条件来给java进程打SELinux TAG
frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) {
fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed",
uid, is_system_server, se_info_ptr, nice_name_ptr));
}
android/system/sepolicy/private/seapp_contexts
这个文件定义了android默认的app安全上下文的标签设置策略:
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=media domain=mediaprovider name=android.process.media type=app_data_file levelFrom=user
user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user
user=_app isV2App=true isEphemeralApp=true domain=ephemeral_app type=app_data_file levelFrom=user
user=_app isPrivApp=true domain=priv_app type=app_data_file levelFrom=user
user=_app minTargetSdkVersion=26 domain=untrusted_app type=app_data_file levelFrom=user
user=_app domain=untrusted_app_25 type=app_data_file levelFrom=user
这些配置都会在Zygote fork出app进程时,调用selinux_android_setcontext的过程中去匹配
如随便写个minTargetSdkVersion>=26的hello world apk安装进去启动,显然其user=_app seinfo!=platform(根据签名判断),根据编译app TargetSdkVersion是否>=26 (没有 minTargetSdkVersion=26 这个配置则表示minTargetSdkVersion=0 )最后会匹配到这一条:
user=_app minTargetSdkVersion=26 domain=untrusted_app type=app_data_file levelFrom=user
那么该进程就被设置安全上下文标签为u:r:untrusted_app:s0:c512,c768(c512,c768这个字段是根据levelFrom=user打的)
具体每个字段意思可以仔细阅读seapp_contexts前面的注释
其中有的配置项包含seinfo=platform这样的,这个表示要匹配到这一条的进程,必须拥有platform签名,具体platform匹配什么签名在如下文件中定义
android/system/sepolicy/private/mac_permissions.xml
还可以自定义其他的seinfo对应不同的签名来配置seapp_contexts。
其他上面提到的native进程如logd、servicemanager,native服务hal service,Android其他native 服务进程如surfaceflinger mediaserver等进程的标签,主要由以下两个方式设置:
init.rc中可以由类似 seclabel u:r:shell:s0 的配置来定义init启动的进程的SELinux 标签
另一种拿surfaceflinger进程为例,其对应的策略文件:
android/system/sepolicy/private/surfaceflinger.te
有如下定义:
init_daemon_domain(surfaceflinger)
根据其宏定义展开
android/system/sepolicy/public/te_macros
#####################################
# init_daemon_domain(domain)
# Set up a transition from init to the daemon domain
# upon executing its binary.
define(`init_daemon_domain', `
domain_auto_trans(init, $1_exec, $1)
')
#####################################
# domain_auto_trans(olddomain, type, newdomain)
# Automatically transition from olddomain to newdomain
# upon executing a file labeled with type.
#
define(`domain_auto_trans', `
# Allow the necessary permissions.
domain_trans($1,$2,$3)
# Make the transition occur by default.
type_transition $1 $2:process $3;
')
#####################################
# 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 new domain.
allow $1 $2:file { getattr open read execute map };
allow $1 $3:process transition;
# New domain is entered by executing the file.
allow $3 $2:file { entrypoint open read execute getattr map };
# New domain can send SIGCHLD to its caller.
ifelse($1, `init', `', `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 };
')
所以编译后的init_daemon_domain(surfaceflinger)
第一次展开为:
domain_auto_trans(init, surfaceflinger_exec, surfaceflinger)
第二次展开为:
domain_trans(init,surfaceflinger_exec,surfaceflinger)
type_transition init surfaceflinger_exec:process surfaceflinger;
最终展开为:
# Old domain may exec the file and transition to the new domain.
allow init surfaceflinger_exec:file { getattr open read execute map };
allow init surfaceflinger:process transition;
# New domain is entered by executing the file.
allow surfaceflinger surfaceflinger_exec:file { entrypoint open read execute getattr map };
# New domain can send SIGCHLD to its caller.
ifelse(init, `init', `', `allow surfaceflinger init:process sigchld;')
# Enable AT_SECURE, i.e. libc secure mode.
dontaudit init surfaceflinger:process noatsecure;
# XXX dontaudit candidate but requires further study.
allow init surfaceflinger:process { siginh rlimitinh };
type_transition init surfaceflinger_exec:process surfaceflinger;
init_daemon_domain(surfaceflinger) 展开后,前面一大堆是为后面一句做的权限准备,最后一句type_transition init surfaceflinger_exec:process surfaceflinger; 是说 init 域的进程在执行type为surfaceflinger_exec的可执行文件时,将其(process)转换到surfaceflinger域,从标签来说就是,init进程启动surfaceflinger时,不允许surfaceflinger继承其标签 u:r:init:s0 而是要将surfaceflinger的标签变成 u:r:surfaceflinger:s0。
所以类似surfaceflinger这种由init启动的native进程/服务,其标签要么是init.rc中由seclable 命令指定 ,要么是其对应的.te文件中由规则init_daemon_domain()宏声明,由init进程域转到了init_daemon_domain()声明的域中。