Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 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 | |
| 15 | package selinux |
| 16 | |
| 17 | import ( |
| 18 | "github.com/google/blueprint/proptools" |
| 19 | |
| 20 | "fmt" |
| 21 | "strconv" |
| 22 | |
| 23 | "android/soong/android" |
| 24 | ) |
| 25 | |
| 26 | func init() { |
| 27 | ctx := android.InitRegistrationContext |
| 28 | ctx.RegisterModuleType("se_neverallow_test", neverallowTestFactory) |
| 29 | } |
| 30 | |
| 31 | type neverallowTestProperties struct { |
Inseob Kim | 085f22f | 2023-11-09 11:13:01 +0900 | [diff] [blame] | 32 | // Default modules for conf |
| 33 | Defaults []string |
| 34 | |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 35 | // Policy files to be tested. |
| 36 | Srcs []string `android:"path"` |
| 37 | } |
| 38 | |
| 39 | type neverallowTestModule struct { |
| 40 | android.ModuleBase |
| 41 | properties neverallowTestProperties |
Inseob Kim | 6c6f53b | 2023-04-26 11:03:35 +0900 | [diff] [blame] | 42 | testTimestamp android.OutputPath |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 43 | } |
| 44 | |
| 45 | type nameProperties struct { |
| 46 | Name *string |
| 47 | } |
| 48 | |
| 49 | var checkpolicyTag = dependencyTag{name: "checkpolicy"} |
| 50 | var sepolicyAnalyzeTag = dependencyTag{name: "sepolicy_analyze"} |
| 51 | |
| 52 | // se_neverallow_test builds given policy files and checks whether any neverallow violations exist. |
| 53 | // This module creates two conf files, one with build test and one without build test. Policy with |
| 54 | // build test will be compiled with checkpolicy, and policy without build test will be tested with |
| 55 | // sepolicy-analyze's neverallow tool. This module's check can be skipped by setting |
| 56 | // SELINUX_IGNORE_NEVERALLOWS := true. |
| 57 | func neverallowTestFactory() android.Module { |
| 58 | n := &neverallowTestModule{} |
| 59 | n.AddProperties(&n.properties) |
Cole Faust | 09e326f | 2024-10-07 16:54:31 -0700 | [diff] [blame] | 60 | android.InitAndroidArchModule(n, android.DeviceSupported, android.MultilibCommon) |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 61 | android.AddLoadHook(n, func(ctx android.LoadHookContext) { |
| 62 | n.loadHook(ctx) |
| 63 | }) |
| 64 | return n |
| 65 | } |
| 66 | |
| 67 | // Child conf module name for checkpolicy test. |
| 68 | func (n *neverallowTestModule) checkpolicyConfModuleName() string { |
| 69 | return n.Name() + ".checkpolicy.conf" |
| 70 | } |
| 71 | |
| 72 | // Child conf module name for sepolicy-analyze test. |
| 73 | func (n *neverallowTestModule) sepolicyAnalyzeConfModuleName() string { |
| 74 | return n.Name() + ".sepolicy_analyze.conf" |
| 75 | } |
| 76 | |
| 77 | func (n *neverallowTestModule) loadHook(ctx android.LoadHookContext) { |
| 78 | checkpolicyConf := n.checkpolicyConfModuleName() |
| 79 | ctx.CreateModule(policyConfFactory, &nameProperties{ |
| 80 | Name: proptools.StringPtr(checkpolicyConf), |
| 81 | }, &policyConfProperties{ |
| 82 | Srcs: n.properties.Srcs, |
| 83 | Build_variant: proptools.StringPtr("user"), |
| 84 | Installable: proptools.BoolPtr(false), |
Inseob Kim | 085f22f | 2023-11-09 11:13:01 +0900 | [diff] [blame] | 85 | }, &struct { |
| 86 | Defaults []string |
| 87 | }{ |
| 88 | Defaults: n.properties.Defaults, |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 89 | }) |
| 90 | |
| 91 | sepolicyAnalyzeConf := n.sepolicyAnalyzeConfModuleName() |
| 92 | ctx.CreateModule(policyConfFactory, &nameProperties{ |
| 93 | Name: proptools.StringPtr(sepolicyAnalyzeConf), |
| 94 | }, &policyConfProperties{ |
| 95 | Srcs: n.properties.Srcs, |
| 96 | Build_variant: proptools.StringPtr("user"), |
| 97 | Exclude_build_test: proptools.BoolPtr(true), |
| 98 | Installable: proptools.BoolPtr(false), |
Inseob Kim | 085f22f | 2023-11-09 11:13:01 +0900 | [diff] [blame] | 99 | }, &struct { |
| 100 | Defaults []string |
| 101 | }{ |
| 102 | Defaults: n.properties.Defaults, |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 103 | }) |
| 104 | } |
| 105 | |
| 106 | func (n *neverallowTestModule) DepsMutator(ctx android.BottomUpMutatorContext) { |
| 107 | ctx.AddDependency(n, checkpolicyTag, n.checkpolicyConfModuleName()) |
| 108 | ctx.AddDependency(n, sepolicyAnalyzeTag, n.sepolicyAnalyzeConfModuleName()) |
| 109 | } |
| 110 | |
| 111 | func (n *neverallowTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
Inseob Kim | 6c6f53b | 2023-04-26 11:03:35 +0900 | [diff] [blame] | 112 | n.testTimestamp = pathForModuleOut(ctx, "timestamp") |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 113 | if ctx.Config().SelinuxIgnoreNeverallows() { |
| 114 | // just touch |
| 115 | android.WriteFileRule(ctx, n.testTimestamp, "") |
| 116 | return |
| 117 | } |
| 118 | |
| 119 | var checkpolicyConfPaths android.Paths |
| 120 | var sepolicyAnalyzeConfPaths android.Paths |
| 121 | |
| 122 | ctx.VisitDirectDeps(func(child android.Module) { |
| 123 | depTag := ctx.OtherModuleDependencyTag(child) |
| 124 | if depTag != checkpolicyTag && depTag != sepolicyAnalyzeTag { |
| 125 | return |
| 126 | } |
| 127 | |
mrziwang | cb3f550 | 2024-06-06 10:04:23 -0700 | [diff] [blame] | 128 | outputs := android.OutputFilesForModule(ctx, child, "") |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 129 | |
| 130 | switch ctx.OtherModuleDependencyTag(child) { |
| 131 | case checkpolicyTag: |
| 132 | checkpolicyConfPaths = outputs |
| 133 | case sepolicyAnalyzeTag: |
| 134 | sepolicyAnalyzeConfPaths = outputs |
| 135 | } |
| 136 | }) |
| 137 | |
| 138 | if len(checkpolicyConfPaths) != 1 { |
| 139 | panic(fmt.Errorf("Module %q should produce exactly one output", n.checkpolicyConfModuleName())) |
| 140 | } |
| 141 | |
| 142 | if len(sepolicyAnalyzeConfPaths) != 1 { |
| 143 | panic(fmt.Errorf("Module %q should produce exactly one output", n.sepolicyAnalyzeConfModuleName())) |
| 144 | } |
| 145 | |
| 146 | checkpolicyConfPath := checkpolicyConfPaths[0] |
| 147 | sepolicyAnalyzeConfPath := sepolicyAnalyzeConfPaths[0] |
| 148 | |
| 149 | rule := android.NewRuleBuilder(pctx, ctx) |
| 150 | |
| 151 | // Step 1. Build a binary policy from the conf file including build test |
Inseob Kim | 6c6f53b | 2023-04-26 11:03:35 +0900 | [diff] [blame] | 152 | binaryPolicy := pathForModuleOut(ctx, "policy") |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 153 | rule.Command().BuiltTool("checkpolicy"). |
| 154 | Flag("-M"). |
| 155 | FlagWithArg("-c ", strconv.Itoa(PolicyVers)). |
| 156 | FlagWithOutput("-o ", binaryPolicy). |
| 157 | Input(checkpolicyConfPath) |
Thiébaud Weksteen | 9ebf0c8 | 2022-01-25 21:07:00 +1100 | [diff] [blame] | 158 | rule.Build("neverallow_checkpolicy", "Neverallow check: "+ctx.ModuleName()) |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 159 | |
| 160 | // Step 2. Run sepolicy-analyze with the conf file without the build test and binary policy |
| 161 | // file from Step 1 |
Thiébaud Weksteen | 9ebf0c8 | 2022-01-25 21:07:00 +1100 | [diff] [blame] | 162 | rule = android.NewRuleBuilder(pctx, ctx) |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 163 | msg := `sepolicy-analyze failed. This is most likely due to the use\n` + |
| 164 | `of an expanded attribute in a neverallow assertion. Please fix\n` + |
| 165 | `the policy.` |
| 166 | |
| 167 | rule.Command().BuiltTool("sepolicy-analyze"). |
| 168 | Input(binaryPolicy). |
| 169 | Text("neverallow"). |
| 170 | Flag("-w"). |
| 171 | FlagWithInput("-f ", sepolicyAnalyzeConfPath). |
| 172 | Text("|| (echo"). |
| 173 | Flag("-e"). |
| 174 | Text(`"` + msg + `"`). |
| 175 | Text("; exit 1)") |
| 176 | |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 177 | rule.Command().Text("touch").Output(n.testTimestamp) |
Thiébaud Weksteen | 9ebf0c8 | 2022-01-25 21:07:00 +1100 | [diff] [blame] | 178 | rule.Build("neverallow_sepolicy-analyze", "Neverallow check: "+ctx.ModuleName()) |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | func (n *neverallowTestModule) AndroidMkEntries() []android.AndroidMkEntries { |
| 182 | return []android.AndroidMkEntries{android.AndroidMkEntries{ |
| 183 | OutputFile: android.OptionalPathForPath(n.testTimestamp), |
Inseob Kim | 021596b | 2024-04-15 11:07:07 +0900 | [diff] [blame] | 184 | Class: "FAKE", |
| 185 | Include: "$(BUILD_PHONY_PACKAGE)", |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 186 | ExtraEntries: []android.AndroidMkExtraEntriesFunc{ |
| 187 | func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { |
Inseob Kim | 021596b | 2024-04-15 11:07:07 +0900 | [diff] [blame] | 188 | entries.SetPath("LOCAL_ADDITIONAL_DEPENDENCIES", n.testTimestamp) |
Inseob Kim | 0de7fcc | 2021-12-22 23:06:53 +0900 | [diff] [blame] | 189 | }, |
| 190 | }, |
| 191 | }} |
| 192 | } |