Selinux 之SeAndroid学习杂记

版权说明:本文为 开开向前冲 原创文章,转载请注明出处;
注:限于作者水平有限,文中有不对的地方还请指教

1. SContext 安全上下文

根据SELinux规范,标准的SContext字符串格式为:

user:role:type[:range]
  1. 查看进程的SContext :ps -Z,
    ps -Z.png

    android 中进程的user 为 u,u在/external/sepolicy/users中定义;
    android 中进程的role 为 r,r在/external/sepolicy/roles中定义;
    type 是进程的domain type,一般是在进程对应的te中指定,例如进程/system/bin/sh对应的te文件在/external/sepolicy/shell.te中有 type shell, domain, mlstrustedsubject;
    [:range]代表可选,这里是s0;这里不做详解;
------> /external/sepolicy/users
user u roles { r } level s0 range s0 - mls_systemhigh;

------> /external/sepolicy/roles
role r;
role r types domain;

------> /external/sepolicy/shell.te
# Domain for shell processes spawned by ADB or console service.
type shell, domain, mlstrustedsubject;#指定shell 进程属于domain域为shell
type shell_exec, exec_type, file_type;

  1. 查看文件的SContext:ls -Z


    ls -Z.png

    android 中进程的user 为 u,u在/external/sepolicy/users中定义;同进程一样
    android 中文件的role 为 object_r;android 中对于"死东西"(文件)都用object_r来表示role;
    type 是文件的domain type;一般定义在/external/sepolicy/file.te中,例如:type rootfs, fs_type;
    [:range]代表可选,这里是s0;

SeAndroid 编译生效检查:修改.te文件后,(前提是先编译过android)remake android,编译成功后去到/out/target/product/xxxx/obj/ETC/sepolicy_intermediates/目录下的policy.conf文件中看看你的修改是否有效;如果有效,则证明你的修改成功,再make boot img,make boot img会将上述目录中的sepolicy打包进boot.img,这样刷boot.img就能验证你的修改是否有效;

Selinux核心思想就是最小权限原则,即主体对客体拥有的权限必须要通过allow语句定义才允许,否则的话,一切都是禁止的。

安全上下文中,只有 类型(Type)才是最重要的,SELinux用户、SELinux角色和安全级别都几乎可以忽略不计的。正因为如此,SEAndroid安全机制又称为是基于TE(Type Enforcement)策略的安全机制 ——摘自老罗

SEAndroid中,通常将标注文件的安全上下文的类型称为file_type,将标注进程的安全上下文的类型称为domain,每一个用于描述文件上下文的类型都将file_type 设置为其属性,每一个用于描述进程安全上下文的类型都将domain设置为其属性。
可以通过 type 语句实现将一个类型设置为另一个类型的属性:

type printerserver, domain; #### 将domain 设置为printerserver的属性
type persist_file, file_type;  #### 将file_type设置为persist_file的属性

上述语句也表明用 printerserver描述的类型描述的是进程的安全上下文;
persist_file描述的类型描述的是文件的安全上下文;

Linux Android系统中第一个启动的进程是init进程。Init进程启动过程中,执行了很多的系统初始化工作,其中就包括初始化SEAndroid安全策略的工作,如下所示:init.c的main方法中会调用selinux_initialize方法初始化Selinux,可以通过修改is_enforcing的值(0或者1)来控制是否禁掉Selinux。

------>/system/core/init/init.c

static void selinux_initialize(void)
{
    if (selinux_is_disabled()) {
        return;
    }

    INFO("loading selinux policy\n");
    if (selinux_android_load_policy() < 0) {
        ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
        android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
        while (1) { pause(); }  // never reached
    }

    selinux_init_all_handles();
    bool is_enforcing = selinux_is_enforcing();
    INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
    security_setenforce(is_enforcing);//is_enforcing控制是否禁掉Selinux
}

下面说说/external/sepolicy/目录下几个重要的文件;

attritbutes:属性文件,定义了Selinux的属性;

------> attritbutes
######################################
# Attribute declarations
# All types used for devices.
attribute dev_type;
# All types used for processes.
attribute domain; ###是不是很熟悉,我们在定义进程 Type 时都要指定这个属性
# All types used for filesystems.
attribute fs_type;
......

device.te:描述Linux 设备 Type

------>device.te
# Device types
type device, dev_type, fs_type;
type alarm_device, dev_type, mlstrustedobject;
type adb_device, dev_type;
type ashmem_device, dev_type, mlstrustedobject;
type audio_device, dev_type;
type binder_device, dev_type, mlstrustedobject;
type block_device, dev_type;
type camera_device, dev_type;
type dm_device, dev_type;
......

file.te:描述Linux 文件 Type

