CTS里面SELinux相关测试中neverallow测试项占绝大多数,Android系统开发者都应该知道,在修改sepolicy时,需要确保不能违反这些neverallow规则,不然会过不了CTS。CTS中nerverallow测试都是在SELinuxNeverallowRulesTest.java文件中,并且从AOSP代码中发现该文件不是人工提交的,而是通过python脚本生成的,为了以后更好的修改sepolicy,就需要了解下SELinuxNeverallowRulesTest.java是如何生成的。

Makefile

首先看下SELinuxNeverallowRulesTest.java的生成的Makefile.

  1. selinux_general_policy := $(call intermediates-dir-for,ETC,general_sepolicy.conf)/general_sepolicy.conf
  2. selinux_neverallow_gen := cts/tools/selinux/SELinuxNeverallowTestGen.py
  3. selinux_neverallow_gen_data := cts/tools/selinux/SELinuxNeverallowTestFrame.py
  4. LOCAL_ADDITIONAL_DEPENDENCIES := $(COMPATIBILITY_TESTCASES_OUT_cts)/sepolicy-analyze
  5. LOCAL_GENERATED_SOURCES := $(call local-generated-sources-dir)/android/cts/security/SELinuxNeverallowRulesTest.java # 目标文件
  6. $(LOCAL_GENERATED_SOURCES) : PRIVATE_SELINUX_GENERAL_POLICY := $(selinux_general_policy)
  7. $(LOCAL_GENERATED_SOURCES) : $(selinux_neverallow_gen) $(selinux_general_policy) $(selinux_neverallow_gen_data)
  8. mkdir -p $(dir $@)
  9. $< $(PRIVATE_SELINUX_GENERAL_POLICY) $@
  10. # $< 为:右边依赖的第一个元素, 即 $(selinux_neverallow_gen) = cts/tools/selinux/SELinuxNeverallowTestGen.py
  11. # $@ 为:左边目标,即要生成的目标文件SELinuxNeverallowRulesTest.java
  12. # 这条命令相当于 cts/tools/selinux/SELinuxNeverallowTestGen.py $(call intermediates-dirfor,ETC,general_sepolicy.conf)/general_sepolicy.conf SELinuxNeverallowRulesTest.java
  13. include $(BUILD_CTS_HOST_JAVA_LIBRARY)

从上面可以看到,执行SELinuxNeverallowTestGen.py general_sepolicy.conf SELinuxNeverallowRulesTest.java会生成SELinuxNeverallowRulesTest.java文件。

general_sepolicy.conf 生成

该文件的生成Makfile

  1. # SELinux policy embedded into CTS.
  2. # CTS checks neverallow rules of this policy against the policy of the device under test.
  3. ##################################
  4. include $(CLEAR_VARS)
  5. LOCAL_MODULE := general_sepolicy.conf # 目标文件
  6. LOCAL_MODULE_CLASS := ETC
  7. LOCAL_MODULE_TAGS := tests
  8. include $(BUILD_SYSTEM)/base_rules.mk
  9. $(LOCAL_BUILT_MODULE): PRIVATE_MLS_SENS := $(MLS_SENS)
  10. $(LOCAL_BUILT_MODULE): PRIVATE_MLS_CATS := $(MLS_CATS)
  11. $(LOCAL_BUILT_MODULE): PRIVATE_TARGET_BUILD_VARIANT := user
  12. $(LOCAL_BUILT_MODULE): PRIVATE_TGT_ARCH := $(my_target_arch)
  13. $(LOCAL_BUILT_MODULE): PRIVATE_WITH_ASAN := false
  14. $(LOCAL_BUILT_MODULE): PRIVATE_SEPOLICY_SPLIT := cts
  15. $(LOCAL_BUILT_MODULE): PRIVATE_COMPATIBLE_PROPERTY := cts
  16. $(LOCAL_BUILT_MODULE): $(call build_policy, $(sepolicy_build_files), \
  17. $(PLAT_PUBLIC_POLICY) $(PLAT_PRIVATE_POLICY)) # PLAT_PUBLIC_POLICY = syetem/sepolicy/public PLAT_PRIVATE_POLICY = system/sepolicy/private
  18. $(transform-policy-to-conf) # 这里是使用m4将te规则文件都处理合成为目标文件$@,即general_sepolicy.conf
  19. $(hide) sed '/dontaudit/d' $@ > $@.dontaudit
  20. ##################################

