1// Copyright (C) 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 "fmt" 19 "os" 20 "strconv" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25) 26 27const ( 28 // TODO: sync with Android.mk 29 MlsSens = 1 30 MlsCats = 1024 31 PolicyVers = 30 32) 33 34func init() { 35 android.RegisterModuleType("se_policy_conf", policyConfFactory) 36 android.RegisterModuleType("se_policy_cil", policyCilFactory) 37} 38 39type policyConfProperties struct { 40 // Name of the output. Default is {module_name} 41 Stem *string 42 43 // Policy files to be compiled to cil file. 44 Srcs []string `android:"path"` 45 46 // Target build variant (user / userdebug / eng). Default follows the current lunch target 47 Build_variant *string 48 49 // Whether to exclude build test or not. Default is false 50 Exclude_build_test *bool 51 52 // Whether to include asan specific policies or not. Default follows the current lunch target 53 With_asan *bool 54 55 // Whether to build CTS specific policy or not. Default is false 56 Cts *bool 57 58 // Whether this module is directly installable to one of the partitions. Default is true 59 Installable *bool 60} 61 62type policyConf struct { 63 android.ModuleBase 64 65 properties policyConfProperties 66 67 installSource android.Path 68 installPath android.InstallPath 69} 70 71// se_policy_conf merges collection of policy files into a policy.conf file to be processed by 72// checkpolicy. 73func policyConfFactory() android.Module { 74 c := &policyConf{} 75 c.AddProperties(&c.properties) 76 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon) 77 return c 78} 79 80func (c *policyConf) installable() bool { 81 return proptools.BoolDefault(c.properties.Installable, true) 82} 83 84func (c *policyConf) stem() string { 85 return proptools.StringDefault(c.properties.Stem, c.Name()) 86} 87 88func (c *policyConf) buildVariant(ctx android.ModuleContext) string { 89 if variant := proptools.String(c.properties.Build_variant); variant != "" { 90 return variant 91 } 92 if ctx.Config().Eng() { 93 return "eng" 94 } 95 if ctx.Config().Debuggable() { 96 return "userdebug" 97 } 98 return "user" 99} 100 101func (c *policyConf) cts() bool { 102 return proptools.Bool(c.properties.Cts) 103} 104 105func (c *policyConf) withAsan(ctx android.ModuleContext) string { 106 isAsanDevice := android.InList("address", ctx.Config().SanitizeDevice()) 107 return strconv.FormatBool(proptools.BoolDefault(c.properties.With_asan, isAsanDevice)) 108} 109 110func (c *policyConf) sepolicySplit(ctx android.ModuleContext) string { 111 if c.cts() { 112 return "cts" 113 } 114 return strconv.FormatBool(ctx.DeviceConfig().SepolicySplit()) 115} 116 117func (c *policyConf) compatibleProperty(ctx android.ModuleContext) string { 118 if c.cts() { 119 return "cts" 120 } 121 return "true" 122} 123 124func (c *policyConf) trebleSyspropNeverallow(ctx android.ModuleContext) string { 125 if c.cts() { 126 return "cts" 127 } 128 return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenTrebleSyspropNeverallow()) 129} 130 131func (c *policyConf) enforceSyspropOwner(ctx android.ModuleContext) string { 132 if c.cts() { 133 return "cts" 134 } 135 return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenEnforceSyspropOwner()) 136} 137 138func (c *policyConf) enforceDebugfsRestrictions(ctx android.ModuleContext) string { 139 if c.cts() { 140 return "cts" 141 } 142 return strconv.FormatBool(ctx.DeviceConfig().BuildDebugfsRestrictionsEnabled()) 143} 144 145func (c *policyConf) transformPolicyToConf(ctx android.ModuleContext) android.OutputPath { 146 conf := android.PathForModuleOut(ctx, "conf").OutputPath 147 rule := android.NewRuleBuilder(pctx, ctx) 148 rule.Command().Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")). 149 Flag("--fatal-warnings"). 150 FlagForEachArg("-D ", ctx.DeviceConfig().SepolicyM4Defs()). 151 FlagWithArg("-D mls_num_sens=", strconv.Itoa(MlsSens)). 152 FlagWithArg("-D mls_num_cats=", strconv.Itoa(MlsCats)). 153 FlagWithArg("-D target_arch=", ctx.DeviceConfig().DeviceArch()). 154 FlagWithArg("-D target_with_asan=", c.withAsan(ctx)). 155 FlagWithArg("-D target_with_dexpreopt=", strconv.FormatBool(ctx.DeviceConfig().WithDexpreopt())). 156 FlagWithArg("-D target_with_native_coverage=", strconv.FormatBool(ctx.DeviceConfig().ClangCoverageEnabled() || ctx.DeviceConfig().GcovCoverageEnabled())). 157 FlagWithArg("-D target_build_variant=", c.buildVariant(ctx)). 158 FlagWithArg("-D target_full_treble=", c.sepolicySplit(ctx)). 159 FlagWithArg("-D target_compatible_property=", c.compatibleProperty(ctx)). 160 FlagWithArg("-D target_treble_sysprop_neverallow=", c.trebleSyspropNeverallow(ctx)). 161 FlagWithArg("-D target_enforce_sysprop_owner=", c.enforceSyspropOwner(ctx)). 162 FlagWithArg("-D target_exclude_build_test=", strconv.FormatBool(proptools.Bool(c.properties.Exclude_build_test))). 163 FlagWithArg("-D target_requires_insecure_execmem_for_swiftshader=", strconv.FormatBool(ctx.DeviceConfig().RequiresInsecureExecmemForSwiftshader())). 164 FlagWithArg("-D target_enforce_debugfs_restriction=", c.enforceDebugfsRestrictions(ctx)). 165 Flag("-s"). 166 Inputs(android.PathsForModuleSrc(ctx, c.properties.Srcs)). 167 Text("> ").Output(conf) 168 169 rule.Build("conf", "Transform policy to conf: "+ctx.ModuleName()) 170 return conf 171} 172 173func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) { 174 // do nothing 175} 176 177func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) { 178 c.installSource = c.transformPolicyToConf(ctx) 179 c.installPath = android.PathForModuleInstall(ctx, "etc") 180 ctx.InstallFile(c.installPath, c.stem(), c.installSource) 181 182 if !c.installable() { 183 c.SkipInstall() 184 } 185} 186 187func (c *policyConf) AndroidMkEntries() []android.AndroidMkEntries { 188 return []android.AndroidMkEntries{android.AndroidMkEntries{ 189 OutputFile: android.OptionalPathForPath(c.installSource), 190 Class: "ETC", 191 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 192 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 193 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.installable()) 194 entries.SetPath("LOCAL_MODULE_PATH", c.installPath.ToMakePath()) 195 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem()) 196 }, 197 }, 198 }} 199} 200 201func (c *policyConf) OutputFiles(tag string) (android.Paths, error) { 202 if tag == "" { 203 return android.Paths{c.installSource}, nil 204 } 205 return nil, fmt.Errorf("Unknown tag %q", tag) 206} 207 208var _ android.OutputFileProducer = (*policyConf)(nil) 209 210type policyCilProperties struct { 211 // Name of the output. Default is {module_name} 212 Stem *string 213 214 // Policy file to be compiled to cil file. 215 Src *string `android:"path"` 216 217 // Additional cil files to be added in the end of the output. This is to support workarounds 218 // which are not supported by the policy language. 219 Additional_cil_files []string `android:"path"` 220 221 // Cil files to be filtered out by the filter_out tool of "build_sepolicy". Used to build 222 // exported policies 223 Filter_out []string `android:"path"` 224 225 // Whether to remove line markers (denoted by ;;) out of compiled cil files. Defaults to false 226 Remove_line_marker *bool 227 228 // Whether to run secilc to check compiled policy or not. Defaults to true 229 Secilc_check *bool 230 231 // Whether to ignore neverallow when running secilc check. Defaults to 232 // SELINUX_IGNORE_NEVERALLOWS. 233 Ignore_neverallow *bool 234 235 // Whether this module is directly installable to one of the partitions. Default is true 236 Installable *bool 237} 238 239type policyCil struct { 240 android.ModuleBase 241 242 properties policyCilProperties 243 244 installSource android.Path 245 installPath android.InstallPath 246} 247 248// se_policy_cil compiles a policy.conf file to a cil file with checkpolicy, and optionally runs 249// secilc to check the output cil file. Affected by SELINUX_IGNORE_NEVERALLOWS. 250func policyCilFactory() android.Module { 251 c := &policyCil{} 252 c.AddProperties(&c.properties) 253 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon) 254 return c 255} 256 257func (c *policyCil) Installable() bool { 258 return proptools.BoolDefault(c.properties.Installable, true) 259} 260 261func (c *policyCil) stem() string { 262 return proptools.StringDefault(c.properties.Stem, c.Name()) 263} 264 265func (c *policyCil) compileConfToCil(ctx android.ModuleContext, conf android.Path) android.OutputPath { 266 cil := android.PathForModuleOut(ctx, c.stem()).OutputPath 267 rule := android.NewRuleBuilder(pctx, ctx) 268 rule.Command().BuiltTool("checkpolicy"). 269 Flag("-C"). // Write CIL 270 Flag("-M"). // Enable MLS 271 FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 272 FlagWithOutput("-o ", cil). 273 Input(conf) 274 275 if len(c.properties.Additional_cil_files) > 0 { 276 rule.Command().Text("cat"). 277 Inputs(android.PathsForModuleSrc(ctx, c.properties.Additional_cil_files)). 278 Text(">> ").Output(cil) 279 } 280 281 if len(c.properties.Filter_out) > 0 { 282 rule.Command().BuiltTool("build_sepolicy"). 283 Text("filter_out"). 284 Flag("-f"). 285 Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). 286 FlagWithOutput("-t ", cil) 287 } 288 289 if proptools.Bool(c.properties.Remove_line_marker) { 290 rule.Command().Text("grep -v"). 291 Text(proptools.ShellEscape(";;")). 292 Text(cil.String()). 293 Text(">"). 294 Text(cil.String() + ".tmp"). 295 Text("&& mv"). 296 Text(cil.String() + ".tmp"). 297 Text(cil.String()) 298 } 299 300 if proptools.BoolDefault(c.properties.Secilc_check, true) { 301 secilcCmd := rule.Command().BuiltTool("secilc"). 302 Flag("-m"). // Multiple decls 303 FlagWithArg("-M ", "true"). // Enable MLS 304 Flag("-G"). // expand and remove auto generated attributes 305 FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 306 Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). // Also add cil files which are filtered out 307 Text(cil.String()). 308 FlagWithArg("-o ", os.DevNull). 309 FlagWithArg("-f ", os.DevNull) 310 311 if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) { 312 secilcCmd.Flag("-N") 313 } 314 } 315 316 rule.Build("cil", "Building cil for "+ctx.ModuleName()) 317 return cil 318} 319 320func (c *policyCil) GenerateAndroidBuildActions(ctx android.ModuleContext) { 321 if proptools.String(c.properties.Src) == "" { 322 ctx.PropertyErrorf("src", "must be specified") 323 return 324 } 325 conf := android.PathForModuleSrc(ctx, *c.properties.Src) 326 cil := c.compileConfToCil(ctx, conf) 327 328 if c.InstallInDebugRamdisk() { 329 // for userdebug_plat_sepolicy.cil 330 c.installPath = android.PathForModuleInstall(ctx) 331 } else { 332 c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux") 333 } 334 c.installSource = cil 335 ctx.InstallFile(c.installPath, c.stem(), c.installSource) 336 337 if !c.Installable() { 338 c.SkipInstall() 339 } 340} 341 342func (c *policyCil) AndroidMkEntries() []android.AndroidMkEntries { 343 return []android.AndroidMkEntries{android.AndroidMkEntries{ 344 OutputFile: android.OptionalPathForPath(c.installSource), 345 Class: "ETC", 346 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 347 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 348 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable()) 349 entries.SetPath("LOCAL_MODULE_PATH", c.installPath.ToMakePath()) 350 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem()) 351 }, 352 }, 353 }} 354} 355 356func (c *policyCil) OutputFiles(tag string) (android.Paths, error) { 357 if tag == "" { 358 return android.Paths{c.installSource}, nil 359 } 360 return nil, fmt.Errorf("Unknown tag %q", tag) 361} 362 363var _ android.OutputFileProducer = (*policyCil)(nil) 364