12、Android安全配置文件:mac_permissions.xml、keys.conf和seapp_contexts详解

Android安全配置文件:mac_permissions.xml、keys.conf和seapp_contexts详解

1. mac_permissions.xml文件概述

mac_permissions.xml文件的名称容易让人产生混淆,其全称为MAC permissions。该文件的主要功能是将签名密钥映射到seinfo字符串,其次还可用于配置非主流的安装时权限检查功能,即安装时MMAC(Middleware Mandatory Access Controls)。不过,Google并未合并MMAC相关功能,但由于使用了NSA的Bitbucket仓库,代码库中包含这些特性。

1.1 XML文件规则

mac_permissions.xml是一个XML文件,需遵循以下规则(斜体部分仅在NSA分支中支持):
- 每个 <signer> 标签都需要一个十六进制编码的X.509证书作为签名。
- <signer signature=""> 元素可以有多个子元素:
- <allow-permission> :生成一组最大允许的权限(白名单)。
- <deny-permission> :生成一个要拒绝的权限黑名单。
- <allow-all> :是一个通配符标签,允许请求的所有权限。
- <package> :是一个复杂标签,为受签名保护的特定包名定义允许、拒绝和通配符子元素。
- 允许零个或多个全局 <package name=""> 标签,这些标签允许为特定包名设置策略,而无需关联签名。
- 允许使用 <default> 标签,其中可以包含未使用先前列出的证书签名且没有每个包全局策略的所有应用的安装策略。
- 任何级别的未知标签都会被跳过。
- 允许零个或多个 <signer> 标签。
- 每个 <signer> 标签允许零个或多个 <package> 标签。
- <package name=""> 标签内不能包含另一个 <package name=""> 标签,若发现则会被跳过。

1.2 权限执行逻辑

当一个标签有多个子元素时,使用以下逻辑最终确定执行类型:
- 如果至少找到一个 <deny-permission> 标签,则使用黑名单。
- 如果不是黑名单,且至少找到一个 <allow-permission> 标签,则使用白名单。
- 如果既不是黑名单也不是白名单,且至少有一个 <allow-all> 标签,则使用通配符(接受所有权限)策略。
- 如果找到 <package name=""> 子元素,则根据上述逻辑使用该子元素的策略,并覆盖任何签名全局策略类型。

1.3 策略执行决策

为了执行策略,必须满足上述至少一种情况,即空的 <signer> <default> <package> 标签将不被接受。执行决策如下:
- 检查用于签署应用的所有签名是否符合 <signer> 标签的策略,但只需一个签名策略通过即可。
- 如果所有签名策略都不通过,或者没有匹配的策略,则查找全局包策略。若找到,该策略将介导安装。
- 必要时,最后参考 <default> 标签。
- 本地包策略始终覆盖任何父策略。
- 如果以上情况都不适用,则拒绝该应用。

1.4 示例

以下是一些示例,忽略了Install MMAC支持,专注于seinfo映射的主要用途:

<!-- Platform dev key in AOSP -->
<signer signature="@PLATFORM" >
  <seinfo value="platform" />
</signer>

<!-- release dev key in AOSP -->
<signer signature="@RELEASE" >
  <seinfo value="release" />
  <package name="com.android.browser" >
    <seinfo value="browser" />
  </package>
</signer>

<!-- All other keys -->
<default>
  <seinfo value="default" />
</default>

签名标签中的 @PLATFORM @RELEASE 是构建期间使用的特殊处理字符串,另一个映射文件将它们映射到实际的密钥值。处理后并放置到设备上的文件会将所有密钥引用替换为十六进制编码的公钥,并去除所有空格和注释以减小大小。可以使用以下命令从设备中拉取构建好的文件并进行格式化:

$ adb pull /system/etc/security/mac_permissions.xml
$ xmllint --format mac_permissions.xml

格式化输出的顶部应该如下所示:

<?xml version="1.0" encoding="iso-8859-1"?>
<!-- AUTOGENERATED FILE DO NOT MODIFY -->
<policy>
  <signer 