可以看到,general_sepolicy.conf 文件是将system/sepolicy/public和system/sepolicy/private规则文件整合在一起,而这些目录包含的是AOSP sepolicy大多数配置信息。

SELinuxNeverallowTestGen.py 脚本逻辑

生成的逻辑都是在该脚本中,下面脚本我调整了顺序,方便说明执行的逻辑,脚本代码

  1. #!/usr/bin/env python
  2. import re
  3. import sys
  4. import SELinuxNeverallowTestFrame
  5. usage = "Usage: ./SELinuxNeverallowTestGen.py <input policy file> <output cts java source>"
  6. if __name__ == "__main__":
  7. # check usage
  8. if len(sys.argv) != 3:
  9. print usage
  10. exit(1)
  11. input_file = sys.argv[1]
  12. output_file = sys.argv[2]
  13. # 这三个变量是同目录下SELinuxNeverallowTestFrame.py文件中的内容,是生成java文件的模版
  14. src_header = SELinuxNeverallowTestFrame.src_header
  15. src_body = SELinuxNeverallowTestFrame.src_body
  16. src_footer = SELinuxNeverallowTestFrame.src_footer
  17. # grab the neverallow rules from the policy file and transform into tests
  18. neverallow_rules = extract_neverallow_rules(input_file) # 提取neverallow规则从general_sepolicy.conf中
  19. i = 0
  20. for rule in neverallow_rules:
  21. src_body += neverallow_rule_to_test(rule, i)
  22. i += 1
  23. # 然后将neverallow规则写入到SELinuxNeverallowRulesTest.java文件中
  24. with open(output_file, 'w') as out_file:
  25. out_file.write(src_header)
  26. out_file.write(src_body)
  27. out_file.write(src_footer)
  28. # extract_neverallow_rules - takes an intermediate policy file and pulls out the
  29. # neverallow rules by taking all of the non-commented text between the 'neverallow'
  30. # keyword and a terminating ';'
  31. # returns: a list of rules
  32. def extract_neverallow_rules(policy_file):
  33. with open(policy_file, 'r') as in_file:
  34. policy_str = in_file.read()
  35. # full-Treble only tests are inside sections delimited by BEGIN_TREBLE_ONLY
  36. # and END_TREBLE_ONLY comments.
  37. # uncomment TREBLE_ONLY section delimiter lines
  38. remaining = re.sub(
  39. r'^\s*#\s*(BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|END_COMPATIBLE_PROPERTY_ONLY)',
  40. r'\1', # group 引用
  41. policy_str,
  42. flags = re.M) # 该方法是将 #开头的注释行任意空格后跟着BEGIN_TREBLE_ONLY、END_TREBLE_ONLY、BEGIN_COMPATIBLE_PROPERTY_ONLY和END_COMPATIBLE_PROPERTY_ONLY时,替换为这些关键字,即去掉注释
  43. # remove comments
  44. remaining = re.sub(r'#.+?$', r'', remaining, flags = re.M) # 将文件中的 # 开头注释行去掉
  45. # match neverallow rules
  46. lines = re.findall(
  47. r'^\s*(neverallow\s.+?;|BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|END_COMPATIBLE_PROPERTY_ONLY)',
  48. remaining,
  49. flags = re.M |re.S) # 将neverallow和以这几个关键字开头的行取出来
  50. # extract neverallow rules from the remaining lines
  51. # 这些关键字会修饰里面的neverallowrules,若treble_only_depth > 1 说明是适用于treble系统, 若compatible_property_only_depth > 1,说明适用于 compatible_property 系统
  52. rules = list()
  53. treble_only_depth = 0
  54. compatible_property_only_depth = 0
  55. for line in lines:
  56. if line.startswith("BEGIN_TREBLE_ONLY"):
  57. treble_only_depth += 1
  58. continue
  59. elif line.startswith("END_TREBLE_ONLY"):
  60. if treble_only_depth < 1:
  61. exit("ERROR: END_TREBLE_ONLY outside of TREBLE_ONLY section")
  62. treble_only_depth -= 1
  63. continue
  64. elif line.startswith("BEGIN_COMPATIBLE_PROPERTY_ONLY"):
  65. compatible_property_only_depth += 1
  66. continue
  67. elif line.startswith("END_COMPATIBLE_PROPERTY_ONLY"):
  68. if compatible_property_only_depth < 1:
  69. exit("ERROR: END_COMPATIBLE_PROPERTY_ONLY outside of COMPATIBLE_PROPERTY_ONLY section")
  70. compatible_property_only_depth -= 1
  71. continue
  72. rule = NeverallowRule(line)
  73. rule.treble_only = (treble_only_depth > 0)
  74. rule.compatible_property_only = (compatible_property_only_depth > 0)
  75. rules.append(rule)
  76. if treble_only_depth != 0:
  77. exit("ERROR: end of input while inside TREBLE_ONLY section")
  78. if compatible_property_only_depth != 0:
  79. exit("ERROR: end of input while inside COMPATIBLE_PROPERTY_ONLY section")
  80. return rules
  81. # neverallow_rule_to_test - takes a neverallow statement and transforms it into
  82. # the output necessary to form a cts unit test in a java source file.
  83. # returns: a string representing a generic test method based on this rule.
  84. # 将neverallowrules 替换到java模版中
  85. def neverallow_rule_to_test(rule, test_num):
  86. squashed_neverallow = rule.statement.replace("\n", " ")
  87. method = SELinuxNeverallowTestFrame.src_method
  88. method = method.replace("testNeverallowRules()",
  89. "testNeverallowRules" + str(test_num) + "()")
  90. method = method.replace("$NEVERALLOW_RULE_HERE$", squashed_neverallow)
  91. method = method.replace(
  92. "$FULL_TREBLE_ONLY_BOOL_HERE$",
  93. "true" if rule.treble_only else "false")
  94. method = method.replace(
  95. "$COMPATIBLE_PROPERTY_ONLY_BOOL_HERE$",
  96. "true" if rule.compatible_property_only else "false")
  97. return method

