Android 使用 SELinux 对所有进程强制执行强制访问控制 (MAC),其中包括以 Root/超级用户权限运行的进程(也称为 Linux 功能)。SELinux 能够限制特权进程并能够自动创建安全政策,从而可提升 Android 的安全性。
SELinux 还支持基于域的宽容模式。在这种模式下,可将特定域(进程)设为宽容模式,同时使系统的其余部分处于强制全局模式。域简单来说就是安全政策中用于标识一个进程或一组进程的标签,安全政策会以相同的方式
对待所有具有相同域标签的进程。借助基于域的宽容模式,可逐渐将 SELinux 应用于系统中越来越多的部分,还可以为新服务制定政策(同时确保系统的其余部分处于强制模式)。
Enforcing:强制模式,SELinux 运作中,且已经正确的开始限制 domain/type
Permissive:宽容模式,SELinux 运作中,仅会有警告讯息并不会限制 domain/type 的存取
userdebug 版本开机后,可以通过adb命令来查看或设置SELinux模式(设置后需重启shell才真正生效,手机重启后恢复),可以用此方法排除问题:
adb shell getenforce,会返回 Enforcing 或 Permissive
adb shell setenforce 1或0,设置其为 Enforcing 或 Permissive
基于 Android 4.3(宽容模式)和 Android 4.4(部分强制模式)的 Android 5.0 版本,开始全面强制执行 SELinux。
通过此项变更,Android 已从对有限的一组关键域(installd、netd、vold 和 zygote)强制执行 SELinux 转为对所有
域(超过 60 个域)强制执行 SELinux。具体而言:
在 Android 5.x 及更高版本中,所有域均处于强制模式。init 以外的任何进程都不应在 init 域中运行。
如果出现任何常规拒绝事件(对于 block_device、socket_device、default_service 等),都表示设备需要一个特殊域。
8.0开始分platform sepolicy和vendor sepolicy
When the system boots up, SELinux is in permissive mode (and not in enforcing mode). The
init process performs the following tasks:
SELinux 依靠标签来匹配操作和政策。标签用于决定允许的事项。套接字、文件和进程在 SELinux 中都有标签。
SELinux 决定基本上是根据为这些对象分配的标签以及定义这些对象可以如何交互的政策做出的。在 SELinux 中,
标签采用以下形式:user:role:type:mls_level,其中 type 是访问决定的主要组成部分,可通过构成标签的其他
组成部分进行修改。对象会映射到类,对每个类的不同访问类型由权限表示。
规则采用以下形式:allow domains types:classes permissions;,其中:
Domain - 一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。
Type - 一个对象(例如,文件、套接字)或一组对象的标签。
Class - 要访问的对象(例如,文件、套接字)的类型。
Permission - 要执行的操作(例如,读取、写入)。
使用政策规则时将遵循的结构示例:
allow appdomain app_data_file:file rw_file_perms;
这表示所有应用域都可以读取和写入带有 app_data_file 标签的文件
创建构成 SELinux 政策基本内容的 avc 规则。规则采用以下形式:
RULE_VARIANT SOURCE_TYPES TARGET_TYPES : CLASSES PERMISSIONS
例如:
allow domain null_device:chr_file { open }
该规则允许具有与“domain”属性关联的任何域的进程对 target_type 标签为“null_device”的“chr_file”类(字符设备文件)的对象执行“open”权限所描述的操作。在实际中,该规则可能会扩展为包含其他权限:
当了解到“domain”是分配给所有进程域的属性,并且 null_device 是字符设备 /dev/null 的标签时,该规则基本上会允许对 /dev/null 进行读写操作。
典型的 Android 应用会在自己的进程中运行,并且具有 untrusted_app 标签(用于向其授予特定受限权限)。
系统中内置的平台应用会以单独的标签运行,并会被授予一组不同的权限。作为核心 Android 系统的一部分,系统 UID 应用以表示另一组权限的 system_app 标签运行。
在任何情况下,都不应直接允许域访问以下通用标签;而应为一个或多个对象创建一个更具体的类型:
socket_device
device
block_device
default_service
system_data_file
tmpfs
步骤总结:
下面简要总结了在 Android 设备上实现 SELinux 时需要执行的步骤:
1. 在内核和配置中添加 SELinux 支持。
2. 为通过 init 启动的每项服务(进程或守护进程)分配专用的域。
3. 通过以下方式标识这些服务:
查看 init.<device>.rc 文件并找到所有服务。
检查以下形式的警告:init: Warning! Service name needs a SELinux domain defined; please fix!(init:警告!服务名称需要一个已定义的 SELinux 网域;请更正!) (在 dmesg 输出中检查)。
检查 ps -Z | grep init 输出,看看哪些服务正在 init 网域中运行。
4. 为所有新进程、驱动程序、套接字等添加标签。需要为所有对象添加适当的标签,以确保它们能够与您应用的政策正确交互。请参阅 AOSP 中使用的标签,以便在创建标签名称时参考。
5. 制定全面涵盖所有标签的安全政策,并将权限限定到其绝对最低级别。
原始设备制造商 (OEM) 最好从 AOSP 中的政策入手,然后在这些政策的基础上创建自己的自定义政策。
一般应该不需要直接修改 system/sepolicy 中的文件,而只需添加您自己的设备专用政策文件(位于 /device/manufacturer/device-name/sepolicy 目录中)即可。
要实现 SELinux,您必须创建或修改以下文件:
1.新的 SELinux 政策源代码 (*.te) 文件 - 位于 /device/manufacturer/device-name/sepolicy 目录中。这些文件用于定义域及其标签。在编译到单个 SELinux 内核政策文件时,新的政策文件会与现有的政策文件组合在一起。
> 请勿更改 Android 开放源代码项目提供的 app.te 文件,否则可能会破坏所有第三方应用。
2.更新后的 BoardConfig.mk makefile - 位于包含 sepolicy 子目录的目录中。如果初始实现中没有 sepolicy 子目录,那么在该子目录创建之后,必须更新 BoardConfig.mk makefile,以引用该子目录。
3.file_contexts - 位于 sepolicy 子目录中。该文件用于为文件分配标签,并且可供多种用户空间组件使用。在创建新政策时,请创建或更新该文件,以便为文件分配新标签。
4.genfs_contexts - 位于 sepolicy 子目录中。该文件用于为不支持扩展属性的文件系统(例如,proc 或 vfat)分配标签。此配置会作为内核政策的一部分进行加载,但更改可能对核心内 inode 无效。要全面应用更改,需要重
新启动设备,或卸载后重新装载文件系统。此外,通过使用 context=mount 选项,还可以为装载的特定系统文件(例如 vfat)分配特定标签。
5.property_contexts - 位于 sepolicy 子目录中。该文件用于为 Android 系统属性分配标签,以便控制哪些进程可以设置这些属性。在启动期间,init 进程会读取此配置。
6.service_contexts - 位于 sepolicy 子目录中。该文件用于为 Android Binder 服务分配标签,以便控制哪些进行可以为相应服务添加(注册)和查找(查询)Binder 引用。在启动期间,servicemanager 进程会读取此配置。
7.seapp_contexts - 位于 sepolicy 子目录中。该文件用于为应用进程和 /data/data 目录分配标签。在每次应用启动时,zygote 进程都会读取此配置;在启动期间,installd 会读取此配置。
8.mac_permissions.xml - 位于 sepolicy 子目录中。该文件用于根据应用签名和应用软件包名称(后者可选)为应用分配 seinfo 标记。然后,分配的 seinfo 标记可在 seapp_contexts 文件中用作密钥,以便为带有该 seinfo
标记的所有应用分配特定标签。在启动期间,system_server 会读取此配置。
接下来,只需在 sepolicy 子目录和各个政策文件创建之后,更新 BoardConfig.mk Makefile(位于包含 sepolicy 子目录的目录中)以引用该子目录和这些政策文件即可,如下所示。BOARD_SEPOLICY 变量及其含义记录在 system/sepolicy/README 文件中。
BOARD_SEPOLICY_DIRS += \
<root>/device/manufacturer/device-name/sepolicy
BOARD_SEPOLICY_UNION += \
genfs_contexts \
file_contexts \
sepolicy.te
从 M 版开始已不再需要 BOARD_SEPOLICY_UNION,因为 BOARD_SEPOLICY_DIRS 变量中包含的任何目录内的所有政策文件都会与基本政策自动合并。
下面详细介绍了 Android 建议您如何采用并自定义 SELinux 来保护设备:
1 在内核中启用 SELinux: CONFIG_SECURITY_SELINUX=y
2 更改 kernel_cmdline 参数,以便: BOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
这仅适用于初始制定设备政策的情况。在拥有初始引导程序政策后,请移除此参数,以便将设备恢复强制模式,否则设备将无法通过 CTS 验证。
3 以宽容模式启动系统,看看在启动时会遇到哪些拒绝事件:
在 Ubuntu 14.04 或更高版本中:
adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
4 评估输出。如需查看相关说明和工具
5 标识设备以及需要添加标签的其他新文件
6 为您的对象使用现有标签或新标签。查看 *_contexts 文件,了解之前是如何为内容添加标签的,然后根据对标签含义的了解分配一个新标签。这最好是一个能够融入到政策中的现有标签,但有时需要使用新标签,并且还需要关于访问该标签的规则。
7 标识应该拥有自己的安全域的域/进程。可能需要为其中每个域/进程从头开始编写政策。例如,从 init 衍生的所有服务都应该有自己的安全域。可以通过以下命令查看保持运行的服务(不过所有服务都需要如此处理):
adb shell su -c ps -Z | grep init
adb shell su -c dmesg | grep 'avc: '
8 查看 init.<device>.rc,以找出所有没有类型的服务。应提早为此类服务提供域,以避免向 init 添加规则或将 init 访问权限与其自身政策中的访问权限混淆。
9 将 BOARD_CONFIG.mk 设为使用 BOARD_SEPOLICY_* 变量。如需关于如何进行此项设置的详细信息,请参阅 system/sepolicy 中的 README。
10 检查 init.<device>.rc 和 fstab.<device> 文件,确保每一次使用“mount”都对应一个添加了适当标签的文件系统,或者指定了 context= mount 选项。
11 查看每个拒绝事件,并创建 SELinux 政策来妥善处理每个拒绝事件。请参阅自定义中的示例。
SELinux neverallow 规则用于禁止在任何情况下都不应该发生的行为。通过执行兼容性测试,现在各种合作伙伴设备上都会强制执行 SELinux neverallow 规则。
以下准则旨在协助制造商在自定义过程中避免与 neverallow 规则相关的错误。此处使用的规则编号与 Android 5.1 中使用的编号一致,并且会因版本而异。
规则 48:neverallow { domain -debuggerd -vold -dumpstate -system_server } self:capability sys_ptrace;
请参阅 ptrace 的帮助页面。sys_ptrace 权能用于授予对任何进程执行 ptrace 命令的权限。拥有该权限后,可以对其他进程进行广泛的控制。只有该规则中列出的指定系统组件才能享有该权限。如果需要该权能,则通常表明存在的某些内容不适用于面向用户的版本或存在不需要的功能。请移除不必要的组件。
规则 76:neverallow { domain -appdomain -dumpstate -shell -system_server -zygote } { file_type -system_file -exec_type }:file execute;
该规则旨在防止执行系统中的任意代码。具体来说,该规则声明仅执行 /system 中的代码,以便通过验证启动等机制实现安全保证。通常,在遇到与这个 neverallow 规则相关的问题时,最好的解决办法是将违规代码移到 /system 分区。
SELinux policy 是由核心的aosp策略(平台(platform ))和设备专用策略(供应商(vendor) )结合而成的。SELinux policy 从android 4.4 到android 7.0 编译时合并了所有的策略片段,然后在根目录中生成单一文件。也就意味着:
SoC vendors 和 ODM manufacturers modified boot.img (for non-A/B devices) or system.img (for A/B devices) every time policy was modified.
Android 8.0 以后包括8.0, platform 和vendor policy 是分开编译的. 所以 SOCs and OEMs可以各自更新 他们的策略部分,编译他们的images (vendor.img, boot.img, etc.),然后独立更新这些images ( update those images independent of platform updates.)
但是,由于模块化的selinux策略文件存储在/厂商vendor分区上,init进程必须更早地挂载system 和 vendor 分区,这样它才能从这些分区中读取selinux文件,并将它们与系统目录中的核心selinux文件合并(在将它们加载到内核之前)。
对于Android 8.0及其后续版本
platform sepolicy 进一步分为 platform private 和 platform public 部分,以便 向vendor policy 编写者输出特定的 types 和attributes.
The platform public types/attributes are guaranteed to be maintained as stable APIs for a given platform version. Compatibility with previous platform public types/attributes can be guaranteed for several versions using platform mapping files.(保证兼容性和稳定性)
system/sepolicy/public
The platform can assume the types and attributes defined under public policy are stable APIs for a given platform version. This forms the part of the sepolicy that is exported by platform on which vendor (i.e. device) policy developers may write additional device-specific policy.
Types are versioned according to the version of the policy that vendor files are written against, defined by the PLATFORM_SEPOLICY_VERSION build variable. The versioned public policy is then included with the vendor policy and (in its original form) in the platform policy. Thus, the final policy includes the private platform policy, the current platform’s public sepolicy, the device-specific policy, and the versioned public policy corresponding to the platform version against which the device policy was written.
/system/sepolicy/private
This part of the policy forms platform-only types, permissions, and attributes required for platform functionality.
These are not exported to the vendor/device policy writers.
Non-platform policy writers must not write their policy extensions based on types/attributes/rules defined in platform private sepolicy .Moreover, these rules are allowed to be modified or may disappear as part of a framework-only update.
The platform private mapping includes policy statements that map the attributes exposed in platform public policy of the previous platform versions to the concrete types used in current platform public sepolicy. This ensures vendor policy that was written based on platform public attributes from the previous platform public sepolicy version(s) continues to work. The versioning is based on the PLATFORM_SEPOLICY_VERSION build variable set in AOSP for a given platform version. A separate mapping file exists for each previous platform version from which this platform is expected to accept vendor policy.
Location
Contains
system/sepolicy/public
The platform’s sepolicy API
system/sepolicy/private
Platform implementation details (vendors can ignore)
system/sepolicy/vendor
Policy and context files that vendors can use (vendors can ignore if desired)
BOARD_SEPOLICY_DIRS
Vendor sepolicy
The build system takes this policy and produces platform and vendor policy components on the system partition and vendor partition, respectively.
步骤:
1 将policies 转化成 SELinux 的通用语言形式:Common Intermediate Language (CIL)
public platform policy
combined private + public policy
public + vendor and BOARD_SEPOLICY_DIRS policy
2 Versioning the policy provided by public as part of the vendor policy. Done by using the produced public CIL policy to inform the combined public + vendor + BOARD_SEPOLICY_DIRS policy as to which parts must be turned into attributes that will be linked to the platform policy.
3 Creating a mapping file linking the platform and vendor parts. Initially, this just links the types from the public policy with the corresponding attributes in the vendor policy; later it will also provide the basis for the file maintained in future platform versions, enabling compatibility with vendor policy targeting this platform version.
4 Combining policy files (describe both on-device and precompiled solutions).
Combine mapping, platform and vendor policy.
Compile output binary policy file.
基于Treble的SELinux policy 对于platform 和vendor policy设计考虑了一个二进制的区别; 如果 vendor 分区存在这样的依赖关系, 比如 platform < vendor < oem. 这种设计会变的更加复杂。
对于Android 8.0 以及更高版本, SELinux 全局policy 分为 private 和public 两部分. Public 部分由policy 和相关的结构(infrastructure)组成, 以保证对于平台版本可用。此public策略将向vendor策略编写者公开,以使供应商能够构建一个供应商策略文件,该文件与平台提供的策略结合起来,将产生设备的全功能策略(fully-functional policy)。
For versioning, the exported platform-public policy will be written as attributes.
For ease of policy writing, exported types will be transformed into versioned attributes as part of the policy build process. Public types may also be used directly in labeling decisions provided by vendor contexts files.
Android maintains a mapping between exported concrete types in platform policy and the corresponding versioned attributes for each platform version. 对于每一个platform version,Android在platform policy公开的具体type和关联的版本属性之间维持着一个映射关系。
This ensures that when objects are labeled with a type, it does not break behavior guaranteed by the platform-public policy in a previous version. This mapping is maintained by keeping a mapping file up-to-date for each platform version, which keeps attribute membership information for each type exported in public policy.
##Object ownership and labeling
Android 8.0 and higher定制policy时, ownership 必须清楚的定义每一个object 以确保 platform 和vendor policy 分离.
比如:如果 vendor labels /dev/foo 并且在后续OTA升级时 platform也 labels /dev/foo, 就会出现未定义的行为,表现 出label冲突. 设备节点只能有一个label。
System properties也会有潜在的命名冲突,导致system中的未定义行为出现
To avoid these issues, clearly define ownership of these objects.
In addition to label collisions, SELinux type/attribute names may also collide. A type/attribute name collision will always result in a policy compiler error.
##Type/attribute namespacing
SELinux does not allow multiple declarations of the same type/attribute. Policy with duplicate declarations will fail to compilation. To avoid type and attribute name collisions, all vendor declarations should be namespaced starting with np_.
type foo, domain; → type np_foo, domain;
##System property and process labeling ownership
为了方便识别平台属性,并在重命名或添加导出平台属性时避免名称冲突,应确保所有供应商属性都有自己的前缀:
Property type
Acceptable prefixes (前缀)
read-writable
vendor.
read-only
ro.vendor. && ro.boot. && ro.hardware.(hardware-related property)
persistent
persist.vendor.
All the vendor services in init rc files should have vendor. for services in init rc files of non-system partitions. Similar rules are applied to the SELinux labels for the vendor properties (vendor_ for the vendor properties).
Preventing collisions for files is challenging because platform and vendor policy both commonly provide labels for all filesystems. Unlike type naming, namespacing of files is not practical since many of them are created by the kernel. To prevent these collisions, follow the naming guidance for filesystems in this section. For Android 8.0, these are recommendations without technical enforcement. In the future, these recommendations will be enforced by the Vendor Test Suite (VTS).
Only the system image must provide labels for /system components through file_contexts, service_contexts, etc. If labels for /system components are added in /vendor policy, a framework-only OTA update may not be possible.
The AOSP SELinux policy already labels parts of vendor partition the platform interacts with, which enables writing SELinux rules for platform processes to be able to talk and/or access parts of vendor partition. Examples:
/vendor path
Platform-provided label
Platform processes depending on the label
/vendor(/.*)?
vendor_file
All HAL clients in framework, ueventd, etc.
/vendor/framework(/.*)?
vendor_framework_file
dex2oat, appdomain, etc.
/vendor/app(/.*)?
vendor_app_file
dex2oat, installd, idmap, etc.
/vendor/overlay(/.*)
vendor_overlay_file
system_server, zygote, idmap, etc.
As a result, specific rules must be followed (enforced through neverallows) when labelling additional files in vendor partition:
Files in /proc may be labeled using only the genfscon label. In Android 7.0, both the platform and vendor policy used genfscon to label files in procfs.
Recommendation: Only platform policy labels /proc. If vendor processes need access to files in /proc that are currently labeled with the default label (proc), vendor policy should not explicitly label them and should instead use the generic proc type to add rules for vendor domains. This allows the platform updates to accommodate future kernel interfaces exposed through procfs and label them explicitly as needed.
Debugfs can be labeled in both file_contexts and genfscon. In Android 7.0, both platform and vendor label debugfs.
Recommendation: In the short term, only vendor policy may label debugfs. In the long term, remove debugfs.
Tracefs can be labeled in both file_contexts and genfscon. In Android 7.0, only the platform labels tracefs.
Recommendation: Only platform may label tracefs.
Files in /sys may be labeled using both file_contexts and genfscon. In Android 7.0, both platform and vendor use file_contexts and genfscon to label files in sysfs.
Recommendation: The platform may label sysfs nodes that are not device-specific. Otherwise, only vendor may label files.
Files in /dev may be labeled in file_contexts. In Android 7.0, both platform and vendor label files here.
Recommendation: Vendor may label only files in /dev/vendor (e.g., /dev/vendor/foo, /dev/vendor/socket/bar).
Files in / may be labeled in file_contexts. In Android 7.0, both platform and vendor label files here.
Recommendation: Only system may label files in /.
Data is labeled through a combination of file_contexts and seapp_contexts.
Recommendation: Disallow vendor labeling outside /data/vendor. Only platform may label other parts of /data.
添加policy的形式
allow source_type target_type:target_class permission(s);
if the vendor policy and platform policy use specific types, and the label of a specific object changes in only one of those policies, the other may contain policy that gained or lost access previously relied upon. For example:
File_contexts:
/sys/A u:object_r:sysfs:s0
Platform: allow p_domain sysfs:class perm;
Vendor: allow v_domain sysfs:class perm;
Could be changed to:
File_contexts:
/sys/A u:object_r:sysfs_A:s0
Although the vendor policy would remain the same, the v_domain would lose access due to the lack of policy for the new sysfs_A type.
Android 9 包含下面域相关的属性:
data_between_core_and_vendor_violators:
Platform 和 vendor 进程(processes) shouldn’t use on-disk files to communicate (unstable ABI).
Recommendation:
system_executes_vendor_violators:
对于所有system域的属性(system domains (except init and shell domains) that 违反 the requirement of not executing vendor binaries. Execution of vendor binaries has unstable API. Platform shouldn’t execute vendor binaries directly.
Recommendation:
Untrusted apps 的任意代码都不能访问HwBinder services, except those considered sufficiently safe for access from such apps(除了那些被认为足够安全的应用程序(见下面的 安全服务 ))。两个主要原因是:
包括:
**same_process_hwservice: ** These services (by definition) run in the process of the client and thus have the same access as the client domain in which the process runs
coredomain_hwservice: These services do not pose risks associated with reason #2.
**hal_configstore_ISurfaceFlingerConfigs.:**This service is specifically designed for use by any domain.
hal_graphics_allocator_hwservice. These operations are also offered by surfaceflinger Binder service, which apps are permitted to access.
hal_omx_hwservice. This is a HwBinder version of the mediacodec Binder service, which apps are permitted to access.
hal_codec2_hwservice. This is a newer version of hal_omx_hwservice.
All hwservices not considered safe have the attribute untrusted_app_visible_hwservice. The corresponding HAL servers have the attribute untrusted_app_visible_halserver. Devices launching with Android P MUST NOT use either untrusted attribute.
建议:
1. Untrusted apps should instead talk to a system service that talks to the vendor HIDL HAL.
比如 apps can talk to binderservicedomain, then mediaserver (which is a binderservicedomain) in turn talks to the hal_graphics_allocator.
OR
2. Apps that need direct access to vendor HALs should have their own vendor-defined sepolicy domain…
Android 9 includes build time tests that ensure all files in specific locations have the appropriate attributes (such as, all files in sysfs have the required sysfs_type attribute).
#Platform-public policy
The platform-public policy is the core of conforming to the Android 8.0 architecture model without simply maintaining the union of platform policies from v1 and v2. Vendors are exposed to a subset of platform policy that contains useable types and attributes and rules on those types and attributes which then becomes part of vendor policy (i.e. vendor_sepolicy.cil).
Types and rules are automatically translated in the vendor-generated policy into attribute_vN such that all platform-provided types are versioned attributes (however attributes are not versioned). The platform is responsible for mapping the concrete types it provides into the appropriate attributes to ensure that vendor policy continues to function and that the rules provided for a particular version are included. The combination of platform-public policy and vendor policy satisfies the Android 8.0 architecture model goal of allowing independent platform and vendor builds.
When using attributes to map to policy versions, a type maps to an attribute or multiple attributes, ensuring objects labeled with the type are accessible via attributes corresponding to their previous types.
Maintaining a goal to hide version information from the policy writer means automatically generating the versioned attributes and assigning them to the appropriate types. In the common case of static types, this is straightforward: type_foo maps to type_foo_v1.
For an object label change such as sysfs → sysfs_A or mediaserver → audioserver, creating this mapping is non-trivial (and is described in the examples above). Platform policy maintainers must determine how to create the mapping at transition points for objects, which requires understanding the relationship between objects and their assigned labels and determining when this occurs. For backwards compatibility, this complexity needs to be managed on the platform side, which is the only partition that may uprev.
For simplicity, the Android platform releases an sepolicy version when a new release branch is cut. As described above, the version number is contained in PLATFORM_SEPOLICY_VERSION and is of the form MM.nn, where MM corresponds to the SDK value and nn is a private value maintained in /platform/system/sepolicy. For example, 19.0 for Kitkat, 21.0 for Lollipop, 22.0 for Lollipop-MR1 23.0 for Marshmallow, 24.0 for Nougat, 25.0 for Nougat-MR1, 26.0 for Oreo, 27.0 for Oreo-MR1, and 28.0 for Android P. Uprevs aren’t always whole numbers. For example, if an MR bump to a versions necessitates an incompatible change in system/sepolicy/public but not an API bump, then that sepolicy version could be: vN.1. The version present in a development branch is a never-to-be-used-in-shipping-devices 10000.0.
Android may deprecate oldest version when upreving. For input on when to deprecate a version, Android may collect the number of devices with vendor policies running that Android version and still receiving major platform updates. If the number is less than a certain threshold, that version is deprecated.
As described in https://github.com/SELinuxProject/cil/issues/9, a large number of attributes assigned to a type result in performance issues in the event of a policy cache miss.
This was confirmed to be an issue in Android, so changes were made to Android 8.0 to remove attributes added to the policy by the policy compiler, as well as to remove unused attributes. These changes resolved performance regressions.
To support the distinction between platform and vendor sepolicy, the system builds SELinux context files differently to keep them separate.为了支持平台和供应商策略之间的区别,系统以不同的方式构建selinux上下文文件,以保持它们的分离。
##File contexts
Android 8.0 introduced the following changes for file_contexts:
To avoid additional compilation overhead on device during boot, file_contexts cease to exist in the binary form. Instead, they are readable, regular expression text file such as {property, service}_contexts (as they were pre-7.0).
The file_contexts are split between two files:
plat_file_contexts
Android platform file_context that has no device-specific labels, except for labeling parts of /vendor partition that must be labeled precisely to ensure proper functioning of the sepolicy files.
Must reside in system partition at /system/etc/selinux/plat_file_contexts on device and be loaded by init at the start along with the vendor file_context.
vendor_file_contexts
Device-specific file_context built by combining file_contexts found in the directories pointed to by BOARD_SEPOLICY_DIRS in the device’s Boardconfig.mk files.
Must be installed at /vendor/etc/selinux/vendor_file_contexts in vendor partition and be loaded by init at the start along with the platform file_context.
In Android 8.0, the property_contexts is split between two files:
plat_property_contexts
Android platform property_context that has no device-specific labels.
Must reside in system partition at /system/etc/selinux/plat_property_contexts and be loaded by init at the start along with the vendor property_contexts.
vendor_property_contexts
Device-specific property_context built by combining property_contexts found in the directories pointed to by BOARD_SEPOLICY_DIRS in device’s Boardconfig.mk files.
Must reside in vendor partition at /vendor/etc/selinux/vendor_property_contexts and be loaded by init at the start along with the platform property_context
In Android 8.0, the service_contexts is split between the following files:
plat_service_contexts
Android platform-specific service_context for the servicemanager. The service_context has no device-specific labels.
Must reside in system partition at /system/etc/selinux/plat_service_contexts and be loaded by servicemanager at the start along with the vendor service_contexts.
vendor_service_contexts
Device-specific service_context built by combining service_contexts found in the directories pointed to by BOARD_SEPOLICY_DIRS in the device’s Boardconfig.mk files.
Must reside in vendor partition at /vendor/etc/selinux/vendor_service_contexts and be loaded by servicemanager at the start along with the platform service_contexts.
Although servicemanager looks for this file at boot time, for a fully compliant TREBLE device, the vendor_service_contexts MUST NOT exist. This is because all interaction between vendor and system processes MUST go through hwservicemanager/hwbinder.
plat_hwservice_contexts
Android platform hwservice_context for hwservicemanager that has no device-specific labels.
Must reside in system partition at /system/etc/selinux/plat_hwservice_contexts and be loaded by hwservicemanager at the start along with the vendor_hwservice_contexts.
vendor_hwservice_contexts
Device-specific hwservice_context built by combining hwservice_contexts found in the directories pointed to by BOARD_SEPOLICY_DIRS in the device’s Boardconfig.mk files.
Must reside in vendor partition at /vendor/etc/selinux/vendor_hwservice_contexts and be loaded by hwservicemanager at the start along with the plat_service_contexts.
vndservice_contexts
Device-specific service_context for the vndservicemanager built by combining vndservice_contexts found in the directories pointed to by BOARD_SEPOLICY_DIRS in the device’s Boardconfig.mk.
This file must reside in vendor partition at /vendor/etc/selinux/vndservice_contexts and be loaded by vndservicemanager at the start.
In Android 8.0, the seapp_contexts is split between two files:
plat_seapp_contexts
Android platform seapp_context that has no device-specific changes.
Must reside in system partition at /system/etc/selinux/plat_seapp_contexts.
vendor_seapp_contexts
Device-specific extension to platform seapp_context built by combining seapp_contexts found in the directories pointed to by BOARD_SEPOLICY_DIRS in the device’s Boardconfig.mk files.
Must reside in vendor partition at /vendor/etc/selinux/vendor_seapp_contexts.
Android 8.0开始 mac_permissions.xml分为两部分:
/system/etc/selinux/.
/vendor/etc/selinux/.
#验证 SELinux
通过执行 getenforce 命令来确认 SELinux 在设备上的运行模式是否正确
该命令会显示全局 SELinux 模式:强制或宽容。要确定每个域的 SELinux 模式
MTK
android/vendor/mediatek/proprietary/bootable/bootloader/lk/platform/mt6739/rules.mk
# choose one of following value -> 1: disabled/ 2: permissive /3: enforcing
8 SELINUX_STATUS := 3
9
10 # set kernel decompress size limit (50MB)
11 KERNEL_DECOMPRESS_SIZE := 0x03200000
12 DEFINES += KERNEL_DECOMPRESS_SIZE=$(KERNEL_DECOMPRESS_SIZE)
13
14 # overwrite SELINUX_STATUS value with PRJ_SELINUX_STATUS, if defined. it's by project variable.
15 ifdef PRJ_SELINUX_STATUS
16 SELINUX_STATUS := $(PRJ_SELINUX_STATUS)
17 endif
18
19 ifeq (yes,$(strip $(MTK_BUILD_ROOT)))
20 SELINUX_STATUS := 2
21 DEFINES += MTK_BUILD_ROOT
22 endif
错误会以事件日志的形式传给 dmesg 和 logcat,SELinux 日志消息中包含“avc:”字样, 示例如下:
avc: denied { connectto } for pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket
该输出的解读如下:
1 上方的 { connectto } 表示执行的操作。根据它和末尾的 tclass (unix_stream_socket),您可以大致了解是对什么对象执行什么操作。在此例中,是操作方正在试图连接到 UNIX 信息流套接字。
2 scontext (u:r🐚s0) 表示发起相应操作的环境,在此例中是 shell 中运行的某个程序。
3 tcontext (u:r:netd:s0) 表示操作目标的环境,在此例中是归 netd 所有的某个 unix_stream_socket。
4 顶部的 comm=“ping” 可帮助您了解拒绝事件发生时正在运行的程序。在此示例中,给出的信息非常清晰明了。
以下是此拒绝事件的关键元素:
操作 - 试图进行的操作会使用括号突出显示:read write 或 setenforce。
操作方 - scontext(来源环境)条目表示操作方;在此例中为 rmt_storage 守护进程。
对象 - tcontext(目标环境)条目表示是对哪个对象执行操作;在此例中为 kmem。
结果 - tclass(目标类别)条目表示操作对象的类型;在此例中为 chr_file(字符设备)
##切换到宽容模式
重要提示:生产设备不支持宽容模式。CTS 测试会确认是否已启用强制模式。
SELinux 强制模式可以在 userdebug 或 eng 版本中通过 ADB 停用。为此,请先运行 adb root 以将 ADB 切换为 root 权限。然后,要停用 SELinux 强制模式,请运行以下命令:
adb shell setenforce 0
或在内核命令行中输入以下命令(适用于设备开发初期):
androidboot.selinux=permissive
androidboot.selinux=enforcing
selinux/policycoreutils/audit2allow 工具可以获取 dmesg 拒绝事件并将其转换成相应的 SELinux 政策声明。因此,该工具有助于大幅加快 SELinux 开发速度。 audit2allow 包含在 Android 源代码树中,会在您基于源代码编译 Android 时自动编译。
要使用该工具,请运行以下命令:
adb pull /sys/fs/selinux/policy
adb logcat -b all -d | audit2allow -p policy
注意:运行这些命令不会更改 bugreport.txt,因为所有日志都已经存在,包括上次重新启动之前存在的日志。在设备进行 OTA 更新或向设备刷入开发版系统时,新旧违规行为会混杂在一起,直到下一次重新启动为止。要解决此问题,请重新启动设备,或者从您的错误报告中滤除 console-ramoops 和 LAST_LOGCAT。
不过,请务必仔细审核要添加到政策中的条目,以免出现权限过宽的情况。例如,如果将上面的 rmt_storage 拒绝事件输入到 audit2allow 中,会生成以下 SELinux 政策声明建议:
#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };
这会授予 rmt 向内核内存写入内容的权限,从而形成明显的安全漏洞。通常情况下,audit2allow 给出的声明建议只是一个大致的基础。在添加这些声明后,您可能需要更改来源域和目标标签,并纳入适当的宏,才能实现良好的政策配置。有时,拒绝事件的合理应对方式不是对政策进行更改,而是更改违规的应用。
#编写 SELinux 政策
在编写设备专用政策时,请按顺序执行以下步骤。
在宽容模式下运行
当设备处于宽容模式时,拒绝事件会被记录下来,但不会被强制执行。宽容模式非常重要,原因有以下两个:
宽容模式可确保政策启用不会延误其他早期设备启动任务。
被强制执行的拒绝事件可能会掩盖其他拒绝事件。例如,文件访问通常会涉及目录搜索、文件打开和文件读取操作。在强制模式下,只会发生目录搜索拒绝事件。宽容模式可确保所有拒绝事件都会显示出来。
要使设备进入宽容模式,最简单的方法是通过内核命令行来实现。相应命令可以添加到设备的 BoardConfig.mk 文件中:platform/device///BoardConfig.mk。修改命令行之后,执行 make clean,接着执行 make bootimage,然后刷写新的启动映像。
在此之后,通过以下命令确认宽容模式:
adb shell getenforce
将处于全局宽容模式的时间设为两周比较合理。在解决大多数拒绝事件之后,返回到强制模式,并在出现错误时加以解决。对于仍然不断出现拒绝事件的域或仍处于密集开发阶段的服务,可以暂时使其进入宽容模式,但要尽快使其返回到强制模式。
在强制模式下,拒绝事件会被记录下来,并且会被强制执行。最佳做法是尽早使您的设备进入强制模式。如果花时间等待创建和强制执行设备专用政策,通常会导致有问题的产品和糟糕的用户体验。要提前足够长的时间开始参与 dogfooding,确保对实际使用中涉及的功能进行全面测试。提早开始有助于确保安全问题能够在相关人员做出设计决策时被考虑在内。相反,仅根据观察到的拒绝事件来授予权限是一种不安全的做法。可以利用这段时间对设备进行安全审核,并针对不应被允许的行为提出错误。
之所以要在新设备上从头开始创建设备专用政策,有很多合理的理由,其中包括:
安全审核
过度宽容的政策
政策规模缩小
Dead 政策
核心服务生成的拒绝事件通常是通过为文件添加标签来解决的。例如:
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0” dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
是完全通过为 /dev/kgsl-3d0 添加适当的标签来解决的。在此示例中,tcontext 是 device。这表示默认环境,在该环境中,/dev 中的内容除非被分配了更具体的标签,否则都会获得 device 标签。直接在此处接受来自 audit2allow 的输出会导致不正确且过度宽容的规则。
要解决这种问题,可以为文件添加更具体的标签,在此示例中为 gpu_device。由于 mediaserver 在核心政策中已有访问 gpu_device 所需的必要权限,因此不再需要更多权限。
其他需要以核心政策中预定义的类型作为标签的设备专用文件:
块设备
音频设备
视频设备
传感器
nfc
gps_device
/sys 中的文件
/proc 中的文件
一般情况下,向默认标签授予权限的做法是错误的。其中许多权限都是 neverallow 规则所不允许的,但即使该规则并未明确禁止这些权限,也最好是提供具体标签。
通过 init 启动的服务需要在各自的 SELinux 域中运行。以下示例会将服务“foo”放入它自己的 SELinux 域中并为其授予权限。
该服务是在设备的 init..rc 文件中启动的,如下所示:
service foo /system/bin/foo
class core
1 创建一个新域“foo”
创建包含以下内容的文件 device///sepolicy/foo.te:
# foo service
type foo, domain;
type foo_exec, exec_type, file_type;
init_daemon_domain(foo)
这是 foo SELinux 域的初始模板,您可以根据该可执行文件执行的具体操作为该模板添加规则。
2 为 /system/bin/foo 添加标签
将以下内容添加到 device///sepolicy/ file_contexts:
/system/bin/foo u:object_r:foo_exec:s0
这可确保为该可执行文件添加适当的标签,以便 SELinux 在适当的域中运行相应服务。
3 编译并刷写启动映像和系统映像
4 优化相应域的 SELinux 规则。
根据拒绝事件确定所需的权限。audit2allow 工具提供了一些实用的指南,但该工具仅适用于提供编写政策时所需的信息。切勿只是复制输出内容。
可以在宽容模式下进行问题排查,但要尽早切换回强制模式,并尽量保持该模式。
##常见错误
1 过度使用否定
以下示例规则类似于锁着前门,但开着窗户:
allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms
该规则的意图很明确:除了第三方应用之外,其他所有应用都可以访问调试设备。
该规则存在几个方面的缺陷。排除 untrusted_app 所起到的效果微不足道,因为所有应用都可以选择在 isolated_app 网域中运行服务。同样,如果第三方应用的新域被添加到了 AOSP,它们也可以访问 scary_debug_device。该规则过于宽容。对于大多数域来说,能够访问该调试工具并不能使它们获益。该规则应编写为仅允许需要访问该调试工具的域。
调试功能及其政策不应存在于正式版中。
最简单的替代方案是,仅当 eng/userdebug 版本中停用了 SELinux 时,才允许使用调试功能,例如 adb root 和 adb shell setenforce 0。
另一种安全的替代方案是在 userdebug_or_eng 声明中包含调试权限
在 Wild 中描述 SEAndroid 政策中介绍了一个令人关注的设备政策自定义发展趋势。设备专用政策应占设备上运行的所有政策的 5-10%。如果自定义政策所占的比例超过 20%,则几乎肯定会包含超特权域和 Dead 政策。
过大的政策:
##授予 dac_override 权限
dac_override 拒绝事件意味着违规进程正在尝试使用错误的 unix user/group/world 权限访问某个文件。正确的解决方案几乎从不授予 dac_override 权限,而是更改相应文件或进程的 unix 权限。有些域(例如 init、vold 和 installd)确实需要能够替换 unix 文件权限才能访问其他进程的文件。要查看更深入的讲解,请访问 Dan Walsh 的博客。
Guys,oppo内推啦,欢迎发简历给我
https://blog.csdn.net/ch853199769/article/details/114842209
手机扫一扫
移动阅读更方便
你可能感兴趣的文章