signature="308204ae30820396a003020102020900d2cba57296ebebe2300d06092a864886
f70d0101050500308196310b300906035504061302555331133…
dec513c8443956b7b0182bcf1f1d">
    <allow-all/>
    <seinfo value="platform"/>
  </signer>

注意, signature="@PLATFORM" 现在是一个十六进制字符串,该字符串是一个有效的X509证书。

1.5 mermaid流程图

graph TD;
    A[开始检查签名策略] --> B{是否有签名策略通过};
    B -- 是 --> C[应用通过检查];
    B -- 否 --> D{是否有全局包策略};
    D -- 是 --> E[使用全局包策略介导安装];
    D -- 否 --> F{是否有默认策略};
    F -- 是 --> G[使用默认策略];
    F -- 否 --> H[应用被拒绝];

2. keys.conf文件

keys.conf 文件的作用是将 mac_permissions.xml 中的 signature="@PLATFORM" 等特殊字符串映射到实际的密钥值。该配置文件允许将PEM编码的X.509证书映射到任意字符串,通常以 @ 开头,但这不是强制要求。文件格式基于Python配置解析器,包含多个部分,部分名称是 mac_permissions.xml 文件中希望用密钥值替换的标签。

2.1 示例配置

以下是 [@PLATFORM] [@RELEASE] 部分的示例:

[@PLATFORM]
ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/platform.x509.pem

[@RELEASE]
ENG       : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem
USER      : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem
USERDEBUG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem

在Android构建时,可以有三种构建级别:工程版、用户调试版或用户版。在 keys.conf 文件中,可以使用 ALL 属性为所有级别关联一个密钥,也可以为每个级别分配不同的密钥。文件还允许使用环境变量,PEM文件的默认位置是 build/target/product/security 。但需要注意的是,这些密钥是AOSP测试密钥且是公开的,不应用于用户发布版本的构建,否则任何人都可以使用系统密钥签署应用并获得系统权限。 keys.conf 文件仅在构建期间使用,不在系统上。

2.2 配置表格

部分名称 构建级别 密钥文件路径
[@PLATFORM] ALL $DEFAULT_SYSTEM_DEV_CERTIFICATE/platform.x509.pem
[@RELEASE] ENG $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem
[@RELEASE] USER $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem
[@RELEASE] USERDEBUG $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem

3. seapp_contexts文件

3.1 文件概述

前面介绍了 mac_permissions.xml 文件如何分配 seinfo 值,现在来看 seapp_contexts 文件如何实际配置和利用这个值。 seapp_contexts 文件用于管理应用程序的标签,与 mac_permissions.xml 一样,它也会被加载到设备上,默认位置是 /seapp_contexts 。文件格式是每行一个键值对映射,遵循以下规则。

3.2 输入选择器及规则

  • 输入选择器:
  • isSystemServer (布尔值)
  • user (字符串)
  • seinfo (字符串)
  • name (字符串)
  • sebool (字符串)
  • 输入选择器规则:
  • isSystemServer=true 只能使用一次。
  • 未指定的 isSystemServer 默认为 false
  • 未指定的字符串选择器将匹配任何值。
  • * 结尾的 user 字符串选择器将执行前缀匹配。
  • user=_app 将匹配任何常规应用的UID。
  • user=_isolated 将匹配任何隔离服务的UID。
  • 条目中所有指定的输入选择器必须匹配(逻辑与)。
  • 匹配不区分大小写。
  • 优先级规则(按顺序):
  • isSystemServer=true 优先于 isSystemServer=false
  • 指定的 user= 字符串优先于未指定的 user= 字符串。
  • 固定的 user= 字符串优先于以 * 结尾的 user= 前缀。
  • 较长的 user= 前缀优先于较短的 user= 前缀。
  • 指定的 seinfo= 字符串优先于未指定的 seinfo= 字符串。
  • 指定的 name= 字符串优先于未指定的 name= 字符串。
  • 指定的 sebool= 字符串优先于未指定的 sebool= 字符串。