总结下脚本功能

  1. 将BEGIN_TREBLE_ONLY|END_TREBLE_ONLY|BEGIN_COMPATIBLE_PROPERTY_ONLY|

    END_COMPATIBLE_PROPERTY_ONLY这几个关键字前面的注释去掉,以便后面解析时使用;

  2. 删除冗余的注释行;

  3. 取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。
  4. 然后用neverallow部分、treble_only和compatible_property_only值对下面方法模板中的$NEVERALLOW_RULE_HERE$、$FULL_TREBLE_ONLY_BOOL_HERE$和$COMPATIBLE_PROPERTY_ONLY_BOOL_HERE$分别替换。

  1. src_method = """
  2. @RestrictedBuildTest
  3. public void testNeverallowRules() throws Exception {
  4. String neverallowRule = "$NEVERALLOW_RULE_HERE$";
  5. boolean fullTrebleOnly = $FULL_TREBLE_ONLY_BOOL_HERE$;
  6. boolean compatiblePropertyOnly = $COMPATIBLE_PROPERTY_ONLY_BOOL_HERE$;
  7. if ((fullTrebleOnly) && (!isFullTrebleDevice())) {
  8. // This test applies only to Treble devices but this device isn't one
  9. return;
  10. }
  11. if ((compatiblePropertyOnly) && (!isCompatiblePropertyEnforcedDevice())) {
  12. // This test applies only to devices on which compatible property is enforced but this
  13. // device isn't one
  14. return;
  15. }
  16. // If sepolicy is split and vendor sepolicy version is behind platform's,
  17. // only test against platform policy.
  18. File policyFile =
  19. (isSepolicySplit() && mVendorSepolicyVersion < P_SEPOLICY_VERSION) ?
  20. deviceSystemPolicyFile :
  21. devicePolicyFile;
  22. /* run sepolicy-analyze neverallow check on policy file using given neverallow rules */
  23. ProcessBuilder pb = new ProcessBuilder(sepolicyAnalyze.getAbsolutePath(),
  24. policyFile.getAbsolutePath(), "neverallow", "-w", "-n",
  25. neverallowRule);
  26. pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
  27. pb.redirectErrorStream(true);
  28. Process p = pb.start();
  29. p.waitFor();
  30. BufferedReader result = new BufferedReader(new InputStreamReader(p.getInputStream()));
  31. String line;
  32. StringBuilder errorString = new StringBuilder();
  33. while ((line = result.readLine()) != null) {
  34. errorString.append(line);
  35. errorString.append("\\n");
  36. }
  37. assertTrue("The following errors were encountered when validating the SELinux"
  38. + "neverallow rule:\\n" + neverallowRule + "\\n" + errorString,
  39. errorString.length() == 0);
  40. }

本地生成 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规则生成过程的更多相关文章

  1. 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 ...

  2. 在Android Studio 中正确使用adil ”绝对经典“

    今天调用远程服务中遇到了一个问题,哎,调了2个小时,后来终于解决,总结来看还是对新的Android Studio 不够熟悉.那么....就可以睡觉啦!!! 在Android Studio中使用进程通信 ...

  3. 监听Android CTS测试项解决方案(二)

    二,监听当前测试项是否是Accelerometer Measurement Test测试项 通过第一种方式介绍的,我们可以得到当前处于活动状态的Activity类似监听CTS测试当前的测试项.但是由于 ...

  4. 监听Android CTS测试项解决方案(一)

    前言: 首先这里需要详细叙述一下标题中"监听Android CTS测试项解决方案"的需求.这里的需求是指我们需要精确的监听到当前CTS测试正在测试的测试项. 因为我们知道CTS认证 ...

  5. android项目中如何加载已有so库 <转>

    1,在项目根目录下建立文件夹libs/armeabi文件夹 2,将so库放入 libs/armeabi文件夹 注意事项: 1,如果采用静态注册的方式请注意C文件中严格按照命名规则 Java_packa ...

  6. 在Android应用中使用Clean架构

    自从开始开发安卓应用,我一直感觉我可以做得更好.我看过不少烂代码,其中当然有我写的.安卓系统的复杂性加上烂代码势必酿成灾祸,所以从错误中成长就很重要.我Google了如何更好地开发应用,发现了这个叫做 ...

  7. 转:Android开发中的MVP架构(最后链接资源不错)

    Android开发中的MVP架构 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解MVP和DDD,但是我们的新项目还是决定通过MVP来构建. 这篇文章是我通过研究和 ...

  8. 转: Android开发中的MVP架构详解(附加链接比较不错)

    转: http://www.codeceo.com/article/android-mvp-artch.html 最近越来越多的人开始谈论架构.我周围的同事和工程师也是如此.尽管我还不是特别深入理解M ...

  9. Android Studio中使用Gradle打包

    首先要注意一点,Android Studio中把proguard.txt已经命名为proguard-rules.pro,由此可见,採用Gradle打包,混淆规则文件的名称是不重要的.能够自己随便命名. ...

随机推荐

  1. 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 ...

  2. C# —— 枚举

    一.使用枚举的优点 枚举能够使代码更加的清晰,它允许使用描述性的名称表示整数值. 枚举使代码更易于维护,有助于确保给变量指定合法的.期望的值. 枚举使代码更易输入. 二.枚举说明 1.简单枚举 枚举使 ...

  3. 巨蟒python全栈开发-第11阶段 ansible_project5

    今日大纲 1.命令展示前端页面实现(下面有个断点) 2.命令下发后端展示

  4. Uva 10446【递推,dp】

    UVa 10446 求(n,bcak)递归次数.自己推出来了一个式子: 其实就是这个式子,但是不知道该怎么写,怕递归写法超时.其实直接递推就好,边界条件易得C(0,back)=1.C(1,back)= ...

  5. laravel5.6 QQ 第三方登录

    https://socialiteproviders.github.io/providers/qq.html 1. Installation // This assumes that you have ...

  6. Android 开源库StickyListHeadersListView来实现ListView列表分组效果

    项目中有一新的需求,要求能像一些Android机带"联系人列表"一样,数据可以自动分组,且在列表滑动过程中,列表头固定在顶部,效果图如下: 下面就带大家实现上面的效果, 首先,我们 ...

  7. selenium webdriver学习(三)------------执行js脚本

    selenium webdriver学习(三)------------执行js脚本 博客分类: Selenium-webdriver   在用selenium 1.X的时候常常会用到getEval() ...

  8. 20182019-acmicpc-asia-dhaka-regional F .Path Intersection 树链剖分

    直接进行树链剖分,每次对路径区间内的所有点值+1,线段树进行维护,然后查询线段树的最大值的个数!!! 查询线段树区间最大值个数,可以先维护区间和,在维护区间最值,如果区间和等于区间最值乘以区间长度,那 ...

  9. 首次揭秘:阿里巴巴中间件在 Serverless 技术领域的探索

    Serverless 话题涉及范围极广,几乎包含了代码管理.测试.发布.运维和扩容等与应用生命周期关联的所有环节.AWS Lambda 是 Serverless 领域的标志性产品,但如果将其应用于核心 ...

  10. 不需内测账号,带你体验微信小程序完整开发过程

    不需内测账号,带你体验微信小程序完整开发过程 2016年09月24日 - 作者: SwiftCafe 微信小程序还没正式发布就已经迅速成为大家讨论的焦点,那么大家可能觉得只有收到内测邀请才能体验小程序 ...