Migrate sepolicy compat test to Android.bp
compat_test tests whether {ver}.compat.cil is compatible to current
policy or not. This commit migrates all tests into a single module named
"sepolicy_compat_tests".
A minor issue is also resolved with this migration. Suppose that the
vendor's speolicy version is {VER}. Then the following cil files are
compiled in runtime.
- system/etc/selinux/plat_sepolicy.cil
- system/etc/selinux/mapping/{VER}.cil
- system/etc/selinux/mapping/{VER}.compat.cil (optional)
- system_ext/etc/selinux/system_ext_sepolicy.cil (optional)
- system_ext/etc/selinux/mapping/{VER}.cil (optional)
- system_ext/etc/selinux/mapping/{VER}.compat.cil (optional)
- product/etc/selinux/product_sepolicy.cil (optional)
- product/etc/selinux/mapping/{VER}.cil (optional)
- product/etc/selinux/mapping/{VER}.compat.cil (optional)
- vendor/etc/selinux/vendor_sepolicy.cil
- vendor/etc/selinux/plat_pub_versioned.cil
- odm/etc/selinux/odm_sepolicy.cil (optional)
That is, the vendor policy of version {VER} (vendor_sepolicy.cil,
plat_pub_versioned.cil, and odm_sepolicy.cil) is required to be
compatible only to {VER}.compat.cil. So, the vendor policy is included
only to $(BOARD_SEPOLICY_VERS)_compat_test. The other tests will be
built only with platform side policies.
Bug: 33691272
Test: boot
Test: manually edit {ver}.compat.cil files and try build
Change-Id: I16b30a9171f10ee8f08fc03b7bd7c047eec12b19
diff --git a/build/soong/compat_cil.go b/build/soong/compat_cil.go
index 46b0f71..3044425 100644
--- a/build/soong/compat_cil.go
+++ b/build/soong/compat_cil.go
@@ -15,13 +15,21 @@
package selinux
import (
+ "fmt"
+
"github.com/google/blueprint/proptools"
"android/soong/android"
)
+var (
+ compatTestDepTag = dependencyTag{name: "compat_test"}
+)
+
func init() {
- android.RegisterModuleType("se_compat_cil", compatCilFactory)
+ ctx := android.InitRegistrationContext
+ ctx.RegisterModuleType("se_compat_cil", compatCilFactory)
+ ctx.RegisterSingletonModuleType("se_compat_test", compatTestFactory)
}
// se_compat_cil collects and installs backwards compatibility cil files.
@@ -107,3 +115,154 @@
},
}}
}
+
+func (c *compatCil) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ return android.Paths{c.installSource}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
+var _ android.OutputFileProducer = (*compatCil)(nil)
+
+// se_compat_test checks if compat files ({ver}.cil, {ver}.compat.cil) files are compatible with
+// current policy.
+func compatTestFactory() android.SingletonModule {
+ f := &compatTestModule{}
+ android.InitAndroidModule(f)
+ android.AddLoadHook(f, func(ctx android.LoadHookContext) {
+ f.loadHook(ctx)
+ })
+ return f
+}
+
+type compatTestModule struct {
+ android.SingletonModuleBase
+
+ compatTestTimestamp android.ModuleOutPath
+}
+
+func (f *compatTestModule) createPlatPubVersionedModule(ctx android.LoadHookContext, ver string) {
+ confName := fmt.Sprintf("pub_policy_%s.conf", ver)
+ cilName := fmt.Sprintf("pub_policy_%s.cil", ver)
+ platPubVersionedName := fmt.Sprintf("plat_pub_versioned_%s.cil", ver)
+
+ ctx.CreateModule(policyConfFactory, &nameProperties{
+ Name: proptools.StringPtr(confName),
+ }, &policyConfProperties{
+ Srcs: []string{
+ fmt.Sprintf(":se_build_files{.plat_public_%s}", ver),
+ ":se_build_files{.reqd_mask}",
+ },
+ Installable: proptools.BoolPtr(false),
+ })
+
+ ctx.CreateModule(policyCilFactory, &nameProperties{
+ Name: proptools.StringPtr(cilName),
+ }, &policyCilProperties{
+ Src: proptools.StringPtr(":" + confName),
+ Filter_out: []string{":reqd_policy_mask.cil"},
+ Secilc_check: proptools.BoolPtr(false),
+ Installable: proptools.BoolPtr(false),
+ })
+
+ ctx.CreateModule(versionedPolicyFactory, &nameProperties{
+ Name: proptools.StringPtr(platPubVersionedName),
+ }, &versionedPolicyProperties{
+ Base: proptools.StringPtr(":" + cilName),
+ Target_policy: proptools.StringPtr(":" + cilName),
+ Version: proptools.StringPtr(ver),
+ Installable: proptools.BoolPtr(false),
+ })
+}
+
+func (f *compatTestModule) createCompatTestModule(ctx android.LoadHookContext, ver string) {
+ srcs := []string{
+ ":plat_sepolicy.cil",
+ ":system_ext_sepolicy.cil",
+ ":product_sepolicy.cil",
+ fmt.Sprintf(":plat_%s.cil", ver),
+ fmt.Sprintf(":%s.compat.cil", ver),
+ fmt.Sprintf(":system_ext_%s.cil", ver),
+ fmt.Sprintf(":system_ext_%s.compat.cil", ver),
+ fmt.Sprintf(":product_%s.cil", ver),
+ }
+
+ if ver == ctx.DeviceConfig().BoardSepolicyVers() {
+ srcs = append(srcs,
+ ":plat_pub_versioned.cil",
+ ":vendor_sepolicy.cil",
+ ":odm_sepolicy.cil",
+ )
+ } else {
+ srcs = append(srcs, fmt.Sprintf(":plat_pub_versioned_%s.cil", ver))
+ }
+
+ compatTestName := fmt.Sprintf("%s_compat_test", ver)
+ ctx.CreateModule(policyBinaryFactory, &nameProperties{
+ Name: proptools.StringPtr(compatTestName),
+ }, &policyBinaryProperties{
+ Srcs: srcs,
+ Ignore_neverallow: proptools.BoolPtr(true),
+ Installable: proptools.BoolPtr(false),
+ })
+}
+
+func (f *compatTestModule) loadHook(ctx android.LoadHookContext) {
+ for _, ver := range ctx.DeviceConfig().PlatformSepolicyCompatVersions() {
+ f.createPlatPubVersionedModule(ctx, ver)
+ f.createCompatTestModule(ctx, ver)
+ }
+}
+
+func (f *compatTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ for _, ver := range ctx.DeviceConfig().PlatformSepolicyCompatVersions() {
+ ctx.AddDependency(f, compatTestDepTag, fmt.Sprintf("%s_compat_test", ver))
+ }
+}
+
+func (f *compatTestModule) GenerateSingletonBuildActions(ctx android.SingletonContext) {
+ // does nothing; se_compat_test is a singeton because two compat test modules don't make sense.
+}
+
+func (f *compatTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var inputs android.Paths
+ ctx.VisitDirectDepsWithTag(compatTestDepTag, func(child android.Module) {
+ o, ok := child.(android.OutputFileProducer)
+ if !ok {
+ panic(fmt.Errorf("Module %q should be an OutputFileProducer but it isn't", ctx.OtherModuleName(child)))
+ }
+
+ outputs, err := o.OutputFiles("")
+ if err != nil {
+ panic(fmt.Errorf("Module %q error while producing output: %v", ctx.OtherModuleName(child), err))
+ }
+ if len(outputs) != 1 {
+ panic(fmt.Errorf("Module %q should produce exactly one output, but did %q", ctx.OtherModuleName(child), outputs.Strings()))
+ }
+
+ inputs = append(inputs, outputs[0])
+ })
+
+ f.compatTestTimestamp = android.PathForModuleOut(ctx, "timestamp")
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().Text("touch").Output(f.compatTestTimestamp).Implicits(inputs)
+ rule.Build("compat", "compat test timestamp for: "+f.Name())
+}
+
+func (f *compatTestModule) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "FAKE",
+ // OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it.
+ // Without OutputFile this module won't be exported to Makefile.
+ OutputFile: android.OptionalPathForPath(f.compatTestTimestamp),
+ Include: "$(BUILD_PHONY_PACKAGE)",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", f.compatTestTimestamp.String())
+ },
+ },
+ }}
+}