3.3 输出及规则

  • 输出:
  • domain (字符串):指定应用程序的进程域。
  • type (字符串):指定应用程序私有数据目录的磁盘标签。
  • levelFrom (字符串,可选值为 none all app user ):给出MLS说明符。
  • level (字符串):显示硬编码的MLS值。
  • 输出规则:
  • 只有指定了 domain= 的条目才会用于应用程序进程标签。
  • 只有指定了 type= 的条目才会用于应用程序目录标签。
  • levelFrom=user 仅支持 _app _isolated UID。
  • levelFrom=app levelFrom=all 仅支持 _app UID。
  • level 可用于为任何UID指定固定级别。

3.4 示例条目

以下是两个示例条目:

user=bluetooth domain=bluetooth type=bluetooth_data_file
user=_app domain=untrusted_app type=app_data_file levelFrom=app

第一个条目将所有UID为 bluetooth 的应用放入 bluetooth 域,并将其数据目录标签设置为 bluetooth_data_file 。第二个条目将所有第三方或“默认”应用放入 untrusted_app 进程域和 app_data_file 数据目录,并使用 levelFrom=app 提供基于MLS的额外隔离。

3.5 实验性功能及操作步骤

目前, levelFrom=app 功能是实验性的,因为它会导致一些已知的应用兼容性问题。以下是验证其功能并禁用它的操作步骤:
1. 下载并安装第三方应用

$ wget https://f-droid.org/repo/org.zeroxlab.zeroxbenchmark_9.apk
$ adb install org.zeroxlab.zeroxbenchmark_9.apk
  1. 检查安装时的seinfo值
$ adb logcat | grep SELinux
  1. 启动应用并检查标签
$ adb shell ps -Z | grep untrusted
  1. 修改 seapp_contexts 文件
    user=_app domain=untrusted_app type=app_data_file 改为 user=_app sebool=app_level domain=untrusted_app type=app_data_file levelFrom=app
  2. 构建并处理错误
$ mmm external/sepolicy

如果出现构建错误,提示在 seapp_contexts 文件的第42行找不到SELinux布尔值 app_level ,则在 app.te 文件中添加 bool app_level false;
6. 推送文件并触发动态重载

$ adb push $OUT/root/sepolicy /data/security/current/
$ adb push $OUT/root/seapp_contexts /data/security/current/
$ adb shell setprop selinux.reload_policy 1
  1. 验证布尔值是否存在
$ adb shell getsebool -a | grep app_level
  1. 卸载并重新安装应用
$ adb uninstall org.zeroxlab.zeroxbenchmark
$ adb install ~/org.zeroxlab.zeroxbenchmark_9.apk

3.6 操作步骤表格

步骤 操作 命令示例
1 下载并安装第三方应用 $ wget https://f-droid.org/repo/org.zeroxlab.zeroxbenchmark_9.apk
$ adb install org.zeroxlab.zeroxbenchmark_9.apk
2 检查安装时的seinfo值 $ adb logcat | grep SELinux
3 启动应用并检查标签 $ adb shell ps -Z | grep untrusted
4 修改seapp_contexts文件 user=_app domain=untrusted_app type=app_data_file 改为 user=_app sebool=app_level domain=untrusted_app type=app_data_file levelFrom=app
5 构建并处理错误 $ mmm external/sepolicy
app.te 中添加 bool app_level false;
6 推送文件并触发动态重载 $ adb push $OUT/root/sepolicy /data/security/current/
$ adb push $OUT/root/seapp_contexts /data/security/current/
$ adb shell setprop selinux.reload_policy 1
7 验证布尔值是否存在 $ adb shell getsebool -a | grep app_level
8 卸载并重新安装应用 $ adb uninstall org.zeroxlab.zeroxbenchmark
$ adb install ~/org.zeroxlab.zeroxbenchmark_9.apk

4. 解决权限问题及自定义应用域

4.1 权限问题排查与解决

