13、深入理解 Android 安全策略:属性标签与构建工具链

深入理解 Android 安全策略:属性标签与构建工具链

1. Android 属性标签概述

在 Android 系统中,属性标签是一项关键的安全机制,通过配置文件和 SELinux 策略,可以对应用私有数据目录及其运行时上下文进行恰当的标记。其主要目的在于限制属性的设置权限,防止经典的 DAC 根攻击意外更改属性值。以下是在这方面需要掌握的几个关键技能:
- 创建新属性
- 对新属性和现有属性进行标签设置
- 解读和处理属性拒绝访问的情况
- 了解特殊 Android 属性及其行为

2. 通过 property_contexts 文件进行属性标签设置

所有属性的标签设置都依赖于 property_contexts 文件,其语法与 file_contexts 类似。不同之处在于, property_contexts 针对的是属性名称或属性键(在 Android 中,属性以键值对形式存储),属性键通常以句点(.)分隔,类似于 file_contexts 中的斜杠(/)。以下是一些示例:

ctl.ril-daemon  u:object_r:ctl_rildaemon_prop:s0
ctl.   u:object_r:ctl_default_prop:s0

从上述示例可以看出,所有以 ctl. 开头的属性都被标记为 ctl_default_prop 类型,但 ctl.ril-daemon 有其特定的类型标签 ctl_rildaemon_prop 。这展示了可以先进行通用标记,再根据需要设置更具体的标签。此外,对于未明确标记的属性,通过 property_contexts 中的 “匹配所有” 表达式,默认标签为 default_prop

# default property context
* u:object_r:default_prop:s0
3. 属性的权限设置

在系统中,可以使用命令行工具 getprop setprop 查看当前属性并创建新属性,示例代码如下:

root@udoo:/ # getprop
...
[sys.usb.state]: [mtp,adb]
[wifi.interface]: [wlan0]
[wlan.driver.status]: [unloaded]

需要注意的是,虽然所有用户都可以读取属性(因为属性被映射到每个用户的地址空间),但并非所有用户都能设置(写入)属性。属性的 DAC 权限模型硬编码在 system/core/init/property_service.c 文件中:

