Android sepolicy简要记

SEAndroid是一种基于安全策略的MAC安全机制。SEAndroid安全机制中的安全策略就是在安全上下文的基础上进行描述的,也就是说,它通过主体和客体的安全上下文,定义主体是否有权限访问客体。

安全上下文

安全上下文: 附加在对象上的标签(label)

由四部分内容组成:SELinux用户、SELinux角色、类型、安全级别 
格式为“user:role:type:sensitivity”

文件init.rc的安全上下文类似如下:( $ls -Z /init.rc)

 -rwxr-x--- root     root    u:object_r:rootfs:s0 init.rc

进程init的安全上下文类似如下:($ps -Z)

LABEL                          USER     PID  PPID  NAME

u:r:init:s0                    root         1       0        /init

进程的安全上下文中,用户固定为 u,角色固定为 r

文件的安全上下文中,用户固定为 u,角色固定为 obejct_r

在SELinux中,安全级别是可选的,也就是说,可以选择启用或者不启用。通常在进程及文件的安全上下文中安全级别都设置为s0

进程的安全上下文的类型称为domain,文件的安全上下文中的类型称为file_type

上面我们看到进程init的安全上下文为u:r:init:s0,type为init
在Android中我们可以通过如下语句定义type:

type init domain;

即将domain设置为init的属性,这样就可以用init为type来描述进程的安全上下文了。

Seapp_contexts

用于声明APP进程和创建数据目录的安全上下文,O上将该文件拆分为plat和nonplat 前缀的两个文件,plat前缀的文件用于声明system app,nonplat前缀的文件用于声明vendor app。

# Ephemeral Apps must run in the ephemeral_app domain
neverallow isEphemeralApp=true domain=((?!ephemeral_app).)*

isSystemServer=true domain=system_server
user=_app seinfo=platform name=com.android.traceur domain=traceur_app type=app_data_file levelFrom=all
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=secure_element seinfo=platform domain=secure_element levelFrom=all
user=radio seinfo=platform domain=radio type=radio_data_file
user=shared_relro domain=shared_relro
user=shell seinfo=platform domain=shell name=com.android.shell type=shell_data_file
user=webview_zygote seinfo=webview_zygote domain=webview_zygote
user=_isolated domain=isolated_app levelFrom=all
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=all
user=_app isPrivApp=true domain=priv_app type=app_data_file levelFrom=user
user=_app minTargetSdkVersion=28 domain=untrusted_app type=app_data_file levelFrom=all
user=_app minTargetSdkVersion=26 domain=untrusted_app_27 type=app_data_file levelFrom=user
user=_app domain=untrusted_app_25 type=app_data_file levelFrom=user

seinfo可以从mac_permissions.xml查看
对于使用平台签名的App来说,它的seinfo为“platform”。这样我们就可以知道,使用平台签名的App所运行在的进程domain为“platform_app”,并且它的数据文件的file_type为“platform_app_data_file”。

File_contexts

用于声明文件的安全上下文,plat前缀的文件用于声明system、rootfs、data等与设备无关的文件。Nonplat 用于声明vendor、data/vendor 等文件。

Service_contexts

用于声明java service 的安全上下文, O上将该文件拆分为plat和nonplat 前缀的两个文件,但nonplat前缀的文件并没有具体的内容(vendor和system java service不允许binder 操作)。

Property_contexts

用于声明属性的安全上下文,plat 前缀的文件用于声明system属性,nonplat前缀的文件用于声明vendor 属性。ril.开头的属性的安全上下文为u:object_r:radio_prop:s0,这意味着只有有权限访问Type为radio_prop的资源的进程才可以访问这些属性。

Hwservice_contexts

O 上新增文件,用于声明HIDL service 安全上下文。