在尝试修改 seapp_contexts 文件以禁用MLS类别时,可能会遇到构建错误。例如,在构建过程中可能会出现如下错误:

Error:
out/host/linux-x86/bin/checkseapp -p 
out/target/product/udoo/obj/ETC/sepolicy_intermediates/sepolicy -o 
out/target/product/udoo/obj/ETC/seapp_contexts_intermediates/seapp_contexts 
out/target/product/udoo/obj/ETC/seapp_contexts_intermediates/seapp_contexts
.tmp
Error: Could not find selinux boolean "app_level" on line: 42 in file: 
out/target/product/udoo/obj/ETC/seapp_contexts_intermediates/seapp_contexts
Error: Could not validate

这表明在 seapp_contexts 文件的第42行找不到SELinux布尔值 app_level 。解决方法是在 app.te 文件中添加 bool app_level false;

另外,在重新安装应用后,可能会发现应用的上下文没有正确更新。经过调试发现,问题出在 /data/security 路径的权限上,该路径不是全局可搜索的,导致了DAC权限失败。可以通过修改 UDOO init.rc 脚本来解决这个问题,具体操作是将 device/fsl/imx6/etc/init.rc 文件中的 mkdir /data/security 0700 system system 改为 mkdir /data/security 0711 system system 。然后重新构建并刷入启动镜像,再次进行上下文测试。

4.2 自定义应用域操作步骤

接下来,我们将为一个应用分配一个唯一的域,具体步骤如下:
1. 卸载应用

$ adb uninstall org.zeroxlab.zeroxbenchmark
  1. 修改 mac_permissions.xml 文件
    mac_permissions.xml 文件中添加以下内容:
<signer signature="@BENCHMARK" >
  <allow-all />
  <seinfo value="benchmark" />
</signer>
  1. 提取应用的公钥证书
$ mkdir tmp
$ cd tmp
$ unzip ~/org.zeroxlab.zeroxbenchmark_9.apk
$ cd META-INF/
$ openssl pkcs7 -inform DER -in *.RSA -out CERT.pem -outform PEM -print_certs

将生成的 CERT.pem 文件中的 subject issuer 行删除,只保留以 BEGIN CERTIFICATE 开头和 END CERTIFICATE 结尾的部分。然后将该文件移动到工作区的 certs 文件夹中,并更名为 benchmark.x509.pem

$ mkdir UDOO_SOURCE_ROOT/certs
$ mv CERT.pem UDOO_SOURCE_ROOT/certs/benchmark.x509.pem
  1. 修改 keys.conf 文件
    keys.conf 文件中添加以下内容:
[@BENCHMARK]
ALL : certs/benchmark.x509.pem
  1. 更新 seapp_contexts 文件
    seapp_contexts 文件中添加以下内容:
user=_app seinfo=benchmark domain=benchmark_app 
type=benchmark_app_data_file
  1. 声明新类型
    sepolicy 目录下的 benchmark_app.te 文件中声明新的域类型:
# Declare the new type
type benchmark_app, domain;
# This macro adds it to the untrusted app domain set and gives it some 
# allow rules for basic functionality as well as object access to the type in argument 2.
untrustedapp_domain(benchmark_app, benchmark_app_data_file)

file.te 文件中添加 benchmark_app_data_file 类型:

type benchmark_app_data_file, file_type, data_file_type, 
app_public_data_type;
  1. 重新构建策略并推送文件
$ mmm external/sepolicy/
$ adb push $OUT/system/etc/security/mac_permissions.xml 
/data/security/current/
$ adb push $OUT/root/sepolicy /data/security/current/
$ adb push $OUT/root/seapp_contexts /data/security/current/
$ adb shell setprop selinux.reload_policy 1
  1. 安装应用并检查日志
$ adb install ~/org.zeroxlab.zeroxbenchmark_9.apk
$ adb logcat | grep -i SELinux

