1// Copyright 2021 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package selinux 16 17import ( 18 "sort" 19 20 "android/soong/android" 21) 22 23var currentCilTag = dependencyTag{name: "current_cil"} 24var prebuiltCilTag = dependencyTag{name: "prebuilt_cil"} 25 26func init() { 27 ctx := android.InitRegistrationContext 28 ctx.RegisterModuleType("se_freeze_test", freezeTestFactory) 29} 30 31// se_freeze_test compares the plat sepolicy with the prebuilt sepolicy. Additional directories can 32// be specified via Makefile variables: SEPOLICY_FREEZE_TEST_EXTRA_DIRS and 33// SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS. 34func freezeTestFactory() android.Module { 35 f := &freezeTestModule{} 36 android.InitAndroidArchModule(f, android.DeviceSupported, android.MultilibCommon) 37 android.AddLoadHook(f, func(ctx android.LoadHookContext) { 38 f.loadHook(ctx) 39 }) 40 return f 41} 42 43type freezeTestModule struct { 44 android.ModuleBase 45 freezeTestTimestamp android.ModuleOutPath 46} 47 48func (f *freezeTestModule) shouldRunTest(ctx android.EarlyModuleContext) bool { 49 val, _ := ctx.Config().GetBuildFlag("RELEASE_BOARD_API_LEVEL_FROZEN") 50 return val == "true" 51} 52 53func (f *freezeTestModule) loadHook(ctx android.LoadHookContext) { 54 extraDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraDirs() 55 extraPrebuiltDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraPrebuiltDirs() 56 57 if !f.shouldRunTest(ctx) { 58 if len(extraDirs) > 0 || len(extraPrebuiltDirs) > 0 { 59 ctx.ModuleErrorf("SEPOLICY_FREEZE_TEST_EXTRA_DIRS or SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS cannot be set before system/sepolicy freezes.") 60 return 61 } 62 63 return 64 } 65 66 if len(extraDirs) != len(extraPrebuiltDirs) { 67 ctx.ModuleErrorf("SEPOLICY_FREEZE_TEST_EXTRA_DIRS and SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS must have the same number of directories.") 68 return 69 } 70} 71 72func (f *freezeTestModule) prebuiltCilModuleName(ctx android.EarlyModuleContext) string { 73 return ctx.DeviceConfig().PlatformSepolicyVersion() + "_plat_pub_policy.cil" 74} 75 76func (f *freezeTestModule) DepsMutator(ctx android.BottomUpMutatorContext) { 77 if !f.shouldRunTest(ctx) { 78 return 79 } 80 81 ctx.AddDependency(f, currentCilTag, "base_plat_pub_policy.cil") 82 ctx.AddDependency(f, prebuiltCilTag, f.prebuiltCilModuleName(ctx)) 83} 84 85func (f *freezeTestModule) outputFileOfDep(ctx android.ModuleContext, depTag dependencyTag) android.Path { 86 deps := ctx.GetDirectDepsWithTag(depTag) 87 if len(deps) != 1 { 88 ctx.ModuleErrorf("%d deps having tag %q; expected only one dep", len(deps), depTag) 89 return nil 90 } 91 92 dep := deps[0] 93 output := android.OutputFilesForModule(ctx, dep, "") 94 if len(output) != 1 { 95 ctx.ModuleErrorf("module %q produced %d outputs; expected only one output", dep.String(), len(output)) 96 return nil 97 } 98 99 return output[0] 100} 101 102func (f *freezeTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 103 if ctx.ModuleName() != "se_freeze_test" || ctx.ModuleDir() != "system/sepolicy" { 104 // two freeze test modules don't make sense. 105 ctx.ModuleErrorf("There can only be 1 se_freeze_test module named se_freeze_test in system/sepolicy") 106 } 107 108 f.freezeTestTimestamp = android.PathForModuleOut(ctx, "freeze_test") 109 110 if !f.shouldRunTest(ctx) { 111 // we still build a rule to prevent possible regression 112 android.WriteFileRule(ctx, f.freezeTestTimestamp, ";; no freeze tests needed before system/sepolicy freezes") 113 return 114 } 115 116 // Freeze test 1: compare ToT sepolicy and prebuilt sepolicy 117 currentCil := f.outputFileOfDep(ctx, currentCilTag) 118 prebuiltCil := f.outputFileOfDep(ctx, prebuiltCilTag) 119 if ctx.Failed() { 120 return 121 } 122 123 rule := android.NewRuleBuilder(pctx, ctx) 124 rule.Command().BuiltTool("sepolicy_freeze_test"). 125 FlagWithInput("-c ", currentCil). 126 FlagWithInput("-p ", prebuiltCil) 127 128 // Freeze test 2: compare extra directories 129 // We don't know the exact structure of extra directories, so just directly compare them 130 extraDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraDirs() 131 extraPrebuiltDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraPrebuiltDirs() 132 133 var implicits []string 134 for _, dir := range append(extraDirs, extraPrebuiltDirs...) { 135 glob, err := ctx.GlobWithDeps(dir+"/**/*", []string{"bug_map"} /* exclude */) 136 if err != nil { 137 ctx.ModuleErrorf("failed to glob sepolicy dir %q: %s", dir, err.Error()) 138 return 139 } 140 implicits = append(implicits, glob...) 141 } 142 sort.Strings(implicits) 143 144 for idx, _ := range extraDirs { 145 rule.Command().Text("diff"). 146 Flag("-r"). 147 Flag("-q"). 148 FlagWithArg("-x ", "bug_map"). // exclude 149 Text(extraDirs[idx]). 150 Text(extraPrebuiltDirs[idx]) 151 } 152 153 rule.Command().Text("touch"). 154 Output(f.freezeTestTimestamp). 155 Implicits(android.PathsForSource(ctx, implicits)) 156 157 rule.Build("sepolicy_freeze_test", "sepolicy_freeze_test") 158} 159 160func (f *freezeTestModule) AndroidMkEntries() []android.AndroidMkEntries { 161 return []android.AndroidMkEntries{android.AndroidMkEntries{ 162 Class: "FAKE", 163 // OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it. 164 // Without OutputFile this module won't be exported to Makefile. 165 OutputFile: android.OptionalPathForPath(f.freezeTestTimestamp), 166 Include: "$(BUILD_PHONY_PACKAGE)", 167 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 168 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 169 entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", f.freezeTestTimestamp.String()) 170 }, 171 }, 172 }} 173} 174