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 "sort" 21 "strconv" 22 "strings" 23 24 "github.com/google/blueprint/proptools" 25 26 "android/soong/android" 27) 28 29const ( 30 // TODO: sync with Android.mk 31 MlsSens = 1 32 MlsCats = 1024 33 PolicyVers = 30 34) 35 36// This order should be kept. checkpolicy syntax requires it. 37var policyConfOrder = []string{ 38 "security_classes", 39 "initial_sids", 40 "access_vectors", 41 "global_macros", 42 "neverallow_macros", 43 "mls_macros", 44 "mls_decl", 45 "mls", 46 "policy_capabilities", 47 "te_macros", 48 "attributes", 49 "ioctl_defines", 50 "ioctl_macros", 51 "*.te", 52 "roles_decl", 53 "roles", 54 "users", 55 "initial_sid_contexts", 56 "fs_use", 57 "genfs_contexts", 58 "port_contexts", 59} 60 61func init() { 62 android.RegisterModuleType("se_policy_conf", policyConfFactory) 63 android.RegisterModuleType("se_policy_cil", policyCilFactory) 64 android.RegisterModuleType("se_policy_binary", policyBinaryFactory) 65} 66 67type policyConfProperties struct { 68 // Name of the output. Default is {module_name} 69 Stem *string 70 71 // Policy files to be compiled to cil file. 72 Srcs []string `android:"path"` 73 74 // Target build variant (user / userdebug / eng). Default follows the current lunch target 75 Build_variant *string 76 77 // Whether to exclude build test or not. Default is false 78 Exclude_build_test *bool 79 80 // Whether to include asan specific policies or not. Default follows the current lunch target 81 With_asan *bool 82 83 // Whether to build CTS specific policy or not. Default is false 84 Cts *bool 85 86 // Whether to build recovery specific policy or not. Default is false 87 Target_recovery *bool 88 89 // Whether this module is directly installable to one of the partitions. Default is true 90 Installable *bool 91 92 // Desired number of MLS categories. Defaults to 1024 93 Mls_cats *int64 94} 95 96type policyConf struct { 97 android.ModuleBase 98 99 properties policyConfProperties 100 101 installSource android.Path 102 installPath android.InstallPath 103} 104 105// se_policy_conf merges collection of policy files into a policy.conf file to be processed by 106// checkpolicy. 107func policyConfFactory() android.Module { 108 c := &policyConf{} 109 c.AddProperties(&c.properties) 110 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon) 111 return c 112} 113 114func (c *policyConf) installable() bool { 115 return proptools.BoolDefault(c.properties.Installable, true) 116} 117 118func (c *policyConf) stem() string { 119 return proptools.StringDefault(c.properties.Stem, c.Name()) 120} 121 122func (c *policyConf) buildVariant(ctx android.ModuleContext) string { 123 if variant := proptools.String(c.properties.Build_variant); variant != "" { 124 return variant 125 } 126 if ctx.Config().Eng() { 127 return "eng" 128 } 129 if ctx.Config().Debuggable() { 130 return "userdebug" 131 } 132 return "user" 133} 134 135func (c *policyConf) cts() bool { 136 return proptools.Bool(c.properties.Cts) 137} 138 139func (c *policyConf) isTargetRecovery() bool { 140 return proptools.Bool(c.properties.Target_recovery) 141} 142 143func (c *policyConf) withAsan(ctx android.ModuleContext) string { 144 isAsanDevice := android.InList("address", ctx.Config().SanitizeDevice()) 145 return strconv.FormatBool(proptools.BoolDefault(c.properties.With_asan, isAsanDevice)) 146} 147 148func (c *policyConf) sepolicySplit(ctx android.ModuleContext) string { 149 if c.cts() { 150 return "cts" 151 } 152 if c.isTargetRecovery() { 153 return "false" 154 } 155 return strconv.FormatBool(ctx.DeviceConfig().SepolicySplit()) 156} 157 158func (c *policyConf) compatibleProperty(ctx android.ModuleContext) string { 159 if c.cts() { 160 return "cts" 161 } 162 if c.isTargetRecovery() { 163 return "false" 164 } 165 return "true" 166} 167 168func (c *policyConf) trebleSyspropNeverallow(ctx android.ModuleContext) string { 169 if c.cts() { 170 return "cts" 171 } 172 if c.isTargetRecovery() { 173 return "false" 174 } 175 return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenTrebleSyspropNeverallow()) 176} 177 178func (c *policyConf) enforceSyspropOwner(ctx android.ModuleContext) string { 179 if c.cts() { 180 return "cts" 181 } 182 if c.isTargetRecovery() { 183 return "false" 184 } 185 return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenEnforceSyspropOwner()) 186} 187 188func (c *policyConf) enforceDebugfsRestrictions(ctx android.ModuleContext) string { 189 if c.cts() { 190 return "cts" 191 } 192 return strconv.FormatBool(ctx.DeviceConfig().BuildDebugfsRestrictionsEnabled()) 193} 194 195func (c *policyConf) mlsCats() int { 196 return proptools.IntDefault(c.properties.Mls_cats, MlsCats) 197} 198 199func findPolicyConfOrder(name string) int { 200 for idx, pattern := range policyConfOrder { 201 if pattern == name || (pattern == "*.te" && strings.HasSuffix(name, ".te")) { 202 return idx 203 } 204 } 205 // name is not matched 206 return len(policyConfOrder) 207} 208 209func (c *policyConf) transformPolicyToConf(ctx android.ModuleContext) android.OutputPath { 210 conf := android.PathForModuleOut(ctx, c.stem()).OutputPath 211 rule := android.NewRuleBuilder(pctx, ctx) 212 213 srcs := android.PathsForModuleSrc(ctx, c.properties.Srcs) 214 sort.SliceStable(srcs, func(x, y int) bool { 215 return findPolicyConfOrder(srcs[x].Base()) < findPolicyConfOrder(srcs[y].Base()) 216 }) 217 218 rule.Command().Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")). 219 Flag("--fatal-warnings"). 220 FlagForEachArg("-D ", ctx.DeviceConfig().SepolicyM4Defs()). 221 FlagWithArg("-D mls_num_sens=", strconv.Itoa(MlsSens)). 222 FlagWithArg("-D mls_num_cats=", strconv.Itoa(c.mlsCats())). 223 FlagWithArg("-D target_arch=", ctx.DeviceConfig().DeviceArch()). 224 FlagWithArg("-D target_with_asan=", c.withAsan(ctx)). 225 FlagWithArg("-D target_with_dexpreopt=", strconv.FormatBool(ctx.DeviceConfig().WithDexpreopt())). 226 FlagWithArg("-D target_with_native_coverage=", strconv.FormatBool(ctx.DeviceConfig().ClangCoverageEnabled() || ctx.DeviceConfig().GcovCoverageEnabled())). 227 FlagWithArg("-D target_build_variant=", c.buildVariant(ctx)). 228 FlagWithArg("-D target_full_treble=", c.sepolicySplit(ctx)). 229 FlagWithArg("-D target_compatible_property=", c.compatibleProperty(ctx)). 230 FlagWithArg("-D target_treble_sysprop_neverallow=", c.trebleSyspropNeverallow(ctx)). 231 FlagWithArg("-D target_enforce_sysprop_owner=", c.enforceSyspropOwner(ctx)). 232 FlagWithArg("-D target_exclude_build_test=", strconv.FormatBool(proptools.Bool(c.properties.Exclude_build_test))). 233 FlagWithArg("-D target_requires_insecure_execmem_for_swiftshader=", strconv.FormatBool(ctx.DeviceConfig().RequiresInsecureExecmemForSwiftshader())). 234 FlagWithArg("-D target_enforce_debugfs_restriction=", c.enforceDebugfsRestrictions(ctx)). 235 FlagWithArg("-D target_recovery=", strconv.FormatBool(c.isTargetRecovery())). 236 Flag("-s"). 237 Inputs(srcs). 238 Text("> ").Output(conf) 239 240 rule.Build("conf", "Transform policy to conf: "+ctx.ModuleName()) 241 return conf 242} 243 244func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) { 245 // do nothing 246} 247 248func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) { 249 if !c.installable() { 250 c.SkipInstall() 251 } 252 253 c.installSource = c.transformPolicyToConf(ctx) 254 c.installPath = android.PathForModuleInstall(ctx, "etc") 255 ctx.InstallFile(c.installPath, c.stem(), c.installSource) 256} 257 258func (c *policyConf) AndroidMkEntries() []android.AndroidMkEntries { 259 return []android.AndroidMkEntries{android.AndroidMkEntries{ 260 OutputFile: android.OptionalPathForPath(c.installSource), 261 Class: "ETC", 262 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 263 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 264 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.installable()) 265 entries.SetPath("LOCAL_MODULE_PATH", c.installPath) 266 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem()) 267 }, 268 }, 269 }} 270} 271 272func (c *policyConf) OutputFiles(tag string) (android.Paths, error) { 273 if tag == "" { 274 return android.Paths{c.installSource}, nil 275 } 276 return nil, fmt.Errorf("Unknown tag %q", tag) 277} 278 279var _ android.OutputFileProducer = (*policyConf)(nil) 280 281type policyCilProperties struct { 282 // Name of the output. Default is {module_name} 283 Stem *string 284 285 // Policy file to be compiled to cil file. 286 Src *string `android:"path"` 287 288 // Additional cil files to be added in the end of the output. This is to support workarounds 289 // which are not supported by the policy language. 290 Additional_cil_files []string `android:"path"` 291 292 // Cil files to be filtered out by the filter_out tool of "build_sepolicy". Used to build 293 // exported policies 294 Filter_out []string `android:"path"` 295 296 // Whether to remove line markers (denoted by ;;) out of compiled cil files. Defaults to false 297 Remove_line_marker *bool 298 299 // Whether to run secilc to check compiled policy or not. Defaults to true 300 Secilc_check *bool 301 302 // Whether to ignore neverallow when running secilc check. Defaults to 303 // SELINUX_IGNORE_NEVERALLOWS. 304 Ignore_neverallow *bool 305 306 // Whether this module is directly installable to one of the partitions. Default is true 307 Installable *bool 308} 309 310type policyCil struct { 311 android.ModuleBase 312 313 properties policyCilProperties 314 315 installSource android.Path 316 installPath android.InstallPath 317} 318 319// se_policy_cil compiles a policy.conf file to a cil file with checkpolicy, and optionally runs 320// secilc to check the output cil file. Affected by SELINUX_IGNORE_NEVERALLOWS. 321func policyCilFactory() android.Module { 322 c := &policyCil{} 323 c.AddProperties(&c.properties) 324 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon) 325 return c 326} 327 328func (c *policyCil) Installable() bool { 329 return proptools.BoolDefault(c.properties.Installable, true) 330} 331 332func (c *policyCil) stem() string { 333 return proptools.StringDefault(c.properties.Stem, c.Name()) 334} 335 336func (c *policyCil) compileConfToCil(ctx android.ModuleContext, conf android.Path) android.OutputPath { 337 cil := android.PathForModuleOut(ctx, c.stem()).OutputPath 338 rule := android.NewRuleBuilder(pctx, ctx) 339 rule.Command().BuiltTool("checkpolicy"). 340 Flag("-C"). // Write CIL 341 Flag("-M"). // Enable MLS 342 FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 343 FlagWithOutput("-o ", cil). 344 Input(conf) 345 346 if len(c.properties.Additional_cil_files) > 0 { 347 rule.Command().Text("cat"). 348 Inputs(android.PathsForModuleSrc(ctx, c.properties.Additional_cil_files)). 349 Text(">> ").Output(cil) 350 } 351 352 if len(c.properties.Filter_out) > 0 { 353 rule.Command().BuiltTool("build_sepolicy"). 354 Text("filter_out"). 355 Flag("-f"). 356 Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). 357 FlagWithOutput("-t ", cil) 358 } 359 360 if proptools.Bool(c.properties.Remove_line_marker) { 361 rule.Command().Text("grep -v"). 362 Text(proptools.ShellEscape(";;")). 363 Text(cil.String()). 364 Text(">"). 365 Text(cil.String() + ".tmp"). 366 Text("&& mv"). 367 Text(cil.String() + ".tmp"). 368 Text(cil.String()) 369 } 370 371 if proptools.BoolDefault(c.properties.Secilc_check, true) { 372 secilcCmd := rule.Command().BuiltTool("secilc"). 373 Flag("-m"). // Multiple decls 374 FlagWithArg("-M ", "true"). // Enable MLS 375 Flag("-G"). // expand and remove auto generated attributes 376 FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 377 Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). // Also add cil files which are filtered out 378 Text(cil.String()). 379 FlagWithArg("-o ", os.DevNull). 380 FlagWithArg("-f ", os.DevNull) 381 382 if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) { 383 secilcCmd.Flag("-N") 384 } 385 } 386 387 rule.Build("cil", "Building cil for "+ctx.ModuleName()) 388 return cil 389} 390 391func (c *policyCil) GenerateAndroidBuildActions(ctx android.ModuleContext) { 392 if proptools.String(c.properties.Src) == "" { 393 ctx.PropertyErrorf("src", "must be specified") 394 return 395 } 396 conf := android.PathForModuleSrc(ctx, *c.properties.Src) 397 cil := c.compileConfToCil(ctx, conf) 398 399 if !c.Installable() { 400 c.SkipInstall() 401 } 402 403 if c.InstallInDebugRamdisk() { 404 // for userdebug_plat_sepolicy.cil 405 c.installPath = android.PathForModuleInstall(ctx) 406 } else { 407 c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux") 408 } 409 c.installSource = cil 410 ctx.InstallFile(c.installPath, c.stem(), c.installSource) 411} 412 413func (c *policyCil) AndroidMkEntries() []android.AndroidMkEntries { 414 return []android.AndroidMkEntries{android.AndroidMkEntries{ 415 OutputFile: android.OptionalPathForPath(c.installSource), 416 Class: "ETC", 417 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 418 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 419 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable()) 420 entries.SetPath("LOCAL_MODULE_PATH", c.installPath) 421 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem()) 422 }, 423 }, 424 }} 425} 426 427func (c *policyCil) OutputFiles(tag string) (android.Paths, error) { 428 if tag == "" { 429 return android.Paths{c.installSource}, nil 430 } 431 return nil, fmt.Errorf("Unknown tag %q", tag) 432} 433 434var _ android.OutputFileProducer = (*policyCil)(nil) 435 436type policyBinaryProperties struct { 437 // Name of the output. Default is {module_name} 438 Stem *string 439 440 // Cil files to be compiled. 441 Srcs []string `android:"path"` 442 443 // Whether to ignore neverallow when running secilc check. Defaults to 444 // SELINUX_IGNORE_NEVERALLOWS. 445 Ignore_neverallow *bool 446 447 // Whether this module is directly installable to one of the partitions. Default is true 448 Installable *bool 449} 450 451type policyBinary struct { 452 android.ModuleBase 453 454 properties policyBinaryProperties 455 456 installSource android.Path 457 installPath android.InstallPath 458} 459 460// se_policy_binary compiles cil files to a binary sepolicy file with secilc. Usually sources of 461// se_policy_binary come from outputs of se_policy_cil modules. 462func policyBinaryFactory() android.Module { 463 c := &policyBinary{} 464 c.AddProperties(&c.properties) 465 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon) 466 return c 467} 468 469func (c *policyBinary) InstallInRoot() bool { 470 return c.InstallInRecovery() 471} 472 473func (c *policyBinary) Installable() bool { 474 return proptools.BoolDefault(c.properties.Installable, true) 475} 476 477func (c *policyBinary) stem() string { 478 return proptools.StringDefault(c.properties.Stem, c.Name()) 479} 480 481func (c *policyBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) { 482 if len(c.properties.Srcs) == 0 { 483 ctx.PropertyErrorf("srcs", "must be specified") 484 return 485 } 486 bin := android.PathForModuleOut(ctx, c.stem()+"_policy") 487 rule := android.NewRuleBuilder(pctx, ctx) 488 secilcCmd := rule.Command().BuiltTool("secilc"). 489 Flag("-m"). // Multiple decls 490 FlagWithArg("-M ", "true"). // Enable MLS 491 Flag("-G"). // expand and remove auto generated attributes 492 FlagWithArg("-c ", strconv.Itoa(PolicyVers)). 493 Inputs(android.PathsForModuleSrc(ctx, c.properties.Srcs)). 494 FlagWithOutput("-o ", bin). 495 FlagWithArg("-f ", os.DevNull) 496 497 if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) { 498 secilcCmd.Flag("-N") 499 } 500 rule.Temporary(bin) 501 502 // permissive check is performed only in user build (not debuggable). 503 if !ctx.Config().Debuggable() { 504 permissiveDomains := android.PathForModuleOut(ctx, c.stem()+"_permissive") 505 rule.Command().BuiltTool("sepolicy-analyze"). 506 Input(bin). 507 Text("permissive"). 508 Text(" > "). 509 Output(permissiveDomains) 510 rule.Temporary(permissiveDomains) 511 512 msg := `==========\n` + 513 `ERROR: permissive domains not allowed in user builds\n` + 514 `List of invalid domains:` 515 516 rule.Command().Text("if test"). 517 FlagWithInput("-s ", permissiveDomains). 518 Text("; then echo"). 519 Flag("-e"). 520 Text(`"` + msg + `"`). 521 Text("&& cat "). 522 Input(permissiveDomains). 523 Text("; exit 1; fi") 524 } 525 526 out := android.PathForModuleOut(ctx, c.stem()) 527 rule.Command().Text("cp"). 528 Flag("-f"). 529 Input(bin). 530 Output(out) 531 532 rule.DeleteTemporaryFiles() 533 rule.Build("secilc", "Compiling cil files for "+ctx.ModuleName()) 534 535 if !c.Installable() { 536 c.SkipInstall() 537 } 538 539 if c.InstallInRecovery() { 540 // install in root 541 c.installPath = android.PathForModuleInstall(ctx) 542 } else { 543 c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux") 544 } 545 c.installSource = out 546 ctx.InstallFile(c.installPath, c.stem(), c.installSource) 547} 548 549func (c *policyBinary) AndroidMkEntries() []android.AndroidMkEntries { 550 return []android.AndroidMkEntries{android.AndroidMkEntries{ 551 OutputFile: android.OptionalPathForPath(c.installSource), 552 Class: "ETC", 553 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 554 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 555 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable()) 556 entries.SetPath("LOCAL_MODULE_PATH", c.installPath) 557 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem()) 558 }, 559 }, 560 }} 561} 562 563func (c *policyBinary) OutputFiles(tag string) (android.Paths, error) { 564 if tag == "" { 565 return android.Paths{c.installSource}, nil 566 } 567 return nil, fmt.Errorf("Unknown tag %q", tag) 568} 569 570var _ android.OutputFileProducer = (*policyBinary)(nil) 571