android.hardware.vibrator::IVibrator                u:object_r:hal_vibrator_hwservice:s0
android.hardware.vr::IVr                            u:object_r:hal_vr_hwservice:s0
android.hardware.weaver::IWeaver                    u:object_r:hal_weaver_hwservice:s0
android.hardware.wifi::IWifi                        u:object_r:hal_wifi_hwservice:s0
android.hardware.wifi.hostapd::IHostapd             u:object_r:hal_wifi_hostapd_hwservice:s0
android.hardware.wifi.offload::IOffload             u:object_r:hal_wifi_offload_hwservice:s0
android.hidl.allocator::IAllocator                  u:object_r:hidl_allocator_hwservice:s0
android.hidl.base::IBase                            u:object_r:hidl_base_hwservice:s0
android.hidl.manager::IServiceManager               u:object_r:hidl_manager_hwservice:s0
android.hidl.memory::IMapper                        u:object_r:hidl_memory_hwservice:s0
android.hidl.token::ITokenManager                   u:object_r:hidl_token_hwservice:s0
android.system.net.netd::INetd                      u:object_r:system_net_netd_hwservice:s0

安全策略

SEAndroid安全机制又称为是基于TE(Type Enforcement)策略的安全机制。所有安全策略都存放在.te结尾的文件中,一般放在 /system/sepolicy/private/,厂商定制的一般放在/device/xxx/common/sepolicy/下

一个Type所具有的权限是通过allow语句来描述的,SEAndroid使用的是最小权限原则,也就是说,只有通过allow语句声明的权限才是允许的,而其它没有通过allow语句声明的权限都是禁止,这样就可以最大限度地保护系统中的资源。

语句格式为:allow scontex tcontex:class action

除了allow还有:neverallow (检查并记录是否有违反这条策略的)、allowaudit(检查记录权限成功及失败的操作,默认只记录检查失败的)、dontaudit(不记录权限检查失败的记录),后三个仅是检查及记录,并不赋予或禁止权限。

常见错误修改

出现违反SELinux安全策略的错误时一般会有如下log输出:

avc:denied { write } for pid=2646 comm="gfslog" name="/" dev="mmcblk0p21" ino=2 scontext=u:r:gfslog:s0 tcontext=u:object_r:system_data_file:s0 tclass=dir permissive=0

一般按照规则 allow scontex tcontex:tclass action 来改即可。即:

allow gfslog system_data_file:dir write

违反规则的同时又neverallow问题修改

Google 在external/sepolicy 中有使用相关neverallow 规则, 对SELinux Policy 的更新进行了限制, 以防止开发者过度开放权限,从而引发安全问题。并且通过CTS Test 检测开发者是否有违法相关的规则.

严格遵守Google 定义的规则,具体即是
* 严禁直接修改external/sepolicy 下面的相关SELinux Policy, 使之保持与Google 一致, 特别是严禁直接删除或者修改Google 定义的neverallow 规则.
* 遇到与Google 定义相违背之处, 只能绕道, 或者修改设计.

方式一:更改type

比如recovery升级中,有如下错误:

avc: denied { read } for name="mmcblk0p15" dev="tmpfs" ino=3364 scontext=u:r:install_recovery:s0 tcontext=u:object_r:block_device:s0 tclass=blk_file permissive=0  

但是domain.te文件中,明确domain中是没有对block_device的读写权限,除了recovery等。

neverallow { domain -kernel -init -recovery } block_device:blk_file { open read write };

方法一:将 install_recovery 添加到上述neverallow的domain例外中,但后续可能会有cts问题

方法二:将要操作的文件定义为其他type,然后允许install_recovery来读写这个新type的文件

方式二 通过binder/socket 等方式连接APP 访问

如: Android L APP 如何获取sys 或者 proc file system 中节点的写权限
说明: Google 默认禁止app , 包括system app, radio app 等直接写/sys 目录以u:object_r:sysfs:s0 为标签的文件以及/proc 目录以u:object_r:proc:s0文件, 认为这个是有安全风险的。如果直接放开SELinux 权限, 会导致CTS 无法通过.

解决方式:
通常遇到此类情况,你有两种做法:
(1). 通过system server service 或者 init 启动的service 读写操作, 然后app 通过binder/socket 等方式连接APP 访问. 此类安全可靠, 并且可以在service 中做相关的安全审查, 推崇这种方法.