如果发现日志中显示的 seinfo 值仍然是 default ,而不是预期的 benchmark ,这是因为 frameworks/base/services/java/com/android/server/pm/SELinuxMMAC.java 文件在包管理器服务启动时加载了 /data/security/mac_permissions.xml 文件,且该文件在不重启的情况下不会重新加载。解决方法是重新挂载系统并将 mac_permissions.xml 文件推送到默认位置:

$ adb remount
$ adb push $OUT/system/etc/security/mac_permissions.xml 
/system/etc/security/

然后卸载并重新安装应用,重启设备,触发动态重载,再次安装应用并检查日志,应该会看到 seinfo=benchmark

4.3 验证自定义域

启动应用后,使用以下命令验证应用的进程域和私有数据目录标签:

$ adb shell ps -Z | grep org.zeroxlab.zeroxbenchmark
$ adb shell ls -Z /data/data | grep org.zeroxlab.zeroxbenchmark

如果输出结果如下:

u:r:benchmark_app:s0 u0_a45 3493 2285 org.zeroxlab.zeroxbenchmark
drwxr-x--x u0_a45 u0_a45 u:object_r:benchmark_app_data_file:s0 
org.zeroxlab.zeroxbenchmark

则说明我们成功为应用创建了一个新的自定义域。

4.4 自定义应用域操作步骤表格

步骤 操作 命令示例
1 卸载应用 $ adb uninstall org.zeroxlab.zeroxbenchmark
2 修改 mac_permissions.xml 在文件中添加 <signer signature="@BENCHMARK" ><allow-all /><seinfo value="benchmark" /></signer>
3 提取公钥证书 $ mkdir tmp; cd tmp; unzip ~/org.zeroxlab.zeroxbenchmark_9.apk; cd META-INF/; openssl pkcs7 -inform DER -in *.RSA -out CERT.pem -outform PEM -print_certs ,删除 subject issuer 行,移动并重命名文件
4 修改 keys.conf 在文件中添加 [@BENCHMARK]<br>ALL : certs/benchmark.x509.pem
5 更新 seapp_contexts 在文件中添加 user=_app seinfo=benchmark domain=benchmark_app type=benchmark_app_data_file
6 声明新类型 benchmark_app.te file.te 文件中声明新类型
7 重新构建并推送文件 $ mmm external/sepolicy/; adb push $OUT/system/etc/security/mac_permissions.xml /data/security/current/; adb push $OUT/root/sepolicy /data/security/current/; adb push $OUT/root/seapp_contexts /data/security/current/; adb shell setprop selinux.reload_policy 1
8 安装应用并检查日志 $ adb install ~/org.zeroxlab.zeroxbenchmark_9.apk; adb logcat | grep -i SELinux ,若有问题,重新挂载系统并推送文件,卸载并重新安装应用,重启设备
9 验证自定义域 $ adb shell ps -Z | grep org.zeroxlab.zeroxbenchmark; adb shell ls -Z /data/data | grep org.zeroxlab.zeroxbenchmark

4.5 mermaid流程图

graph TD;
    A[开始自定义应用域] --> B[卸载应用];
    B --> C[修改mac_permissions.xml];
    C --> D[提取公钥证书];
    D --> E[修改keys.conf];
    E --> F[更新seapp_contexts];
    F --> G[声明新类型];
    G --> H[重新构建并推送文件];
    H --> I[安装应用并检查日志];
    I -- 日志正确 --> J[验证自定义域];
    I -- 日志错误 --> K[重新挂载系统并推送文件];
    K --> L[卸载并重新安装应用];
    L --> M[重启设备];
    M --> I;

5. 总结

通过对 mac_permissions.xml keys.conf seapp_contexts 这三个文件的详细介绍和操作实践,我们了解了如何在Android系统中进行签名密钥映射、权限配置和应用标签管理。同时,我们也学会了如何解决在配置过程中遇到的各种问题,以及如何为应用自定义域。这些操作对于提高Android系统的安全性和应用的隔离性具有重要意义。在实际应用中,我们可以根据具体需求灵活调整这些配置,以满足不同的安全和功能要求。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值