一、概念

1. 运行模式

Selinux有两种运行模式:Permissive和Enforcing。未明确配置权限,当访问时默认权限是拒绝。为方便开发调试权限配置,单个domain可设置为permissive模式,permissive domain

       语法格式

Selinux依赖于标签来匹配操作和策略,标签决定什么是允许的,套接字、文件和进程都在selinux中有标签。 Selinux决策基于分配给这些对象的标签和定义它们如何交互的策略,label的格式:user:role:type:mls_level,如/dev/amaudio_.*   u:object_r:audio_device:s0

策略(policy)的格式是:allow domains types:classes permissions:

  • Action:通常为allow、neverallow,常用的为allow
  • Domains:代表一个进程或者一组进程
  • Type:对象通过label定义一个代替对象的类型(type),通过定义的type映射到类;每个类的不同类型的访问由权限表示,如type btmic_data_file, file_type, data_file_type,此处对象通过type映射到类。
  • Class:selinux中被访问的对象(object)的类型
  • Permissions:可被执行的和class相关的操作

Selinux权限配置,其中元素关系如下图

 

 

Policy的意思为:在domains域中允许对标记为type类型的class执行permission操作。

例如:allow appdomain app_data_file:file rw_file_perms,所有应用程序域都允许读取和写入标记为app_data_file的文件

        attribute、domains、types

attribute、domains、types概念:

  • An attribute is simply a name for a set of domains or types.
  • Each domain or type can be associated with any number of attributes
  • When a rule is written that specifies an attribute name, that name is automatically expanded to the list of domains or types associated with the attribute

属性只是一组域或类型的名称。每个域或类型都可以与任意数量的属性相关联,例如

type tr069_service, netdomain, coredomain, domain;

tr069_service域和netdomain, coredomain, domain域属性关联。这里netdomain, coredomain, domain都是与属性,此时新域tr069_service属于netdomain, coredomain, domain这些域。例如

type tr069_service_exec, exec_type, file_type, system_file_type;

tr069_service_exec类型和exec_type, file_type, system_file_type类型属性关联。exec_type, file_type, system_file_type属于类型属性,tr069_service_exec属于exec_type, file_type, system_file_type这些类型。

当编写指定属性名称的规则时,该名称将自动扩展到与该属性关联的域或类型列表。因此,当有类似的域或类型需要同一个权限,此时可以把这些类似的类型或域关联到一个类型属性或域属性,指定规则时,使用类型属性或域属性代替具体的各类似类型。如此,可以精简策略配置。

根据以上语法,sepolicy中的xxx_contexts文件定义object的label,xxx.te文件中定义域、域进行与属性关联和类型关联,例如tr069_service.te文件

 

按照selinux编写语法,创建avc规则,规则的格式为:

RULE_VARIANT SOURCE_TYPES TARGET_TYPES : CLASSES PERMISSIONS

意思是:当带有source_types标记的object尝试对class类型的具有target_types标签对象执行permission相关的操作时,应发生什么(RULE_VARIANT)。

二、编译和验证

2.1 编译

在Andriod4.4至Andriod7.0,policy被编译合并为一个文件,放置boot.img或system.img。Andriod8.0及Android8.0+被分别编译,SOC和OEM被编译进vendor.img,如此需要在开机是,快速挂在/system和/vendro,在加载进kernel前合并policy。

AOSP中sepolicy资源文件有:

  1. External/selinux  用于编译主机命令行工具
  2. System/sepolicy Android核心selinux policy配置

 

selinux 初始化

在开机的初始阶段,SELinux 为permissive模式,init进程做一下工作:

  1. 通过/sys/fs/selinux/load加载系统中的sepolicy到kernel
  2. 切换selinux到enforcing模式
  3. 执行re-exec(),使selinux规则对自身起作用

2.2 验证

验证策略

若新增域,则初始设置为Permissive(Permissive模式,仅显示需要的权限,但不实际拒绝),分析dmesg和logcat中avc,完善和修正权限。由于在Permissive模式,会展开所有权限的需求,如此会导致一些实际不需要的权限也在log中体现,基于此,完成可理解的必要的权限配置后,尽早设置为Enforcing,调试依然存在的deny项。

初始设置为Permissive模式,有几种方式:

  • 整个设备运行在Permissive模式

配置selinux模式:修改kernel_cmdline 参数为BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive。该参数在BoardConfig.mk中添加。

  • 个别域设置为Permissive模式

在域的te文件开始处添加:permissive 域名,如下图所示

 

  • 设备运行状态,在命令行执行 setenforce 0

这种方式,设备重启后会恢复为Enforcing,如此,方便确认某个问题是权限导致。

在设备端使用getenforce获取当前selinux运行模式。

完善和修正权限

在设备运行过程中,若确实权限,分别可以在kernel log和logcat log中体现相应信息。根据获取到的denies信息,使用audit2allow命令生成指导性权限配置策略。生成指导性权限配置策略可以基于系统已配置权限,根据系统策略初始化方式:开机后,系统会合并AOSP和vendor sepolicy为一个policy文件,给kernel selinux初始化。因此可在设备中查找policy位置(通常会在),使用adb pull到本地,方便命令使用。命令如下

find -type f -name "policy" | grep "selinux"

运行时使用/sys/fs/selinux/policy文件,使用dmesg和logcat,获取denies的权限

 

dmesg | grep "avc:"

logcat -b all | grep "avc:"

把log保存在文件denies.txt中,在Android根目录执行

cat denies.txt | audit2allow -p policy

在盒端运行状态下,查看进程权限:ps -Z 查看权限,例如

ps -e -Z | grep audioserver

 