方式三 更改Label

(2). 修改对应节点的SELinux Security Label, 为特定的APP, 如system app, radio, bluetooth 等内置APP开启权限, 但严禁为untrsted app 开启权限. 具体的做法下面以 system app 控制/sys/class/leds/lcd-backlight/brightness 来说明.
在device/mediatek/common/sepolicy/file.te 定义brightness SELinux type

type sys_lcd_brightness_file, fs_type,sysfs_type;

在device/mediatek/common/sepolicy/file_contexts 绑定 brightness 对应的label, 注意对应的节点是实际节点,而不是链接.

/sys/devices/platform/leds-mt65xx/leds/lcd-backlight/brightness u:object_r:sys_lcd_brightness_file:s0

在device/mediatek/common/sepolicy/system_app.te 中申请权限.

allow system_app sys_lcd_brightness_file:file rw_file_perms;

为其它的process 申请相关的权限,如system_server, 在device/mediatek/common/sepolicy/system_server.te
allow system_server sys_lcd_brightness_file:file rw_file_perms;

原则上我们都推崇使用第一种处理.

Process 无法访问某个新增device

说明: Google 默认禁止除unconfineddomain 的进程以及ueventd 之外的进程直接访问某个普通定义的device, 所谓普通定义即device 对应的SELinux Label 是u:object_r:device:s0.
解决方式: 需要为新增的device 定义具体的Label, 然后再给对应的process 开启相关的权限.

Native Process 运行java 程序

说明: 以往我们在上下层通讯中, 比如某个native process/service 通常会借用如am 命令, 向ActivityManagerService 发送broadcast, 或者start activity 等. 通知上层某个事件已经发生了. 在android 5.0 以后, Google 严禁非app 以及几个特别的domain 的程序执行非rootfs or /system 分区的文件, 具体定义如:
neverallow { domain -appdomain -dumpstate -shell -su -system_server -zygote } { file_type -system_file -exec_type }:file execute;

解决方式:

(第一种方法).借用am 命令,实质上还是通过获取AMS 的binder 引用,再通过binder 向AMS 发送命令, 同样的你可以直接binder 来操作, 代表案例有: mediaserver 中使用的/frameworks/av/media/libmediaplayerservice/ActivityManager.cpp.
先获取servicemanager, 然后再获取activty binder 接口, 然后再封装parcel 后发送相关的命令给AMS.

具体对应的function cmd 以及parcel 的封装格式可以参考: frameworks/base/core/java/android/app/ActivityManagerNative.java.

注意:如果这个process 没有申请binder 权限, 则需要先申请binder 权限, 可以使用 binder_use, binder_call, binder_service
(第二种方法). 将这个process 纳入appdomain, 但这个带来的影响是, 这个process 的权限会受到更大的限制, 因为Google 对appdomain 有非常严格的限制. 比如某个process 是demo
device/mediatek/common/sepolicy/demo.te 里面新增
app_domain(demo)

system app 读写nvram 操作

说明: 以往我们可以通过jni 直接读写nvram, 目前Google 已经严禁app 去读写系统块设备文件.
解决方式: 已经做好了nvram_agent_binder 这样一个服务进程,使用时就是去访问它这个service 即可

UEventObserver 在APP 中使用

说明:
(1). Google 禁止UEventObserver API在第三方APP 使用,即任何不可信任的APP 都禁止使用此API.
(2). 如果是系统APP ,比如phone app, settings 等使用,那么就要根据app 使用的domain, 添加相关的SELinux 权限.
解决方式: 确保你的APP 是系统的APP, 非untrusted app.
如针对settings app, 在device/mediatek/common/sepolicy/system_app.te 里面新增
allow system_app self:netlink_kobject_uevent_socket { create ioctl read getattr setattr bind connect getopt setopt shutdown };

如何开机设置SELinux 模式

1 更新配置
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