------> file.te
# Persist file types
type persist_file, file_type;
type persist_data_file, file_type;
type persist_drm_file, file_type;
......

file_contexts:文件file_contexts通过正则表达式来描述系统文件的安全上下文,Linux系统中一切皆文件,前面的device.te和file.te中都都有指定设备和文件Type,这些Type是怎么和系统中的设备和文件关联的呢?就是通过file_contexts文件;

------> file_contexts
###################################
# data files
#
/data/connectivity(/.*)?                                            u:object_r:cnd_data_file:s0
/data/data_test(/.*)?                                               u:object_r:data_test_data_file:s0
/data/diag_log(/.*)?                                                u:object_r:diag_data_file:s0
/data/hlos_rfs(/.*)?                                                u:object_r:rfs_shared_hlos_file:s0
/data/camera(/.*)?                                                  u:object_r:camera_socket:s0
/data/system/sensors(/.*)?                                          u:object_r:sensors_data_file:s0
/data/time/*                                                        u:object_r:time_data_file:s0
/data/nfc(/.*)?                                                     u:object_r:nfc_data_file:s0
/data/system/perfd(/.*)?                                            u:object_r:mpctl_data_file:s0
......

根据SELinux规范,完整的 allow 相关的语句格式为:

rule_name source_type target_type : class perm_set
allow zygote shell_data_file:dir search;###这句话表示允许Zygote 进程对shell_data_file类型的 dir 进行search;
这里的 dir 和 search称为object class和perm set,即可以在object class对象上进行perm set操作;object class定义在security_classes中,perm set定义在access_vectors中;

security_classes:定义被保护的object class对象,例如file,dir,fd等;

------> security_classes
# Define the security object classes
# file-related classes
class filesystem
class file
class dir
class fd
class lnk_file
class chr_file
class blk_file
class sock_file
class fifo_file

access_vectors:定义security_classes中object class对象具有哪些perm set;

------> access_vectors
#
# Define a common prefix for file access vectors.
#
common file
{
    ioctl
    read
    write
    create
    getattr
    setattr
    lock
    relabelfrom
    relabelto
    append
    unlink
    link
    rename
    execute
    swapon
    quotaon
    mounton
}
......

上面说明了可以对被保护的 file 进行ioctl read write create等操作;

mac_permissions.xml:



    
    
      
    

    
    
      
    

文件mac_permissions.xml给不同签名的App分配不同的seinfo字符串,例如,在AOSP源码环境下编译并且使用平台签名的App获得的seinfo为“platform”,使用第三方签名安装的App获得的seinfo签名为"default"。这里的setinfo并不是安全上下文的Type;但是系统会根据这个setinfo到external/sepolicy/seapp_contexts中去查找和和setinfo 对应的类型;

seapp_contexts:根据setinfo查找对应应用的安全上下文 Type;

------> seapp_contexts
# Input selectors:
#   isSystemServer (boolean)
#   user (string)
#   seinfo (string)
#   name (string)
#   path (string)
#   sebool (string)
# isSystemServer=true can only be used once.
# An unspecified isSystemServer defaults to false.
# An unspecified string selector will match any value.
# A user string selector that ends in * will perform a prefix match.
# user=_app will match any regular app UID.
# user=_isolated will match any isolated service UID.
# All specified input selectors in an entry must match (i.e. logical AND).
# Matching is case-insensitive.
#
# Precedence rules:
#     (1) isSystemServer=true before isSystemServer=false.
#     (2) Specified user= string before unspecified user= string.
#     (3) Fixed user= string before user= prefix (i.e. ending in *).
#     (4) Longer user= prefix before shorter user= prefix.
#     (5) Specified seinfo= string before unspecified seinfo= string.
#     (6) Specified name= string before unspecified name= string.
#     (7) Specified path= string before unspecified path= string.
#     (8) Specified sebool= string before unspecified sebool= string.
#
# Outputs:
#   domain (string)
#   type (string)
#   levelFrom (string; one of none, all, app, or user)
#   level (string)
# Only entries that specify domain= will be used for app process labeling.
# Only entries that specify type= will be used for app directory labeling.
# levelFrom=user is only supported for _app or _isolated UIDs.
# levelFrom=app or levelFrom=all is only supported for _app UIDs.
# level may be used to specify a fixed level for any UID.
#
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_app type=app_data_file
user=_app domain=untrusted_app type=app_data_file

这里我保留了文件的全部内容,文中注释很重要;
前面mac_permisssions.xml 中指定使用平台签名的应用setinfo 为platform,所以在seapp_contexts中最匹配的一行为:

user=_app seinfo=platform domain=platform_app type=app_data_file

这样就可以知道,使用平台签名的App进程domain为“platform_app”,它的数据文件的file_type为“app_data_file”。

第三方签名的应用的seinfo为 "default",但是在seapp_contexts并没有以 user=_app seinfo=default开头的行,但是有一行最匹配:

user=_app domain=untrusted_app type=app_data_file

这样就知道了第三方App进程的domain 为 "untrusted_app",它的数据文件的file_type为"app_data_file";

global_macros,te_macros:一些宏定义文件;

------> te_macros
# upon executing its binary.
define(`init_daemon_domain', `
domain_auto_trans(init, $1_exec, $1)
tmpfs_domain($1)
')
#####################################
# app_domain(domain)
# Allow a base set of permissions required for all apps.
define(`app_domain', `
typeattribute $1 appdomain;
# Label ashmem objects with our own unique type.
tmpfs_domain($1)
# Map with PROT_EXEC.
allow $1 $1_tmpfs:file execute;
')
......

property_contexts:和file_contexts类似,这里初始化属性的安全上下文;

-----> property_contexts
##########################
# property service keys
#
#
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
.......

还有很多的文件,这里就不逐一分析了,遇到问题就明白了,这里举两个例子;
/external/sepolicy目录下是Google 针对整个平台的限制,一般都不会修改;自己的修改一般都在/device/qcom/sepolicy目录;
这里针对qcom平台:/device/qcom/sepolicy/

例1:为一个进程添加Selinux 访问权限;

步骤如下:
1:在/device/qcom/sepolicy/common目录下创建一个和进程名一样的.te文件;例如hello进程对应的hello.te;在hello.te中使用type声明该进程的 domain Type;

------> hello.te
type hello, domain; ### 声明该进程的domain Type 为 hello
type hello_exec, exec_type, file_type; ###这里说明hello进程可执行文件的 Type为hello_exec,
#### 这里需要去file_contexts中去配置相关类型;
init_daemon_domain(hello) ###必须实现
binder_use(hello)
binder_service(hello)

allow hello hello_service:service_manager add;###hello_service需要向service.te中注册,
allow hello system_server:binder call;
allow hello platform_app:binder call;
allow hello device:sock_file write;
allow hello untrusted_app:binder call;
allow hello system_app:dir search;
allow hello system_app:file { open read getattr };
......

因为这里注册的是Service 还需要去service.te和service_contexts中添加对应内容,如果不需要提供跨进程服务就不需要添加;

-------> service.te
......
type hello_service,   service_manager_type; ####声明系统服务的Type 为hello_service,属性为service_manager_type
......
------> service_contexts
......
servicePackageName   u:object_r:hello_service:s0   ####servicePackageName是服务的包名,
### 这里和hello.te中的allow hello hello_service:service_manager add;有关
......
------> file_contexts
......
/system/bin/hello     u:object_r:hello_exec:s0 
### hello_exec用于hello.te中的type hello_exec, exec_type, file_type;中
......

2:将步骤1中的hello.te字符串添加到/device/qcom/sepolicy/下的Android.mk文件BOARD_SEPOLICY_UNION := \ 标签中编译;

BOARD_SEPOLICY_UNION := \
                        ......
                        hello.te
                        ......

是不是很简单,这样我们就添加完成了Hello进程的访问权限;

例2:为一个文件添加访问控制;

步骤1:由于是为文件添加访问权限;所以我们需要声明该文件的Type;文件Type 在需要在file.te和file_contexts中声明;file_contexts中声明该文件位置;

------> file.te 
#Hello data files /data/hello
......
type hello_data_file, file_type, data_file_type;
......

------> file_contexts
......
/data/hello(/.*)?                                               u:object_r:hello_data_file:s0
......

这样我们就算是为文件添加了权限,对于这个文件,有哪些文件需要去访问呢?这里我们不妨假定为platform app需要访问这个文件;

接下来我们就在platform_app.te中添加相关权限;

------> platform_app.te
# allow access /data/hello/
......
allow platform_app hello_data_file:file { open getattr read };
allow platform_app hello_data_file:dir { search };
......

这样我们就为一个文件添加了访问控制;添加Linux 设备也是类似,对于设备配置只是去device.te和file_contexts添加类似于文件类型的东西;因为Linux 一切皆文件,设备也是文件,所以需要在file_contexts中为指定路径配置设备 Type;

到这里初步说明了一般在Android中会用到的Selinux 场景,很多深的东西还需要进一步研究;这里只是一个皮毛;

下面几个不错的博客;我也是参考他们的博客学习

深入理解SELinux 之SEAndroid
修改domain.te导致CTS不过解决方案-SELinux报错修改篇
file_contexts.bin和file_contexts转换工具,支持7.0~8.0
老罗说Selinux
TE语言规则
TE规则

你可能感兴趣的:(Selinux 之SeAndroid学习杂记)