使用audit2allow 命令产生的权限仅作为指导性权限,作为分配权限的起点,从起点出发拆分和细化权限实现。例如,在system app通过manager获取某个binder服务时,若未配置权限,audit2allow生成的policy是配置获取对default_android_hwservice的相关权限,这明显是被系统默认不允许的,此种情况分析log中出现该权限需求的上下文,确定具体需要的服务名称,如tr069_service,此时可以把default_android_hwservice替换为具体的服务即可。其他出现对default_xxx的权限申请,都可以使用如此方式配置,也不排除有一些default_xxx的确是可以分配权限的。

三、实现SELinux

3.1 新增sepolicy

编写自己的sepolicy通常在/device/manufacturer/device-name/sepolicy目录下。8.0 and 8.0+,分为selinux policy分为system和vendor,一版情况下不能相互访问,关于system和vendor的兼容性policy开发,详见“定制化”和“Policy兼容性”。编写完policy,更新到系统,通过在/device/manufacturer/device-name/BoardConfig.mk中使用BOARD_SEPOLICY_DIRS、BOARD_VENDOR_SEPOLICY_DIRS或BOARD_SEPOLICY_UNION。BOARD_SEPOLICY_UNION赋值为te文件。添加方式,如:

BOARD_SEPOLICY_UNION += \

        genfs_contexts \

        file_contexts \

        sepolicy.te



BOARD_SEPOLICY_DIRS += \

        <root>/device/manufacturer/device-name/sepolicy

BOARD_SEPOLICY_DIRS和BOARD_VENDOR_SEPOLICY_DIRS的区别

 

注意:使新增的sepolicy编译到系统,可以在任意路径添加sepolicy,同样使用BOARD_SEPOLICY_DIRS或BOARD_VENDOR_SEPOLICY_DIRS或BOARD_SEPOLICY_UNION在可声明PRODUCT_PACKAGES的mk文件中添加新增sepolicy申明,例如

 

3.2 客制化

在/device/manufacturer/device-name/sepolicy下实现:

1)初始时,新的域中设置为宽容模式(如permissive dhcp;),在userdebug模式调试权限完后,关闭该模式

2)如xxx_domain(dhcp),dhcp可以使用xxx的功能

3)不同类型对象拥有的权限,参考Available controls: https://source.android.com/security/selinux/customize

8.0及8.0+客制化

在8.0之前使用BOARD_SEPOLICY_DIRS添加策略,编译后,策略被结合添加在AOSP策略中,一起打包入platform image;现在使用BOARD_SEPOLICY_DIRS添加的策略放置在vendor image中。使AOSP和vendor分离,系统实现treble化(简单理解:降低系统耦合,提高系统的可扩展性,和模块独立性)。

不同的场景,policy实现的方案不同,在这些场景中,服务分为一下几种:

  • 仅仅在vendor中运

使用vndservicemanager注册服务;在device/manufacturer/device-name/sepolicy中添加策略

  • 和AOSP交互的服务

使用hwservicemanager注册服务,实现了AOSP中定义的hal;在device/manufacturer/device-name/sepolicy中添加策略,system/sepolicy/public/也被编译到vendor image

  • 仅可以被AOSP调用的服务

作为AOSP的外延,在system/sepolicy/private中添加策略,不可以和vendor image交互。可以被framework-only OTA升级;只可使用system/sepolicy/public中定义的策略

  • 作为vendor的延伸服务于AOSP扩展的组件

存在于AOSP system image的client,扩展实现了非AOSP hal,如system_server延伸。必须在device/manufacturer/device-name/sepolicy中添加策略,system/sepolicy/public/也被编译到vendor image,system、vendor间交互使用的策略。和AOSP交互的服务的区别是:不需要修改AOSP组件;仅和system image延伸交互的AOSP组件,新增的policy必选添加在system/sepolicy/private

  • System image的延伸仅访问AOSP interface

非AOSP system进程使用一个AOSP依赖的HAL。在system/sepolicy/private中添加策略,只可使用system/sepolicy/public中定义的策略;可能使用system/vendor的接口,也可以在device/manufacturer/device-name/sepolicy添加策略,但是升级后导致system/sepolicy/private中新的策略不可用

  • Vendor image的延伸,服务于一个新的system组件

添加一个新的非AOSP hal,服务于一个AOSP中没有的新的client进程。System、vendor之间交互的policy必须在device/manufacturer/device-name/sepolicy中实现,可以对system/sepolicy/public扩展,不可以删除已存在policy,扩展部分可以被system/sepolicy/private 和device/manufacturer/device-name/sepolicy使用;仅新的type和相应的allow规则被添加到system/sepolicy/public,另外新的type,不可以被/vendor下的policy直接使用。

按照以上定义的场景,可以根据实际情况,确定新增服务的位置,合理实现sepolicy。

3.3 Policy兼容性

为了避免由于OTA升级,导致label冲突,在编写selinux policy,使用命名空间。对于type/attribute,vendor使用的声明以np_开头,如type foo, domain; → type np_foo, domain;

对于property,使用如下策略

 

Vendor可以继续使用ro.boot.*(来自于kernel cmdline)和ro.hardware.*(明显和硬件相关的属性)。对于service,所有的vendor services的init rc,命名为vendor.xxx.rc;类似的vendor property的label,使用vendor_xxx。更细节的兼容性设计,详见https://source.android.google.cn/security/selinux/compatibility?hl=en

附录

Selinux官方文档:https://source.android.com/security/selinux

 

 

 

GitHub 加速计划 / sel / selinux
150
64
下载
common selinux implementation
最近提交(Master分支:3 个月前 )
1b71cb46 pwalk, pwalkdir: fix walk vs remove race 1 年前
40a1afee Misc nitpicks 1 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