2 允许USER 版本 disable SELinux (如果你需要在USER Build 上开启)
修改system/core/init/Android.mk 新增

ifeq ($(strip $(TARGET_BUILD_VARIANT)),user)
LOCAL_CFLAGS += -DALLOW_DISABLE_SELINUX=1
Endif

SELinux Update in O overview

Google android O 8.0 开始, 对android 架构进行大幅度的更新, 一个最为重要的方面是切割Google/SoC Vendor/ODM 三者的复杂关联性, 让android 单独升级成为可能.

为了防止System.img / Vendor.img 中数据, 服务, 应用等相互的依赖, 调用, 引用. Google 大幅度的更新了selinux policy, 进行严格的限制.

这里写图片描述

比如严格限制了system image 和 vendor image 之间的socket, binder 通讯. 只能通过HIDL, HwBinder 进行交互.

sepolicy 分离

伴随着system image 和 vendor image 的分离, 自然也会伴随着sepolicy 的分离, 从以往集中放在bootimage , 到分离存放到system image 以及 vendor image. 原则上与system 相关的sepolicy 就存放system image, 与SoC vendor 相关的sepolicy 就存放在vendor image.

对应sepolicy, Google 也设定了不同的存放目录, 以便进行分离, 以Google 默认的sepolicy 为例. /system/sepolicy

public: android 和 vendor 共享的sepolicy 定义, 通常情况下, 意味着vendor 开发者可能为此新增一些权限. 一般system/vendor 共用的一些类型和属性的定义, neverallow 限制等会存放于此.

private: 通常意义上的仅限于system image 内部的使用, 不对vendor 开放. 这个只会编译到system image 中.

vendor: 它仅仅能引用public 目录下的相关定义, 这个只会编译到vendor image 中. 但它依旧可以对system image 里面的module 设定sepolicy(对应module 需要在public 下进行声明); 在很大程度上绕过了Google GTS 约束测试.

mapping: 为兼容老版本的sepolicy 而导入, 只有在system image version > vendor version 的时候, 才可能被用到. 即包括两方面, 新版本增加的type , 新版本移除的type, 以及老版本public, 新版本private 等变化的设定, 以兼容老版本.

针对性的, MTK 这边也有类似的操作:

/device/mediatek/sepolicy/basic|bsp|full/

non_plat: 仅用于vendor 目录的sepolicy 设定. 和Google vendor 目录类似.
plat_private: 仅用于system 目录的sepolicy 设定, 和Google 的private 目录类似.
plat_public: 同时可用于vendor/system 的sepolicy 设定, 和Google 的public 目录类似.

针对MTK 默认的设定, 可以参考:

/device/mediatek/common/BoardConfig.mk

对于手机来说生成的selinux policy 位于:

System android sepolicy: system/etc/selinux

Vendor ODM sepolicy: vendor/etc/selinux

再说强制性约束(neverallow)

Google 新增的强制性约束主要是针对system/vendor 之间的IPC 约束.
这里写图片描述

具体的定义可以参考:

/system/sepolicy/public/domain.te

新增重要类型/属性

这里写图片描述

这里写图片描述

新增场景语法HAL/Binder与设计

1.1 How to define sepolicy for HAL process
HAL 的sepolicy 可以分成两种, 一种是HAL service 默认已经定义好的, 另外一种是完全新增的HAL service. 我们这里只说后面一种, 前面就是后面的简化版本.

Google 使用属性来定义client/server, 以便不同家vendor 能够绑定属性来达成.

(0). Define HAL service attribute, xxxx 为HAL service

/device/mediatek/sepolicy/bsp/non_plat

attribute hal_xxxx;

expandattribute hal_xxxx true;

attribute hal_xxxx_client;

expandattribute hal_xxxx_client true;

attribute hal_xxxx_server;

expandattribute hal_xxxx_server false;

(1). Define new hwservice type yyy 是某家公司的代号, 如mtk

/device/mediatek/sepolicy/bsp/non_plat/hwservice.te

