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或_isolatedUID。 -
levelFrom=app或levelFrom=all仅支持_appUID。 -
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
- 检查安装时的seinfo值 :
$ adb logcat | grep SELinux
- 启动应用并检查标签 :
$ adb shell ps -Z | grep untrusted
-
修改
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。 - 构建并处理错误 :
$ 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
- 验证布尔值是否存在 :
$ adb shell getsebool -a | grep app_level
- 卸载并重新安装应用 :
$ 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
-
修改
mac_permissions.xml文件 :
在mac_permissions.xml文件中添加以下内容:
<signer signature="@BENCHMARK" >
<allow-all />
<seinfo value="benchmark" />
</signer>
- 提取应用的公钥证书 :
$ 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
-
修改
keys.conf文件 :
在keys.conf文件中添加以下内容:
[@BENCHMARK]
ALL : certs/benchmark.x509.pem
-
更新
seapp_contexts文件 :
在seapp_contexts文件中添加以下内容:
user=_app seinfo=benchmark domain=benchmark_app
type=benchmark_app_data_file
-
声明新类型
:
在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;
- 重新构建策略并推送文件 :
$ 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
- 安装应用并检查日志 :
$ 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系统的安全性和应用的隔离性具有重要意义。在实际应用中,我们可以根据具体需求灵活调整这些配置,以满足不同的安全和功能要求。
超级会员免费看

被折叠的 条评论
为什么被折叠?



