1*e4a36f41SAndroid Build Coastguard Worker// Copyright 2021 The Android Open Source Project 2*e4a36f41SAndroid Build Coastguard Worker// 3*e4a36f41SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*e4a36f41SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*e4a36f41SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*e4a36f41SAndroid Build Coastguard Worker// 7*e4a36f41SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*e4a36f41SAndroid Build Coastguard Worker// 9*e4a36f41SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*e4a36f41SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*e4a36f41SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e4a36f41SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*e4a36f41SAndroid Build Coastguard Worker// limitations under the License. 14*e4a36f41SAndroid Build Coastguard Worker 15*e4a36f41SAndroid Build Coastguard Workerpackage selinux 16*e4a36f41SAndroid Build Coastguard Worker 17*e4a36f41SAndroid Build Coastguard Workerimport ( 18*e4a36f41SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 19*e4a36f41SAndroid Build Coastguard Worker 20*e4a36f41SAndroid Build Coastguard Worker "fmt" 21*e4a36f41SAndroid Build Coastguard Worker "strconv" 22*e4a36f41SAndroid Build Coastguard Worker 23*e4a36f41SAndroid Build Coastguard Worker "android/soong/android" 24*e4a36f41SAndroid Build Coastguard Worker) 25*e4a36f41SAndroid Build Coastguard Worker 26*e4a36f41SAndroid Build Coastguard Workerfunc init() { 27*e4a36f41SAndroid Build Coastguard Worker ctx := android.InitRegistrationContext 28*e4a36f41SAndroid Build Coastguard Worker ctx.RegisterModuleType("se_neverallow_test", neverallowTestFactory) 29*e4a36f41SAndroid Build Coastguard Worker} 30*e4a36f41SAndroid Build Coastguard Worker 31*e4a36f41SAndroid Build Coastguard Workertype neverallowTestProperties struct { 32*e4a36f41SAndroid Build Coastguard Worker // Default modules for conf 33*e4a36f41SAndroid Build Coastguard Worker Defaults []string 34*e4a36f41SAndroid Build Coastguard Worker 35*e4a36f41SAndroid Build Coastguard Worker // Policy files to be tested. 36*e4a36f41SAndroid Build Coastguard Worker Srcs []string `android:"path"` 37*e4a36f41SAndroid Build Coastguard Worker} 38*e4a36f41SAndroid Build Coastguard Worker 39*e4a36f41SAndroid Build Coastguard Workertype neverallowTestModule struct { 40*e4a36f41SAndroid Build Coastguard Worker android.ModuleBase 41*e4a36f41SAndroid Build Coastguard Worker properties neverallowTestProperties 42*e4a36f41SAndroid Build Coastguard Worker testTimestamp android.OutputPath 43*e4a36f41SAndroid Build Coastguard Worker} 44*e4a36f41SAndroid Build Coastguard Worker 45*e4a36f41SAndroid Build Coastguard Workertype nameProperties struct { 46*e4a36f41SAndroid Build Coastguard Worker Name *string 47*e4a36f41SAndroid Build Coastguard Worker} 48*e4a36f41SAndroid Build Coastguard Worker 49*e4a36f41SAndroid Build Coastguard Workervar checkpolicyTag = dependencyTag{name: "checkpolicy"} 50*e4a36f41SAndroid Build Coastguard Workervar sepolicyAnalyzeTag = dependencyTag{name: "sepolicy_analyze"} 51*e4a36f41SAndroid Build Coastguard Worker 52*e4a36f41SAndroid Build Coastguard Worker// se_neverallow_test builds given policy files and checks whether any neverallow violations exist. 53*e4a36f41SAndroid Build Coastguard Worker// This module creates two conf files, one with build test and one without build test. Policy with 54*e4a36f41SAndroid Build Coastguard Worker// build test will be compiled with checkpolicy, and policy without build test will be tested with 55*e4a36f41SAndroid Build Coastguard Worker// sepolicy-analyze's neverallow tool. This module's check can be skipped by setting 56*e4a36f41SAndroid Build Coastguard Worker// SELINUX_IGNORE_NEVERALLOWS := true. 57*e4a36f41SAndroid Build Coastguard Workerfunc neverallowTestFactory() android.Module { 58*e4a36f41SAndroid Build Coastguard Worker n := &neverallowTestModule{} 59*e4a36f41SAndroid Build Coastguard Worker n.AddProperties(&n.properties) 60*e4a36f41SAndroid Build Coastguard Worker android.InitAndroidArchModule(n, android.DeviceSupported, android.MultilibCommon) 61*e4a36f41SAndroid Build Coastguard Worker android.AddLoadHook(n, func(ctx android.LoadHookContext) { 62*e4a36f41SAndroid Build Coastguard Worker n.loadHook(ctx) 63*e4a36f41SAndroid Build Coastguard Worker }) 64*e4a36f41SAndroid Build Coastguard Worker return n 65*e4a36f41SAndroid Build Coastguard Worker} 66*e4a36f41SAndroid Build Coastguard Worker 67*e4a36f41SAndroid Build Coastguard Worker// Child conf module name for checkpolicy test. 68*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) checkpolicyConfModuleName() string { 69*e4a36f41SAndroid Build Coastguard Worker return n.Name() + ".checkpolicy.conf" 70*e4a36f41SAndroid Build Coastguard Worker} 71*e4a36f41SAndroid Build Coastguard Worker 72*e4a36f41SAndroid Build Coastguard Worker// Child conf module name for sepolicy-analyze test. 73*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) sepolicyAnalyzeConfModuleName() string { 74*e4a36f41SAndroid Build Coastguard Worker return n.Name() + ".sepolicy_analyze.conf" 75*e4a36f41SAndroid Build Coastguard Worker} 76*e4a36f41SAndroid Build Coastguard Worker 77*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) loadHook(ctx android.LoadHookContext) { 78*e4a36f41SAndroid Build Coastguard Worker checkpolicyConf := n.checkpolicyConfModuleName() 79*e4a36f41SAndroid Build Coastguard Worker ctx.CreateModule(policyConfFactory, &nameProperties{ 80*e4a36f41SAndroid Build Coastguard Worker Name: proptools.StringPtr(checkpolicyConf), 81*e4a36f41SAndroid Build Coastguard Worker }, &policyConfProperties{ 82*e4a36f41SAndroid Build Coastguard Worker Srcs: n.properties.Srcs, 83*e4a36f41SAndroid Build Coastguard Worker Build_variant: proptools.StringPtr("user"), 84*e4a36f41SAndroid Build Coastguard Worker Installable: proptools.BoolPtr(false), 85*e4a36f41SAndroid Build Coastguard Worker }, &struct { 86*e4a36f41SAndroid Build Coastguard Worker Defaults []string 87*e4a36f41SAndroid Build Coastguard Worker }{ 88*e4a36f41SAndroid Build Coastguard Worker Defaults: n.properties.Defaults, 89*e4a36f41SAndroid Build Coastguard Worker }) 90*e4a36f41SAndroid Build Coastguard Worker 91*e4a36f41SAndroid Build Coastguard Worker sepolicyAnalyzeConf := n.sepolicyAnalyzeConfModuleName() 92*e4a36f41SAndroid Build Coastguard Worker ctx.CreateModule(policyConfFactory, &nameProperties{ 93*e4a36f41SAndroid Build Coastguard Worker Name: proptools.StringPtr(sepolicyAnalyzeConf), 94*e4a36f41SAndroid Build Coastguard Worker }, &policyConfProperties{ 95*e4a36f41SAndroid Build Coastguard Worker Srcs: n.properties.Srcs, 96*e4a36f41SAndroid Build Coastguard Worker Build_variant: proptools.StringPtr("user"), 97*e4a36f41SAndroid Build Coastguard Worker Exclude_build_test: proptools.BoolPtr(true), 98*e4a36f41SAndroid Build Coastguard Worker Installable: proptools.BoolPtr(false), 99*e4a36f41SAndroid Build Coastguard Worker }, &struct { 100*e4a36f41SAndroid Build Coastguard Worker Defaults []string 101*e4a36f41SAndroid Build Coastguard Worker }{ 102*e4a36f41SAndroid Build Coastguard Worker Defaults: n.properties.Defaults, 103*e4a36f41SAndroid Build Coastguard Worker }) 104*e4a36f41SAndroid Build Coastguard Worker} 105*e4a36f41SAndroid Build Coastguard Worker 106*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) DepsMutator(ctx android.BottomUpMutatorContext) { 107*e4a36f41SAndroid Build Coastguard Worker ctx.AddDependency(n, checkpolicyTag, n.checkpolicyConfModuleName()) 108*e4a36f41SAndroid Build Coastguard Worker ctx.AddDependency(n, sepolicyAnalyzeTag, n.sepolicyAnalyzeConfModuleName()) 109*e4a36f41SAndroid Build Coastguard Worker} 110*e4a36f41SAndroid Build Coastguard Worker 111*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 112*e4a36f41SAndroid Build Coastguard Worker n.testTimestamp = pathForModuleOut(ctx, "timestamp") 113*e4a36f41SAndroid Build Coastguard Worker if ctx.Config().SelinuxIgnoreNeverallows() { 114*e4a36f41SAndroid Build Coastguard Worker // just touch 115*e4a36f41SAndroid Build Coastguard Worker android.WriteFileRule(ctx, n.testTimestamp, "") 116*e4a36f41SAndroid Build Coastguard Worker return 117*e4a36f41SAndroid Build Coastguard Worker } 118*e4a36f41SAndroid Build Coastguard Worker 119*e4a36f41SAndroid Build Coastguard Worker var checkpolicyConfPaths android.Paths 120*e4a36f41SAndroid Build Coastguard Worker var sepolicyAnalyzeConfPaths android.Paths 121*e4a36f41SAndroid Build Coastguard Worker 122*e4a36f41SAndroid Build Coastguard Worker ctx.VisitDirectDeps(func(child android.Module) { 123*e4a36f41SAndroid Build Coastguard Worker depTag := ctx.OtherModuleDependencyTag(child) 124*e4a36f41SAndroid Build Coastguard Worker if depTag != checkpolicyTag && depTag != sepolicyAnalyzeTag { 125*e4a36f41SAndroid Build Coastguard Worker return 126*e4a36f41SAndroid Build Coastguard Worker } 127*e4a36f41SAndroid Build Coastguard Worker 128*e4a36f41SAndroid Build Coastguard Worker outputs := android.OutputFilesForModule(ctx, child, "") 129*e4a36f41SAndroid Build Coastguard Worker 130*e4a36f41SAndroid Build Coastguard Worker switch ctx.OtherModuleDependencyTag(child) { 131*e4a36f41SAndroid Build Coastguard Worker case checkpolicyTag: 132*e4a36f41SAndroid Build Coastguard Worker checkpolicyConfPaths = outputs 133*e4a36f41SAndroid Build Coastguard Worker case sepolicyAnalyzeTag: 134*e4a36f41SAndroid Build Coastguard Worker sepolicyAnalyzeConfPaths = outputs 135*e4a36f41SAndroid Build Coastguard Worker } 136*e4a36f41SAndroid Build Coastguard Worker }) 137*e4a36f41SAndroid Build Coastguard Worker 138*e4a36f41SAndroid Build Coastguard Worker if len(checkpolicyConfPaths) != 1 { 139*e4a36f41SAndroid Build Coastguard Worker panic(fmt.Errorf("Module %q should produce exactly one output", n.checkpolicyConfModuleName())) 140*e4a36f41SAndroid Build Coastguard Worker } 141*e4a36f41SAndroid Build Coastguard Worker 142*e4a36f41SAndroid Build Coastguard Worker if len(sepolicyAnalyzeConfPaths) != 1 { 143*e4a36f41SAndroid Build Coastguard Worker panic(fmt.Errorf("Module %q should produce exactly one output", n.sepolicyAnalyzeConfModuleName())) 144*e4a36f41SAndroid Build Coastguard Worker } 145*e4a36f41SAndroid Build Coastguard Worker 146*e4a36f41SAndroid Build Coastguard Worker checkpolicyConfPath := checkpolicyConfPaths[0] 147*e4a36f41SAndroid Build Coastguard Worker sepolicyAnalyzeConfPath := sepolicyAnalyzeConfPaths[0] 148*e4a36f41SAndroid Build Coastguard Worker 149*e4a36f41SAndroid Build Coastguard Worker rule := android.NewRuleBuilder(pctx, ctx) 150*e4a36f41SAndroid Build Coastguard Worker 151*e4a36f41SAndroid Build Coastguard Worker // Step 1. Build a binary policy from the conf file including build test 152*e4a36f41SAndroid Build Coastguard Worker binaryPolicy := pathForModuleOut(ctx, "policy") 153*e4a36f41SAndroid Build Coastguard Worker rule.Command().BuiltTool("checkpolicy"). 154*e4a36f41SAndroid Build Coastguard Worker Flag("-M"). 155*e4a36f41SAndroid Build Coastguard Worker FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 156*e4a36f41SAndroid Build Coastguard Worker FlagWithOutput("-o ", binaryPolicy). 157*e4a36f41SAndroid Build Coastguard Worker Input(checkpolicyConfPath) 158*e4a36f41SAndroid Build Coastguard Worker rule.Build("neverallow_checkpolicy", "Neverallow check: "+ctx.ModuleName()) 159*e4a36f41SAndroid Build Coastguard Worker 160*e4a36f41SAndroid Build Coastguard Worker // Step 2. Run sepolicy-analyze with the conf file without the build test and binary policy 161*e4a36f41SAndroid Build Coastguard Worker // file from Step 1 162*e4a36f41SAndroid Build Coastguard Worker rule = android.NewRuleBuilder(pctx, ctx) 163*e4a36f41SAndroid Build Coastguard Worker msg := `sepolicy-analyze failed. This is most likely due to the use\n` + 164*e4a36f41SAndroid Build Coastguard Worker `of an expanded attribute in a neverallow assertion. Please fix\n` + 165*e4a36f41SAndroid Build Coastguard Worker `the policy.` 166*e4a36f41SAndroid Build Coastguard Worker 167*e4a36f41SAndroid Build Coastguard Worker rule.Command().BuiltTool("sepolicy-analyze"). 168*e4a36f41SAndroid Build Coastguard Worker Input(binaryPolicy). 169*e4a36f41SAndroid Build Coastguard Worker Text("neverallow"). 170*e4a36f41SAndroid Build Coastguard Worker Flag("-w"). 171*e4a36f41SAndroid Build Coastguard Worker FlagWithInput("-f ", sepolicyAnalyzeConfPath). 172*e4a36f41SAndroid Build Coastguard Worker Text("|| (echo"). 173*e4a36f41SAndroid Build Coastguard Worker Flag("-e"). 174*e4a36f41SAndroid Build Coastguard Worker Text(`"` + msg + `"`). 175*e4a36f41SAndroid Build Coastguard Worker Text("; exit 1)") 176*e4a36f41SAndroid Build Coastguard Worker 177*e4a36f41SAndroid Build Coastguard Worker rule.Command().Text("touch").Output(n.testTimestamp) 178*e4a36f41SAndroid Build Coastguard Worker rule.Build("neverallow_sepolicy-analyze", "Neverallow check: "+ctx.ModuleName()) 179*e4a36f41SAndroid Build Coastguard Worker} 180*e4a36f41SAndroid Build Coastguard Worker 181*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) AndroidMkEntries() []android.AndroidMkEntries { 182*e4a36f41SAndroid Build Coastguard Worker return []android.AndroidMkEntries{android.AndroidMkEntries{ 183*e4a36f41SAndroid Build Coastguard Worker OutputFile: android.OptionalPathForPath(n.testTimestamp), 184*e4a36f41SAndroid Build Coastguard Worker Class: "FAKE", 185*e4a36f41SAndroid Build Coastguard Worker Include: "$(BUILD_PHONY_PACKAGE)", 186*e4a36f41SAndroid Build Coastguard Worker ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 187*e4a36f41SAndroid Build Coastguard Worker func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 188*e4a36f41SAndroid Build Coastguard Worker entries.SetPath("LOCAL_ADDITIONAL_DEPENDENCIES", n.testTimestamp) 189*e4a36f41SAndroid Build Coastguard Worker }, 190*e4a36f41SAndroid Build Coastguard Worker }, 191*e4a36f41SAndroid Build Coastguard Worker }} 192*e4a36f41SAndroid Build Coastguard Worker} 193