Android CTS中neverallow规则生成过程
CTS里面SELinux相关测试中neverallow测试项占绝大多数,Android系统开发者都应该知道,在修改sepolicy时,需要确保不能违反这些neverallow规则,不然会过不了CTS。CTS中nerverallow测试都是在SELinuxNeverallowRulesTest.java文件中,并且从AOSP代码中发现该文件不是人工提交的,而是通过python脚本生成的,为了以后更好的修改sepolicy,就需要了解下SELinuxNeverallowRulesTest.java是如何生成的。
Makefile
首先看下SELinuxNeverallowRulesTest.java的生成的Makefile.
selinux_general_policy := $(call intermediates-dir-for,ETC,general_sepolicy.conf)/general_sepolicy.conf
selinux_neverallow_gen := cts/tools/selinux/SELinuxNeverallowTestGen.py
selinux_neverallow_gen_data := cts/tools/selinux/SELinuxNeverallowTestFrame.py
LOCAL_ADDITIONAL_DEPENDENCIES := $(COMPATIBILITY_TESTCASES_OUT_cts)/sepolicy-analyze
LOCAL_GENERATED_SOURCES := $(call local-generated-sources-dir)/android/cts/security/SELinuxNeverallowRulesTest.java # 目标文件
$(LOCAL_GENERATED_SOURCES) : PRIVATE_SELINUX_GENERAL_POLICY := $(selinux_general_policy)
$(LOCAL_GENERATED_SOURCES) : $(selinux_neverallow_gen) $(selinux_general_policy) $(selinux_neverallow_gen_data)
mkdir -p $(dir $@)
$< $(PRIVATE_SELINUX_GENERAL_POLICY) $@
# $< 为:右边依赖的第一个元素, 即 $(selinux_neverallow_gen) = cts/tools/selinux/SELinuxNeverallowTestGen.py
# $@ 为:左边目标,即要生成的目标文件SELinuxNeverallowRulesTest.java
# 这条命令相当于 cts/tools/selinux/SELinuxNeverallowTestGen.py $(call intermediates-dirfor,ETC,general_sepolicy.conf)/general_sepolicy.conf SELinuxNeverallowRulesTest.java
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
从上面可以看到,执行SELinuxNeverallowTestGen.py general_sepolicy.conf SELinuxNeverallowRulesTest.java会生成SELinuxNeverallowRulesTest.java文件。
general_sepolicy.conf 生成
该文件的生成Makfile
# SELinux policy embedded into CTS.
# CTS checks neverallow rules of this policy against the policy of the device under test.
##################################
include $(CLEAR_VARS)
LOCAL_MODULE := general_sepolicy.conf # 目标文件
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := tests
include $(BUILD_SYSTEM)/base_rules.mk
$(LOCAL_BUILT_MODULE): PRIVATE_MLS_SENS := $(MLS_SENS)
$(LOCAL_BUILT_MODULE): PRIVATE_MLS_CATS := $(MLS_CATS)
$(LOCAL_BUILT_MODULE): PRIVATE_TARGET_BUILD_VARIANT := user
$(LOCAL_BUILT_MODULE): PRIVATE_TGT_ARCH := $(my_target_arch)
$(LOCAL_BUILT_MODULE): PRIVATE_WITH_ASAN := false
$(LOCAL_BUILT_MODULE): PRIVATE_SEPOLICY_SPLIT := cts
$(LOCAL_BUILT_MODULE): PRIVATE_COMPATIBLE_PROPERTY := cts
$(LOCAL_BUILT_MODULE): $(call build_policy, $(sepolicy_build_files), \
$(PLAT_PUBLIC_POLICY) $(PLAT_PRIVATE_POLICY)) # PLAT_PUBLIC_POLICY = syetem/sepolicy/public PLAT_PRIVATE_POLICY = system/sepolicy/private
$(transform-policy-to-conf) # 这里是使用m4将te规则文件都处理合成为目标文件$@,即general_sepolicy.conf
$(hide) sed '/dontaudit/d' $@ > $@.dontaudit
##################################
可以看到,general_sepolicy.conf 文件是将system/sepolicy/public和system/sepolicy/private规则文件整合在一起,而这些目录包含的是AOSP sepolicy大多数配置信息。
SELinuxNeverallowTestGen.py 脚本逻辑
生成的逻辑都是在该脚本中,下面脚本我调整了顺序,方便说明执行的逻辑,脚本代码
#!/usr/bin/env python
import re
import sys
import SELinuxNeverallowTestFrame
usage = "Usage: ./SELinuxNeverallowTestGen.py <input policy file> <output cts java source>"
if __name__ == "__main__":
# check usage
if len(sys.argv) != 3:
print usage
exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
# 这三个变量是同目录下SELinuxNeverallowTestFrame.py文件中的内容,是生成java文件的模版
src_header = SELinuxNeverallowTestFrame.src_header
src_body = SELinuxNeverallowTestFrame.src_body
src_footer = SELinuxNeverallowTestFrame.src_footer
# grab the neverallow rules from the policy file and transform into tests
neverallow_rules = extract_neverallow_rules(input_file) # 提取neverallow规则从general_sepolicy.conf中
i = 0
for rule in neverallow_rules:
src_body += neverallow_rule_to_test(rule, i)
i += 1
# 然后将neverallow规则写入到SELinuxNeverallowRulesTest.java文件中
with open(output_file, 'w') as out_file:
out_file.write(src_header)
out_file.write(src_body)
out_file.write(src_footer)
# extract_neverallow_rules - takes an intermediate policy file and pulls out the
# neverallow rules by taking all of the non-commented text between the 'neverallow'
# keyword and a terminating ';'
# returns: a list of rules
def extract_neverallow_rules(policy_file):
with open(policy_file, 'r') as in_file:
policy_str = in_file.read()
# full-Treble only tests are inside sections delimited by BEGIN_TREBLE_ONLY
# and END_TREBLE_ONLY comments.
# uncomment TREBLE_ONLY section delimiter lines
remaining = re.sub(
r'^\s*#\s*(BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|END_COMPATIBLE_PROPERTY_ONLY)',
r'\1', # group 引用
policy_str,
flags = re.M) # 该方法是将 #开头的注释行任意空格后跟着BEGIN_TREBLE_ONLY、END_TREBLE_ONLY、BEGIN_COMPATIBLE_PROPERTY_ONLY和END_COMPATIBLE_PROPERTY_ONLY时,替换为这些关键字,即去掉注释
# remove comments
remaining = re.sub(r'#.+?$', r'', remaining, flags = re.M) # 将文件中的 # 开头注释行去掉
# match neverallow rules
lines = re.findall(
r'^\s*(neverallow\s.+?;|BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|END_COMPATIBLE_PROPERTY_ONLY)',
remaining,
flags = re.M |re.S) # 将neverallow和以这几个关键字开头的行取出来
# extract neverallow rules from the remaining lines
# 这些关键字会修饰里面的neverallowrules,若treble_only_depth > 1 说明是适用于treble系统, 若compatible_property_only_depth > 1,说明适用于 compatible_property 系统
rules = list()
treble_only_depth = 0
compatible_property_only_depth = 0
for line in lines:
if line.startswith("BEGIN_TREBLE_ONLY"):
treble_only_depth += 1
continue
elif line.startswith("END_TREBLE_ONLY"):
if treble_only_depth < 1:
exit("ERROR: END_TREBLE_ONLY outside of TREBLE_ONLY section")
treble_only_depth -= 1
continue
elif line.startswith("BEGIN_COMPATIBLE_PROPERTY_ONLY"):
compatible_property_only_depth += 1
continue
elif line.startswith("END_COMPATIBLE_PROPERTY_ONLY"):
if compatible_property_only_depth < 1:
exit("ERROR: END_COMPATIBLE_PROPERTY_ONLY outside of COMPATIBLE_PROPERTY_ONLY section")
compatible_property_only_depth -= 1
continue
rule = NeverallowRule(line)
rule.treble_only = (treble_only_depth > 0)
rule.compatible_property_only = (compatible_property_only_depth > 0)
rules.append(rule)
if treble_only_depth != 0:
exit("ERROR: end of input while inside TREBLE_ONLY section")
if compatible_property_only_depth != 0:
exit("ERROR: end of input while inside COMPATIBLE_PROPERTY_ONLY section")
return rules
# neverallow_rule_to_test - takes a neverallow statement and transforms it into
# the output necessary to form a cts unit test in a java source file.
# returns: a string representing a generic test method based on this rule.
# 将neverallowrules 替换到java模版中
def neverallow_rule_to_test(rule, test_num):
squashed_neverallow = rule.statement.replace("\n", " ")
method = SELinuxNeverallowTestFrame.src_method
method = method.replace("testNeverallowRules()",
"testNeverallowRules" + str(test_num) + "()")
method = method.replace("$NEVERALLOW_RULE_HERE$", squashed_neverallow)
method = method.replace(
"$FULL_TREBLE_ONLY_BOOL_HERE$",
"true" if rule.treble_only else "false")
method = method.replace(
"$COMPATIBLE_PROPERTY_ONLY_BOOL_HERE$",
"true" if rule.compatible_property_only else "false")
return method
总结下脚本功能
将BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|
END_COMPATIBLE_PROPERTY_ONLY这几个关键字前面的注释去掉,以便后面解析时使用;删除冗余的注释行;
取neverallow和上面四个关键字的部分进行解析,并根据下面情况对treble_only和compatible_property_only进行设置;
- neverallow 包含在BEGIN_TREBLE_ONLY和END_TREBLE_ONLY之间,treble_only被设置为true;
- neverallow 包含在BEGIN_COMPATIBLE_PROPERTY_ONLY和END_COMPATIBLE_PROPERTY_ONLY之间,compatible_property_only被设置为true;
- neverallow 不在任何BEGIN_TREBLE_ONLY/END_TREBLE_ONLY和BEGIN_COMPATIBLE_PROPERTY_ONLY/END_COMPATIBLE_PROPERTY_ONLY之间,则treble_only和compatible_property_only都被设置为false。
然后用neverallow部分、treble_only和compatible_property_only值对下面方法模板中的$NEVERALLOW_RULE_HERE$、$FULL_TREBLE_ONLY_BOOL_HERE$和$COMPATIBLE_PROPERTY_ONLY_BOOL_HERE$分别替换。
src_method = """
@RestrictedBuildTest
public void testNeverallowRules() throws Exception {
String neverallowRule = "$NEVERALLOW_RULE_HERE$";
boolean fullTrebleOnly = $FULL_TREBLE_ONLY_BOOL_HERE$;
boolean compatiblePropertyOnly = $COMPATIBLE_PROPERTY_ONLY_BOOL_HERE$;
if ((fullTrebleOnly) && (!isFullTrebleDevice())) {
// This test applies only to Treble devices but this device isn't one
return;
}
if ((compatiblePropertyOnly) && (!isCompatiblePropertyEnforcedDevice())) {
// This test applies only to devices on which compatible property is enforced but this
// device isn't one
return;
}
// If sepolicy is split and vendor sepolicy version is behind platform's,
// only test against platform policy.
File policyFile =
(isSepolicySplit() && mVendorSepolicyVersion < P_SEPOLICY_VERSION) ?
deviceSystemPolicyFile :
devicePolicyFile;
/* run sepolicy-analyze neverallow check on policy file using given neverallow rules */
ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
policyFile.getAbsolutePath(), "neverallow", "-w", "-n",
neverallowRule);
pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
pb.redirectErrorStream(true);
Process p = pb.start();
p.waitFor();
BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
StringBuilder errorString = new StringBuilder();
while ((line = result.readLine()) != null) {
errorString.append(line);
errorString.append("\\n");
}
assertTrue("The following errors were encountered when validating the SELinux"
+ "neverallow rule:\\n" + neverallowRule + "\\n" + errorString,
errorString.length() == 0);
}
本地生成 SELinuxNeverallowRulesTest.java 文件
在修改SELinux后,想确定下是否满足neverallow规则,虽然编译过程中会进行neverallow检查,但由于打包时间比较耗时,如果在本地生成的话,那速度会更快。
本地生成 SELinuxNeverallowRulesTest.java 命令
默认是在源码的根目录
make general_sepolicy.conf
cts/tools/selinux/SELinuxNeverallowTestGen.py out/target/product/cepheus/obj/ETC/general_sepolicy.conf_intermediates/general_sepolicy.conf SELinuxNeverallowRulesTest.java
由于某些规则是使用attribute,可能不是很明显,还需要结合其他方法来确定。
总结
从生成代码中可以看到,neverallow规则都属于AOSP system/sepolicy/private和system/sepolicy/public中的neverallow,所以在添加规则时不能修改neverallow,也不能违背。
附件
cts_neverallow.zip,中包含有:
SELinuxNeverallowTestGen.py 脚本
general_sepolicy.conf
SELinuxNeverallowTestFrame.py Java测试代码模板
first 为SELinuxNeverallowTestGen.py第一步执行的结果
second 为SELinuxNeverallowTestGen.py第二步执行的结果
SELinuxNeverallowRulesTest.java 为生成的文件
后面三个文件是前三个文件所生成,执行命令为:
SELinuxNeverallowTestGen.py general_sepolicy.conf SELinuxNeverallowRulesTest.java
链接
https://liwugang.github.io/2019/12/29/CTS-neverallow.html
Android CTS中neverallow规则生成过程的更多相关文章
- Android N和O中使用adb shell dpm set-device-owner 'com.android.cts.verifier/com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver' setup Device Owner失败
PC端出现如下log: D:\workspace\AndroidO\CTS\CTS_Verifier>adb shell dpm set-device-owner 'com.android.ct ...
- 在Android Studio 中正确使用adil ”绝对经典“
今天调用远程服务中遇到了一个问题,哎,调了2个小时,后来终于解决,总结来看还是对新的Android Studio 不够熟悉.那么....就可以睡觉啦!!! 在Android Studio中使用进程通信 ...
- 监听Android CTS测试项解决方案(二)
二,监听当前测试项是否是Accelerometer Measurement Test测试项 通过第一种方式介绍的,我们可以得到当前处于活动状态的Activity类似监听CTS测试当前的测试项.但是由于 ...
- 监听Android CTS测试项解决方案(一)
前言: 首先这里需要详细叙述一下标题中"监听Android CTS测试项解决方案"的需求.这里的需求是指我们需要精确的监听到当前CTS测试正在测试的测试项. 因为我们知道CTS认证 ...
- android项目中如何加载已有so库 <转>
1,在项目根目录下建立文件夹libs/armeabi文件夹 2,将so库放入 libs/armeabi文件夹 注意事项: 1,如果采用静态注册的方式请注意C文件中严格按照命名规则 Java_packa ...
- 在Android应用中使用Clean架构
自从开始开发安卓应用,我一直感觉我可以做得更好.我看过不少烂代码,其中当然有我写的.安卓系统的复杂性加上烂代码势必酿成灾祸,所以从错误中成长就很重要.我Google了如何更好地开发应用,发现了这个叫做 ...
- 转:Android开发中的MVP架构(最后链接资源不错)
Android开发中的MVP架构 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解MVP和DDD,但是我们的新项目还是决定通过MVP来构建. 这篇文章是我通过研究和 ...
- 转: Android开发中的MVP架构详解(附加链接比较不错)
转: http://www.codeceo.com/article/android-mvp-artch.html 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解M ...
- Android Studio中使用Gradle打包
首先要注意一点,Android Studio中把proguard.txt已经命名为proguard-rules.pro,由此可见,採用Gradle打包,混淆规则文件的名称是不重要的.能够自己随便命名. ...
随机推荐
- UVA_10300:Ecological Premium
Sample Input 351 1 12 2 23 3 32 3 48 9 239 1 86 12 18 1 1310 30 409 8 5100 1000 70Sample Output 3886 ...
- C# —— 枚举
一.使用枚举的优点 枚举能够使代码更加的清晰,它允许使用描述性的名称表示整数值. 枚举使代码更易于维护,有助于确保给变量指定合法的.期望的值. 枚举使代码更易输入. 二.枚举说明 1.简单枚举 枚举使 ...
- 巨蟒python全栈开发-第11阶段 ansible_project5
今日大纲 1.命令展示前端页面实现(下面有个断点) 2.命令下发后端展示
- Uva 10446【递推,dp】
UVa 10446 求(n,bcak)递归次数.自己推出来了一个式子: 其实就是这个式子,但是不知道该怎么写,怕递归写法超时.其实直接递推就好,边界条件易得C(0,back)=1.C(1,back)= ...
- laravel5.6 QQ 第三方登录
https://socialiteproviders.github.io/providers/qq.html 1. Installation // This assumes that you have ...
- Android 开源库StickyListHeadersListView来实现ListView列表分组效果
项目中有一新的需求,要求能像一些Android机带"联系人列表"一样,数据可以自动分组,且在列表滑动过程中,列表头固定在顶部,效果图如下: 下面就带大家实现上面的效果, 首先,我们 ...
- selenium webdriver学习(三)------------执行js脚本
selenium webdriver学习(三)------------执行js脚本 博客分类: Selenium-webdriver 在用selenium 1.X的时候常常会用到getEval() ...
- 20182019-acmicpc-asia-dhaka-regional F .Path Intersection 树链剖分
直接进行树链剖分,每次对路径区间内的所有点值+1,线段树进行维护,然后查询线段树的最大值的个数!!! 查询线段树区间最大值个数,可以先维护区间和,在维护区间最值,如果区间和等于区间最值乘以区间长度,那 ...
- 首次揭秘:阿里巴巴中间件在 Serverless 技术领域的探索
Serverless 话题涉及范围极广,几乎包含了代码管理.测试.发布.运维和扩容等与应用生命周期关联的所有环节.AWS Lambda 是 Serverless 领域的标志性产品,但如果将其应用于核心 ...
- 不需内测账号,带你体验微信小程序完整开发过程
不需内测账号,带你体验微信小程序完整开发过程 2016年09月24日 - 作者: SwiftCafe 微信小程序还没正式发布就已经迅速成为大家讨论的焦点,那么大家可能觉得只有收到内测邀请才能体验小程序 ...