/* White list of permissions for setting property services. */
struct {
  const char *prefix;
  unsigned int uid;
  unsigned int gid;
} property_perms[] = {
  { "net.rmnet0.", AID_RADIO, 0 },
  { "net.gprs.", AID_RADIO, 0 },
  { "net.ppp", AID_RADIO, 0 },
  ...
  { "persist.service.bdroid.", AID_BLUETOOTH, 0 },
  { "selinux." , AID_SYSTEM, 0 },
  { "persist.audio.device", AID_SYSTEM, 0 },
  { NULL, 0, 0 }

只有当用户的 UID 或 GID 在 property_perms 数组中,且属性前缀匹配时,才能设置相应的属性。例如,要设置以 selinux. 开头的属性,用户必须是 UID 为 AID_SYSTEM (uid 1000)或 root 用户。遗憾的是,目前没有类似 ls -Z 查看文件标签的 getprop -Z 命令来查看属性及其标签。

4. 重新标记现有属性

为了更好地掌握属性标签设置,以重新标记 wifi.interface 属性为例。首先,通过触发拒绝访问并查看拒绝日志来验证其当前上下文:

root@udoo:/ # setprop wifi.interface wlan0
avc: denied { set } for property=wifi.interface scontext=u:r:shell:s0 
tcontext=u:object_r:default_prop:s0 tclass=property_service

从拒绝输出可知,该属性的类型标签为 default_prop ,接下来将其更改为 wifi_prop 。具体操作步骤如下:
1. 编辑 sepolicy 目录下的 property.te 文件,声明新的类型:

type wifi_prop, property_type;
  1. 修改 property_contexts 文件,添加以下内容应用新标签:
# wifi properties
wifi. u:object_r:wifi_prop:s0
  1. 构建策略:
$ mmm external/sepolicy
  1. 推送新的 property_contexts 文件:
$ adb push out/target/product/udoo/root/property_contexts 
/data/security/current
  1. 触发动态重新加载:
$ adb shell setprop selinux.reload_policy 1

然而,首次尝试可能会失败,因为 property_contexts 文件的正确位置应该是 /data/security ,而不是 /data/security/current 。通过搜索相关文件可以发现这一问题:

$ grep -rn property_contexts *
init/init.c:745: { SELABEL_OPT_PATH, "/data/security/property_contexts" },
init/init.c:746: { SELABEL_OPT_PATH, "/property_contexts" },
init/init.c:760: ERROR("SELinux: Could not load property_contexts: %s\n",

将文件推送到正确位置并再次尝试:

$ adb push out/target/product/udoo/root/property_contexts /data/security
$ adb shell setprop selinux.reload_policy 1

但可能仍然失败,这是因为包含 wifi_prop 类型声明的 sepolicy 文件未被推送。需要将其推送并再次触发重新加载:

$ adb push out/target/product/udoo/root/sepolicy /data/security/current/
$ adb shell setprop selinux.reload_policy 1

此时会看到拒绝信息,但目标属性的标签已变为 u:object_r:wifi_prop:s0 。接下来,可以在 shell.te 文件中添加允许规则:

# wifi prop
allow shelldomain wifi_prop:property_service set;

编译策略,推送到设备并触发动态重新加载,再次尝试设置 wifi.interface 属性,将不再出现拒绝信息。

5. 创建和标记新属性

在系统中,所有属性都可以通过 setprop 调用或 C 语言( bionic/libc/include/sys/system_properties.h )和 Java( android.os.SystemProperties )中的等效函数调用动态创建。需要注意的是,Java 的 System.getProperty() System.setProperty() 调用针对的是应用私有属性存储,与全局属性无关。对于非 root 用户创建或设置属性,需要修改 property_perms[] 数组。例如,要创建 udoo.name udoo.owner 属性,并仅允许 root 用户和 shell 域访问:

root@udoo:/ # setprop udoo.name udoo
avc: denied { set } for property=udoo.name scontext=u:r:shell:s0 
tcontext=u:object_r:default_prop:s0 tclass=property_service
root@udoo:/ # setprop udoo.owner William

从拒绝信息可知,这些属性的类型为 default_prop ,可按照重新标记现有属性的步骤进行修正。

6. 特殊属性

Android 中有一些具有特殊行为的属性,以下是几种常见的特殊属性:
| 属性类型 | 描述 | 示例命令 |
| ---- | ---- | ---- |
| 控制属性 | 以 ctl 开头,用于通过 init 控制服务 | setprop ctl.start <servicename> 启动服务
setprop ctl.stop <servicename> 停止服务
setprop ctl.restart <servicename> 重启服务 |
| 持久属性 | 以 persist 开头,在重启后仍然保留,数据存储在 /data/property 目录下同名文件中 | root@udoo:/ # ls /data/property/
persist.gps.oacmode
persist.service.bdroid.bdaddr
persist.sys.profiler_ms
persist.sys.usb.config |
| SELinux 属性 | selinux.reload_policy 属性用于触发动态重新加载事件 | $ adb shell setprop selinux.reload_policy 1 |

7. Android 构建工具链概述

在深入了解 Android 安全策略的代码和策略之后,掌握构建工具链对于提高开发效率至关重要。以下是需要关注的几个方面:
- 构建特定目标
- 分析 sepolicy Android.mk 文件
- 自定义构建策略配置
- 了解各种构建工具,如 check_seapp insertkeys.py checkpolicy checkfc sepolicy-check sepolicy-analyze

8. 构建子组件 - 目标和项目

在 Android 开发中,我们使用过一些命令来构建项目,如 mm mmm make bootimage 。Google 在相关文档中对部分工具进行了描述,但仍有很多命令未详细列出。在 Android 构建系统中,“目标” 通常指特定的 make 目标,而非目标设备。可以通过指定目标来构建系统的特定部分,例如 make bootimage 用于构建 boot.img 文件, make sepolicy 用于构建 sepolicy 文件。

要确定可以构建的目标名称,可以查看 Android.mk 文件中以 LOCAL_MODULE 开头的行。例如,在 external/sepolicy Android.mk 文件中:

$ grep -w '^LOCAL_MODULE' Android.mk
LOCAL_MODULE := sepolicy
LOCAL_MODULE := file_contexts
LOCAL_MODULE := seapp_contexts
LOCAL_MODULE := property_contexts
LOCAL_MODULE := selinux-network.sh
LOCAL_MODULE := mac_permissions.xml
LOCAL_MODULE := eops.xml

Android 还提供了 mm mmm 命令,它们的作用是构建 Android.mk 文件中指定的所有目标,但不构建其依赖项。 mm 命令使用当前工作目录, mmm 命令需要指定路径。使用 -B 选项可以强制重新构建,这可以节省大量时间。

9. 剖析 sepolicy 的 Android.mk 文件

external/sepolicy 项目使用 Android.mk 文件来构建输出。下面详细分析构建 sepolicy 的过程:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

    A([开始]):::startend --> B(初始化 Android.mk 基本设置):::process
    B --> C(声明中间目标文件 policy.conf):::process
    C --> D(设置 MLS_SENS 和 MLS_CATS 变量):::process
    D --> E(使用 build_policy 函数生成 policy.conf):::process
    E --> F(使用 m4 处理 policy.conf):::process
    F --> G(生成 .dontaudit 版本的 policy.conf):::process
    G --> H(使用 checkpolicy 编译 sepolicy):::process
    H --> I(设置 local 变量并清除 policy.conf):::process
    I --> J([结束]):::startend

具体步骤如下:
- 初始化设置

include $(CLEAR_VARS)
LOCAL_MODULE := sepolicy
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
include $(BUILD_SYSTEM)/base_rules.mk…
  • 声明中间目标文件
sepolicy_policy.conf := $(intermediates)/policy.conf
$(sepolicy_policy.conf): PRIVATE_MLS_SENS := $(MLS_SENS)
$(sepolicy_policy.conf): PRIVATE_MLS_CATS := $(MLS_CATS)
$(sepolicy_policy.conf) : $(call build_policy, security_classes 
initial_sids access_vectors global_macros mls_macros mls 
policy_capabilities te_macros attributes bools *.te roles users 
initial_sid_contexts fs_use genfs_contexts port_contexts)
  • 构建中间目标 policy.conf
    使用 m4 处理 SELinux 策略文件,将 PRIVATE_MLS_SENS PRIVATE_MLS_CATS 作为宏定义传入,并生成 .dontaudit 版本:
@mkdir -p $(dir $@)
$(hide) m4 -D mls_num_sens=$(PRIVATE_MLS_SENS) -D 
mls_num_cats=$(PRIVATE_MLS_CATS) -s $^ > $@
$(hide) sed '/dontaudit/d' $@ > $@.dontaudit…
  • 构建最终目标 sepolicy
    使用 checkpolicy m4 处理后的 policy.conf policy.conf.dontaudit 编译成 sepolicy sepolicy.dontaudit
$(LOCAL_BUILT_MODULE) : $(sepolicy_policy.conf) 
$(HOST_OUT_EXECUTABLES)/checkpolicy
@mkdir -p $(dir $@)
$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -c $(POLICYVERS) -o $@ $<
$(hide) $(HOST_OUT_EXECUTABLES)/checkpolicy -M -c $(POLICYVERS) -o $(dir 
$<)/$(notdir $@).dontaudit $<.dontaudit…
  • 清理和设置变量
built_sepolicy := $(LOCAL_BUILT_MODULE)
sepolicy_policy.conf :=

此外,构建 sepolicy 还依赖于 POLICYVERS 变量,如果未设置,默认值为 26。

通过深入理解 Android 属性标签和构建工具链,可以更好地进行 Android 安全策略的开发和管理,确保系统的安全性和稳定性。

深入理解 Android 安全策略:属性标签与构建工具链

10. 构建工具详解

在 Android 安全策略的构建过程中,有多个重要的构建工具发挥着关键作用,下面对这些工具进行详细介绍:
| 工具名称 | 功能描述 |
| ---- | ---- |
| check_seapp | 用于检查 seapp_contexts 文件的正确性,确保应用程序的上下文标签设置符合策略要求。它可以帮助开发者发现标签配置中的错误,避免因标签设置不当导致的安全漏洞。 |
| insertkeys.py | 该脚本主要用于在策略文件中插入密钥信息。在某些安全场景下,需要对策略进行加密或签名, insertkeys.py 可以将相应的密钥插入到合适的位置,增强策略的安全性。 |
| checkpolicy | 核心的策略编译工具,将文本形式的 SELinux 策略转换为内核可以加载的二进制形式。它会对策略文件进行语法检查和语义分析,确保策略的合法性和一致性。在构建 sepolicy 文件时, checkpolicy 会根据指定的策略版本号(如 POLICYVERS )进行编译。 |
| checkfc | 用于检查文件上下文配置文件(如 file_contexts )的正确性。它会验证文件路径和对应的标签是否符合策略规则,防止因文件上下文配置错误而导致的访问控制问题。 |
| sepolicy-check | 对 SELinux 策略文件进行全面的检查和验证,包括策略的完整性、兼容性和安全性等方面。通过 sepolicy-check ,可以提前发现策略中可能存在的问题,避免在系统运行时出现安全故障。 |
| sepolicy-analyze | 提供对 SELinux 策略的详细分析功能。它可以帮助开发者理解策略的结构和规则,分析策略对不同进程和对象的访问控制效果,从而进行策略的优化和调整。 |

11. 自定义构建策略配置

在实际开发中,可能需要根据特定的需求对构建策略进行自定义配置。以下是一些常见的自定义配置场景和操作步骤:

11.1 修改策略版本号

如果默认的策略版本号(如 POLICYVERS 的默认值 26)不满足需求,可以在构建脚本中手动指定新的版本号。例如,在 Android.mk 文件中添加如下代码:

POLICYVERS := 28
11.2 调整 MLS 敏感度和类别

MLS(多级安全)是 SELinux 中的一个重要特性,通过设置不同的敏感度和类别可以实现更精细的访问控制。在 sepolicy Android.mk 文件中,可以修改 MLS_SENS MLS_CATS 变量的值:

MLS_SENS := 5
MLS_CATS := 10
11.3 自定义策略文件路径

如果需要使用自定义的策略文件路径,可以在 Android.mk 文件中修改相关的路径配置。例如:

LOCAL_MODULE_PATH := $(TARGET_OUT)/custom/sepolicy
12. 构建过程中的常见问题及解决方法

在构建 Android 安全策略的过程中,可能会遇到各种问题,下面列举一些常见问题及相应的解决方法:

12.1 策略编译失败
  • 问题描述 :使用 checkpolicy 编译策略时出现错误信息,提示语法错误或语义错误。
  • 解决方法 :检查策略文件中的语法错误,确保所有的规则和声明都符合 SELinux 策略的语法规范。可以使用 sepolicy-check 工具进行更详细的检查,找出具体的错误位置。
12.2 文件上下文加载失败
  • 问题描述 :系统无法正确加载文件上下文配置文件(如 property_contexts ),导致属性标签设置无效。
  • 解决方法 :检查文件路径是否正确,确保文件存在且具有正确的权限。可以通过搜索相关代码文件,如 init.c ,找到文件加载的优先级位置,并将文件放置在正确的目录下。
12.3 动态重新加载策略失败
  • 问题描述 :使用 setprop selinux.reload_policy 1 触发动态重新加载策略时,没有生效或出现错误信息。
  • 解决方法 :确保所有相关的策略文件(如 sepolicy property_contexts )都已正确推送和更新。检查策略文件中是否存在未解决的依赖问题,确保所有的类型声明和规则都已正确定义。
13. 总结与展望

通过对 Android 属性标签和构建工具链的深入学习,我们了解了如何对 Android 系统中的属性进行标签设置,以及如何使用构建工具来生成和管理 SELinux 策略。属性标签的正确设置可以有效限制属性的访问权限,防止潜在的安全攻击;而掌握构建工具链则可以提高开发效率,确保策略的正确性和稳定性。

在未来的 Android 开发中,随着安全需求的不断提高,对 SELinux 策略的优化和定制将变得更加重要。开发者需要不断学习和掌握新的安全技术和工具,以应对日益复杂的安全挑战。同时,也需要关注 Android 系统的更新和变化,及时调整策略配置,确保系统的安全性和兼容性。

总之,深入理解 Android 安全策略的属性标签和构建工具链是保障 Android 系统安全的关键,希望本文的内容能够对开发者有所帮助。

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

    A([开始]):::startend --> B(选择自定义配置场景):::process
    B --> C{是否修改策略版本号?}:::process
    C -- 是 --> D(在 Android.mk 中指定新的 POLICYVERS):::process
    C -- 否 --> E{是否调整 MLS 敏感度和类别?}:::process
    E -- 是 --> F(修改 MLS_SENS 和 MLS_CATS 变量):::process
    E -- 否 --> G{是否自定义策略文件路径?}:::process
    G -- 是 --> H(修改 LOCAL_MODULE_PATH 变量):::process
    D --> I(构建策略):::process
    F --> I
    H --> I
    I --> J([结束]):::startend

以上流程图展示了自定义构建策略配置的基本流程,开发者可以根据具体需求选择不同的配置选项,然后进行策略的构建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值