type yyy_hal_xxxx_hwservice, hwservice_manager_type;

(2). Associate HAL interface with new HWService type, yyy 为某家公司代号, zzz 为具体的接口.

/device/mediatek/sepolicy/bsp/non_plat/hwservice_contexts

vendor.yyy.hardware.xxxx::zzz u:object_r: yyy_hal_xxxx_hwservice:s0;

(3). Creat HAL TE file

/device/mediatek/sepolicy/bsp/non_plat/hal_xxxx.te

type yyy_hal_xxxx, domain;

hal_server_domain(yyy_hal_xxx, hal_xxxx)

type yyy_hal_xxxx_exec, exec_type, file_type, vendor_file_type;

init_daemon_domain(yyy_hal_xxxx)

(4). Add this new HWService for server and client

/device/mediatek/sepolicy/bsp/non_plat/hal_xxxx.te

add_hwservice(hal_xxxx_server, yyy_hal_xxxx_hwservice)

allow hal_xxxx_client yyy_hal_xxxx_hwservice :hwservice_manager find;

#hwbinder IPC from clients into server, and callbacks

binder_call(hal_xxxx_client, hal_xxxx_server)

binder_call(hal_xxxx_server, hal_xxxx_client)

(6). Add other rules for server or client.

1.2 Binder/HWBinder/VndBinder
O 版本后新增了HWBinder, VndBinder, 即Binder 限于非vendor partition 使用, HWBinder 限于vendor / system 跨分区使用, Vndbinder 则限于非system partition 使用.

(1). Binder

binder_use(domain) // Allow domain to use Binder IPC

binder_service(domain) // Mark a domain as being a Binder service domain

binder_call(clientdomain, servicedomain) // Allow clientdomain to perform binder IPC to servicedomain (include: remote call service’s method, transfer binder object/FD to service)

  • if your domain is a service domain, please add ” binder_service(your_domain) ” to your te file;
  • if your domain is a client domain, please add ” binder_call(your_domain, servicedomain)” to your te file;
  • if you getService/addService/findService/listService from servicemanager, please add ” binder_use(your_domain) ” to your te file;

(2). HWBinder

Allow domain to use HWBinder IPC
hwbinder_use(domain)

Allow a set of permissions required for a domain to be a server which provides a HAL implementation over HWBinder.
hal_server_domain(domain, hal_type)

Allow a set of permissions required for a domain to be a client of a HAL of a specific type.
HAL_client_domain(domain, hal_type)

Allow clientdomain to perform hwbinder IPC to serverdomain, and callbacks
binder_call(hal_type_client, hal_type_server)

binder_call(hal_type_server, hal_type_client) // for callbacks.

(3). vndbinder

Allow domain to use vendor binder IPC (for vendor partition.)

 vndbinder_use(domain)

(4). combine above two in a macro, add_{hw}service().

add_service(domain_name, service_name) /* add/find permission rule to servicemanager */

add_hwservice (domain_name, service_name) /* add/find permission rule to hwservicemanager */

等价于:

    allow domain_name service_name:hwservice_manager { add find };

    neverallow { domain -domain_name } service_name:hwservice_manager add;

审查最终结果/确认更新

sepolicy 分离存储到system image 和 vendor image, 在编译完成后, 进行审查确认时, 可以查证:

/system/etc/selinux; /vendor/etc/selinux.

这里写图片描述

注意

  1. 维持external/sepolicy 与Google AOSP一致, 尽量不要修改. 特别是不要去除任何的neverallow 语句.

  2. 严禁修改untrusted_app.te, 放开untrusted_app 的权限.

  3. 系统关键进程启动长时间运行的process, 必须进行domain 切换. 比如netd, installd, vold, zygote 等.

  4. Native thread 严禁使用kernel 标签, 而kernel thread 除init 外, 都应当是kernel 标签.

  5. 在user build 中不能存在如su, recovery, init_shell 标签的进程.

  6. 在user build 中所有的process 都必须是Enforce Mode

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安德路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值