1// Copyright 2017 Google Inc. All rights reserved. 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 android 16 17import ( 18 "fmt" 19 "path/filepath" 20 "reflect" 21 "regexp" 22 "strconv" 23 "strings" 24 25 "github.com/google/blueprint/proptools" 26) 27 28// "neverallow" rules for the build system. 29// 30// This allows things which aren't related to the build system and are enforced 31// against assumptions, in progress code refactors, or policy to be expressed in a 32// straightforward away disjoint from implementations and tests which should 33// work regardless of these restrictions. 34// 35// A module is disallowed if all of the following are true: 36// - it is in one of the "In" paths 37// - it is not in one of the "NotIn" paths 38// - it has all "With" properties matched 39// - - values are matched in their entirety 40// - - nil is interpreted as an empty string 41// - - nested properties are separated with a '.' 42// - - if the property is a list, any of the values in the list being matches 43// counts as a match 44// - it has none of the "Without" properties matched (same rules as above) 45 46func registerNeverallowMutator(ctx RegisterMutatorsContext) { 47 ctx.BottomUp("neverallow", neverallowMutator) 48} 49 50var neverallows = []Rule{} 51 52func init() { 53 AddNeverAllowRules(createIncludeDirsRules()...) 54 AddNeverAllowRules(createTrebleRules()...) 55 AddNeverAllowRules(createJavaDeviceForHostRules()...) 56 AddNeverAllowRules(createCcSdkVariantRules()...) 57 AddNeverAllowRules(createUncompressDexRules()...) 58 AddNeverAllowRules(createInstallInRootAllowingRules()...) 59 AddNeverAllowRules(createProhibitFrameworkAccessRules()...) 60 AddNeverAllowRules(createCcStubsRule()) 61 AddNeverAllowRules(createProhibitHeaderOnlyRule()) 62 AddNeverAllowRules(createLimitNdkExportRule()...) 63 AddNeverAllowRules(createLimitDirgroupRules()...) 64 AddNeverAllowRules(createLimitGenruleRules()...) 65 AddNeverAllowRules(createFilesystemIsAutoGeneratedRule()) 66 AddNeverAllowRules(createKotlinPluginRule()...) 67 AddNeverAllowRules(createPrebuiltEtcBpDefineRule()) 68 AddNeverAllowRules(createAutogenRroBpDefineRule()) 69 AddNeverAllowRules(createNoSha1HashRule()) 70} 71 72// Add a NeverAllow rule to the set of rules to apply. 73func AddNeverAllowRules(rules ...Rule) { 74 neverallows = append(neverallows, rules...) 75} 76 77var ( 78 neverallowNotInIncludeDir = []string{ 79 "art", 80 "art/libnativebridge", 81 "art/libnativeloader", 82 "libcore", 83 "libnativehelper", 84 "external/apache-harmony", 85 "external/apache-xml", 86 "external/boringssl", 87 "external/bouncycastle", 88 "external/conscrypt", 89 "external/icu", 90 "external/okhttp", 91 "external/vixl", 92 "external/wycheproof", 93 } 94 neverallowNoUseIncludeDir = []string{ 95 "frameworks/av/apex", 96 "frameworks/av/tools", 97 "frameworks/native/cmds", 98 "system/apex", 99 "system/bpf", 100 "system/gatekeeper", 101 "system/hwservicemanager", 102 "system/libbase", 103 "system/libfmq", 104 "system/libvintf", 105 } 106) 107 108func createIncludeDirsRules() []Rule { 109 rules := make([]Rule, 0, len(neverallowNotInIncludeDir)+len(neverallowNoUseIncludeDir)) 110 111 for _, path := range neverallowNotInIncludeDir { 112 rule := 113 NeverAllow(). 114 WithMatcher("include_dirs", StartsWith(path+"/")). 115 Because("include_dirs is deprecated, all usages of '" + path + "' have been migrated" + 116 " to use alternate mechanisms and so can no longer be used.") 117 118 rules = append(rules, rule) 119 } 120 121 for _, path := range neverallowNoUseIncludeDir { 122 rule := NeverAllow().In(path+"/").WithMatcher("include_dirs", isSetMatcherInstance). 123 Because("include_dirs is deprecated, all usages of them in '" + path + "' have been migrated" + 124 " to use alternate mechanisms and so can no longer be used.") 125 rules = append(rules, rule) 126 } 127 128 return rules 129} 130 131func createTrebleRules() []Rule { 132 return []Rule{ 133 NeverAllow(). 134 In("vendor", "device"). 135 With("vndk.enabled", "true"). 136 Without("vendor", "true"). 137 Without("product_specific", "true"). 138 Because("the VNDK can never contain a library that is device dependent."), 139 NeverAllow(). 140 With("vndk.enabled", "true"). 141 Without("vendor", "true"). 142 Without("owner", ""). 143 Because("a VNDK module can never have an owner."), 144 145 // TODO(b/67974785): always enforce the manifest 146 NeverAllow(). 147 Without("name", "libhidlbase-combined-impl"). 148 Without("name", "libhidlbase"). 149 With("product_variables.enforce_vintf_manifest.cflags", "*"). 150 Because("manifest enforcement should be independent of ."), 151 152 // TODO(b/67975799): vendor code should always use /vendor/bin/sh 153 NeverAllow(). 154 Without("name", "libc_bionic_ndk"). 155 With("product_variables.treble_linker_namespaces.cflags", "*"). 156 Because("nothing should care if linker namespaces are enabled or not"), 157 158 // Example: 159 // *NeverAllow().with("Srcs", "main.cpp")) 160 } 161} 162 163func createJavaDeviceForHostRules() []Rule { 164 javaDeviceForHostProjectsAllowedList := []string{ 165 "development/build", 166 "external/guava", 167 "external/kotlinx.coroutines", 168 "external/robolectric-shadows", 169 "external/robolectric", 170 "frameworks/base/ravenwood", 171 "frameworks/base/tools/hoststubgen", 172 "frameworks/layoutlib", 173 } 174 175 return []Rule{ 176 NeverAllow(). 177 NotIn(javaDeviceForHostProjectsAllowedList...). 178 ModuleType("java_device_for_host", "java_host_for_device"). 179 Because("java_device_for_host can only be used in allowed projects"), 180 } 181} 182 183func createCcSdkVariantRules() []Rule { 184 sdkVersionOnlyAllowedList := []string{ 185 // derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk. 186 // This sometimes works because the APEX modules that contain derive_sdk and 187 // derive_sdk_prefer32 suppress the platform installation rules, but fails when 188 // the APEX modules contain the SDK variant and the platform variant still exists. 189 "packages/modules/SdkExtensions/derive_sdk", 190 // These are for apps and shouldn't be used by non-SDK variant modules. 191 "prebuilts/ndk", 192 "frameworks/native/libs/binder/ndk", 193 "tools/test/graphicsbenchmark/apps/sample_app", 194 "tools/test/graphicsbenchmark/functional_tests/java", 195 "vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests", 196 "external/libtextclassifier/native", 197 } 198 199 platformVariantPropertiesAllowedList := []string{ 200 // android_native_app_glue and libRSSupport use native_window.h but target old 201 // sdk versions (minimum and 9 respectively) where libnativewindow didn't exist, 202 // so they can't add libnativewindow to shared_libs to get the header directory 203 // for the platform variant. Allow them to use the platform variant 204 // property to set shared_libs. 205 "prebuilts/ndk", 206 "frameworks/rs", 207 } 208 209 return []Rule{ 210 NeverAllow(). 211 NotIn(sdkVersionOnlyAllowedList...). 212 WithMatcher("sdk_variant_only", isSetMatcherInstance). 213 Because("sdk_variant_only can only be used in allowed projects"), 214 NeverAllow(). 215 NotIn(platformVariantPropertiesAllowedList...). 216 WithMatcher("platform.shared_libs", isSetMatcherInstance). 217 Because("platform variant properties can only be used in allowed projects"), 218 } 219} 220 221func createCcStubsRule() Rule { 222 ccStubsImplementationInstallableProjectsAllowedList := []string{ 223 "packages/modules/Virtualization/libs/libvm_payload", 224 } 225 226 return NeverAllow(). 227 NotIn(ccStubsImplementationInstallableProjectsAllowedList...). 228 WithMatcher("stubs.implementation_installable", isSetMatcherInstance). 229 Because("implementation_installable can only be used in allowed projects.") 230} 231 232func createUncompressDexRules() []Rule { 233 return []Rule{ 234 NeverAllow(). 235 NotIn("art", "cts/hostsidetests/compilation"). 236 WithMatcher("uncompress_dex", isSetMatcherInstance). 237 Because("uncompress_dex is only allowed for certain jars for test in art."), 238 } 239} 240 241func createInstallInRootAllowingRules() []Rule { 242 return []Rule{ 243 NeverAllow(). 244 Without("name", "init_first_stage_defaults"). 245 Without("name", "init_first_stage"). 246 Without("name", "init_first_stage.microdroid"). 247 Without("name", "librecovery_ui_ext"). 248 With("install_in_root", "true"). 249 NotModuleType("prebuilt_root"). 250 NotModuleType("prebuilt_vendor"). 251 NotModuleType("prebuilt_sbin"). 252 NotModuleType("prebuilt_system"). 253 NotModuleType("prebuilt_first_stage_ramdisk"). 254 NotModuleType("prebuilt_res"). 255 NotModuleType("prebuilt_any"). 256 Because("install_in_root is only for init_first_stage or librecovery_ui_ext."), 257 } 258} 259 260func createProhibitFrameworkAccessRules() []Rule { 261 return []Rule{ 262 NeverAllow(). 263 With("libs", "framework"). 264 WithoutMatcher("sdk_version", Regexp("(core_.*|^$)")). 265 Because("framework can't be used when building against SDK"), 266 } 267} 268 269func createProhibitHeaderOnlyRule() Rule { 270 return NeverAllow(). 271 Without("name", "framework-minus-apex-headers"). 272 With("headers_only", "true"). 273 Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules") 274} 275 276func createLimitNdkExportRule() []Rule { 277 reason := "If the headers you're trying to export are meant to be a part of the NDK, they should be exposed by an ndk_headers module. If the headers shouldn't be a part of the NDK, the headers should instead be exposed from a separate `cc_library_headers` which consumers depend on." 278 // DO NOT ADD HERE - please consult danalbert@ 279 // b/357711733 280 return []Rule{ 281 NeverAllow(). 282 NotIn("frameworks/native/libs/binder/ndk"). 283 ModuleType("ndk_library"). 284 WithMatcher("export_header_libs", isSetMatcherInstance).Because(reason), 285 NeverAllow().ModuleType("ndk_library").WithMatcher("export_generated_headers", isSetMatcherInstance).Because(reason), 286 NeverAllow().ModuleType("ndk_library").WithMatcher("export_include_dirs", isSetMatcherInstance).Because(reason), 287 NeverAllow().ModuleType("ndk_library").WithMatcher("export_shared_lib_headers", isSetMatcherInstance).Because(reason), 288 NeverAllow().ModuleType("ndk_library").WithMatcher("export_static_lib_headers", isSetMatcherInstance).Because(reason), 289 } 290} 291 292func createLimitDirgroupRules() []Rule { 293 reason := "The dirgroup module can only be used with Trusty visibility" 294 scriptsDirsList := []string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"} 295 return []Rule{ 296 NeverAllow(). 297 ModuleType("dirgroup"). 298 WithMatcher("visibility", NotInList(scriptsDirsList)).Because(reason), 299 NeverAllow(). 300 ModuleType("dirgroup"). 301 WithoutMatcher("visibility", InAllowedList(scriptsDirsList)).Because(reason), 302 } 303} 304 305func createLimitGenruleRules() []Rule { 306 dirSrcsReason := "The `dir_srcs` property in a `genrule` module can only be used by Trusty" 307 keepGendirReason := "The `keep_gendir` property in a `genrule` module can only be used by Trusty" 308 allowedModuleNameList := []string{ 309 // Trusty TEE target names 310 "trusty_tee_package_goog", 311 "trusty_tee_package", 312 // Trusty vm target names 313 "trusty_desktop_vm_arm64.bin", 314 "trusty_desktop_vm_x86_64.bin", 315 "trusty_desktop_test_vm_arm64.bin", 316 "trusty_desktop_test_vm_x86_64.bin", 317 "trusty_test_vm_arm64.bin", 318 "trusty_test_vm_x86_64.elf", 319 "trusty_test_vm_os_arm64.bin", 320 "trusty_test_vm_os_x86_64.elf", 321 "trusty_security_vm_arm64.bin", 322 "trusty_security_vm_x86_64.elf", 323 "trusty_widevine_vm_arm64.bin", 324 "trusty_widevine_vm_x86_64.elf", 325 } 326 return []Rule{ 327 NeverAllow(). 328 ModuleType("genrule"). 329 WithoutMatcher("name", InAllowedList(allowedModuleNameList)). 330 WithMatcher("dir_srcs", isSetMatcherInstance).Because(dirSrcsReason), 331 NeverAllow(). 332 ModuleType("genrule"). 333 WithoutMatcher("name", InAllowedList(allowedModuleNameList)). 334 With("keep_gendir", "true").Because(keepGendirReason), 335 } 336} 337 338func createFilesystemIsAutoGeneratedRule() Rule { 339 return NeverAllow(). 340 NotIn("build/soong/fsgen"). 341 ModuleType("filesystem", "android_system_image"). 342 WithMatcher("is_auto_generated", isSetMatcherInstance). 343 Because("is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory") 344} 345 346func createNoSha1HashRule() Rule { 347 return NeverAllow(). 348 ModuleType("filesystem", "android_filesystem"). 349 ModuleType("filesystem", "android_system_image"). 350 With("avb_hash_algorithm", "sha1"). 351 Because("sha1 is discouraged") 352} 353 354func createKotlinPluginRule() []Rule { 355 kotlinPluginProjectsAllowedList := []string{ 356 "external/kotlinc", 357 } 358 359 return []Rule{ 360 NeverAllow(). 361 NotIn(kotlinPluginProjectsAllowedList...). 362 ModuleType("kotlin_plugin"). 363 Because("kotlin_plugin can only be used in allowed projects"), 364 } 365} 366 367// These module types are introduced to convert PRODUCT_COPY_FILES to Soong, 368// and is only intended to be used by filesystem_creator. 369func createPrebuiltEtcBpDefineRule() Rule { 370 return NeverAllow(). 371 ModuleType( 372 "prebuilt_any", 373 "prebuilt_usr_srec", 374 "prebuilt_priv_app", 375 "prebuilt_rfs", 376 "prebuilt_framework", 377 "prebuilt_wlc_upt", 378 "prebuilt_odm", 379 "prebuilt_vendor_dlkm", 380 "prebuilt_bt_firmware", 381 "prebuilt_tvservice", 382 "prebuilt_optee", 383 "prebuilt_tvconfig", 384 "prebuilt_vendor", 385 "prebuilt_sbin", 386 "prebuilt_system", 387 "prebuilt_first_stage_ramdisk", 388 "prebuilt_radio", 389 "prebuilt_gpu", 390 "prebuilt_vendor_overlay", 391 "prebuilt_tee", 392 ). 393 DefinedInBpFile(). 394 Because("module type not allowed to be defined in bp file") 395} 396 397func createAutogenRroBpDefineRule() Rule { 398 return NeverAllow(). 399 ModuleType( 400 "autogen_runtime_resource_overlay", 401 ). 402 DefinedInBpFile(). 403 Because("Module type will be autogenerated by soong. Use runtime_resource_overlay instead") 404} 405 406func neverallowMutator(ctx BottomUpMutatorContext) { 407 m, ok := ctx.Module().(Module) 408 if !ok { 409 return 410 } 411 412 dir := ctx.ModuleDir() + "/" 413 properties := m.GetProperties() 414 415 osClass := ctx.Module().Target().Os.Class 416 417 for _, r := range neverallowRules(ctx.Config()) { 418 n := r.(*rule) 419 if !n.appliesToPath(dir) { 420 continue 421 } 422 423 modType := proptools.StringDefault(m.base().baseProperties.Soong_config_base_module_type, ctx.ModuleType()) 424 if !n.appliesToModuleType(modType) { 425 continue 426 } 427 428 if !n.appliesToProperties(ctx, properties) { 429 continue 430 } 431 432 if !n.appliesToOsClass(osClass) { 433 continue 434 } 435 436 if !n.appliesToDirectDeps(ctx) { 437 continue 438 } 439 440 if !n.appliesToBpDefinedModule(ctx) { 441 continue 442 } 443 444 ctx.ModuleErrorf("violates " + n.String()) 445 } 446} 447 448type ValueMatcher interface { 449 Test(string) bool 450 String() string 451} 452 453type equalMatcher struct { 454 expected string 455} 456 457func (m *equalMatcher) Test(value string) bool { 458 return m.expected == value 459} 460 461func (m *equalMatcher) String() string { 462 return "=" + m.expected 463} 464 465type anyMatcher struct { 466} 467 468func (m *anyMatcher) Test(value string) bool { 469 return true 470} 471 472func (m *anyMatcher) String() string { 473 return "=*" 474} 475 476var anyMatcherInstance = &anyMatcher{} 477 478type startsWithMatcher struct { 479 prefix string 480} 481 482func (m *startsWithMatcher) Test(value string) bool { 483 return strings.HasPrefix(value, m.prefix) 484} 485 486func (m *startsWithMatcher) String() string { 487 return ".starts-with(" + m.prefix + ")" 488} 489 490type regexMatcher struct { 491 re *regexp.Regexp 492} 493 494func (m *regexMatcher) Test(value string) bool { 495 return m.re.MatchString(value) 496} 497 498func (m *regexMatcher) String() string { 499 return ".regexp(" + m.re.String() + ")" 500} 501 502type notInListMatcher struct { 503 allowed []string 504} 505 506func (m *notInListMatcher) Test(value string) bool { 507 return !InList(value, m.allowed) 508} 509 510func (m *notInListMatcher) String() string { 511 return ".not-in-list(" + strings.Join(m.allowed, ",") + ")" 512} 513 514type InListMatcher struct { 515 allowed []string 516} 517 518func (m *InListMatcher) Test(value string) bool { 519 return InList(value, m.allowed) 520} 521 522func (m *InListMatcher) String() string { 523 return ".in-list(" + strings.Join(m.allowed, ",") + ")" 524} 525 526type isSetMatcher struct{} 527 528func (m *isSetMatcher) Test(value string) bool { 529 return value != "" 530} 531 532func (m *isSetMatcher) String() string { 533 return ".is-set" 534} 535 536var isSetMatcherInstance = &isSetMatcher{} 537 538type ruleProperty struct { 539 fields []string // e.x.: Vndk.Enabled 540 matcher ValueMatcher 541} 542 543func (r *ruleProperty) String() string { 544 return fmt.Sprintf("%q matches: %s", strings.Join(r.fields, "."), r.matcher) 545} 546 547type ruleProperties []ruleProperty 548 549func (r ruleProperties) String() string { 550 var s []string 551 for _, r := range r { 552 s = append(s, r.String()) 553 } 554 return strings.Join(s, " ") 555} 556 557// A NeverAllow rule. 558type Rule interface { 559 In(path ...string) Rule 560 561 NotIn(path ...string) Rule 562 563 InDirectDeps(deps ...string) Rule 564 565 WithOsClass(osClasses ...OsClass) Rule 566 567 ModuleType(types ...string) Rule 568 569 NotModuleType(types ...string) Rule 570 571 With(properties, value string) Rule 572 573 WithMatcher(properties string, matcher ValueMatcher) Rule 574 575 Without(properties, value string) Rule 576 577 WithoutMatcher(properties string, matcher ValueMatcher) Rule 578 579 DefinedInBpFile() Rule 580 581 Because(reason string) Rule 582} 583 584type rule struct { 585 // User string for why this is a thing. 586 reason string 587 588 paths []string 589 unlessPaths []string 590 591 directDeps map[string]bool 592 593 osClasses []OsClass 594 595 moduleTypes []string 596 unlessModuleTypes []string 597 598 props ruleProperties 599 unlessProps ruleProperties 600 601 onlyBootclasspathJar bool 602 603 definedInBp bool 604} 605 606// Create a new NeverAllow rule. 607func NeverAllow() Rule { 608 return &rule{directDeps: make(map[string]bool)} 609} 610 611// In adds path(s) where this rule applies. 612func (r *rule) In(path ...string) Rule { 613 r.paths = append(r.paths, cleanPaths(path)...) 614 return r 615} 616 617// NotIn adds path(s) to that this rule does not apply to. 618func (r *rule) NotIn(path ...string) Rule { 619 r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...) 620 return r 621} 622 623// InDirectDeps adds dep(s) that are not allowed with this rule. 624func (r *rule) InDirectDeps(deps ...string) Rule { 625 for _, d := range deps { 626 r.directDeps[d] = true 627 } 628 return r 629} 630 631// WithOsClass adds osClass(es) that this rule applies to. 632func (r *rule) WithOsClass(osClasses ...OsClass) Rule { 633 r.osClasses = append(r.osClasses, osClasses...) 634 return r 635} 636 637// ModuleType adds type(s) that this rule applies to. 638func (r *rule) ModuleType(types ...string) Rule { 639 r.moduleTypes = append(r.moduleTypes, types...) 640 return r 641} 642 643// NotModuleType adds type(s) that this rule does not apply to.. 644func (r *rule) NotModuleType(types ...string) Rule { 645 r.unlessModuleTypes = append(r.unlessModuleTypes, types...) 646 return r 647} 648 649// With specifies property/value combinations that are restricted for this rule. 650func (r *rule) With(properties, value string) Rule { 651 return r.WithMatcher(properties, selectMatcher(value)) 652} 653 654// WithMatcher specifies property/matcher combinations that are restricted for this rule. 655func (r *rule) WithMatcher(properties string, matcher ValueMatcher) Rule { 656 r.props = append(r.props, ruleProperty{ 657 fields: fieldNamesForProperties(properties), 658 matcher: matcher, 659 }) 660 return r 661} 662 663// Without specifies property/value combinations that this rule does not apply to. 664func (r *rule) Without(properties, value string) Rule { 665 return r.WithoutMatcher(properties, selectMatcher(value)) 666} 667 668// Without specifies property/matcher combinations that this rule does not apply to. 669func (r *rule) WithoutMatcher(properties string, matcher ValueMatcher) Rule { 670 r.unlessProps = append(r.unlessProps, ruleProperty{ 671 fields: fieldNamesForProperties(properties), 672 matcher: matcher, 673 }) 674 return r 675} 676 677// DefinedInBpFile specifies that this rule applies to modules that are defined 678// in bp files, and does not apply to modules that are auto generated by other modules. 679func (r *rule) DefinedInBpFile() Rule { 680 r.definedInBp = true 681 return r 682} 683 684func selectMatcher(expected string) ValueMatcher { 685 if expected == "*" { 686 return anyMatcherInstance 687 } 688 return &equalMatcher{expected: expected} 689} 690 691// Because specifies a reason for this rule. 692func (r *rule) Because(reason string) Rule { 693 r.reason = reason 694 return r 695} 696 697func (r *rule) String() string { 698 s := []string{"neverallow requirements. Not allowed:"} 699 if len(r.paths) > 0 { 700 s = append(s, fmt.Sprintf("in dirs: %q", r.paths)) 701 } 702 if len(r.moduleTypes) > 0 { 703 s = append(s, fmt.Sprintf("module types: %q", r.moduleTypes)) 704 } 705 if len(r.props) > 0 { 706 s = append(s, fmt.Sprintf("properties matching: %s", r.props)) 707 } 708 if len(r.directDeps) > 0 { 709 s = append(s, fmt.Sprintf("dep(s): %q", SortedKeys(r.directDeps))) 710 } 711 if len(r.osClasses) > 0 { 712 s = append(s, fmt.Sprintf("os class(es): %q", r.osClasses)) 713 } 714 if len(r.unlessPaths) > 0 { 715 s = append(s, fmt.Sprintf("EXCEPT in dirs: %q", r.unlessPaths)) 716 } 717 if len(r.unlessModuleTypes) > 0 { 718 s = append(s, fmt.Sprintf("EXCEPT module types: %q", r.unlessModuleTypes)) 719 } 720 if len(r.unlessProps) > 0 { 721 s = append(s, fmt.Sprintf("EXCEPT properties matching: %q", r.unlessProps)) 722 } 723 if len(r.reason) != 0 { 724 s = append(s, " which is restricted because "+r.reason) 725 } 726 if len(s) == 1 { 727 s[0] = "neverallow requirements (empty)" 728 } 729 return strings.Join(s, "\n\t") 730} 731 732func (r *rule) appliesToPath(dir string) bool { 733 includePath := len(r.paths) == 0 || HasAnyPrefix(dir, r.paths) 734 excludePath := HasAnyPrefix(dir, r.unlessPaths) 735 return includePath && !excludePath 736} 737 738func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool { 739 if len(r.directDeps) == 0 { 740 return true 741 } 742 743 matches := false 744 ctx.VisitDirectDeps(func(m Module) { 745 if !matches { 746 name := ctx.OtherModuleName(m) 747 matches = r.directDeps[name] 748 } 749 }) 750 751 return matches 752} 753 754func (r *rule) appliesToOsClass(osClass OsClass) bool { 755 if len(r.osClasses) == 0 { 756 return true 757 } 758 759 for _, c := range r.osClasses { 760 if c == osClass { 761 return true 762 } 763 } 764 765 return false 766} 767 768func (r *rule) appliesToModuleType(moduleType string) bool { 769 // Remove prefix for auto-generated modules 770 moduleType = strings.TrimSuffix(moduleType, "__loadHookModule") 771 moduleType = strings.TrimSuffix(moduleType, "__bottomUpMutatorModule") 772 return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes) 773} 774 775func (r *rule) appliesToProperties(ctx BottomUpMutatorContext, properties []interface{}) bool { 776 includeProps := hasAllProperties(ctx, properties, r.props) 777 excludeProps := hasAnyProperty(ctx, properties, r.unlessProps) 778 return includeProps && !excludeProps 779} 780 781func (r *rule) appliesToBpDefinedModule(ctx BottomUpMutatorContext) bool { 782 if !r.definedInBp { 783 return true 784 } 785 return !ctx.OtherModuleIsAutoGenerated(ctx.Module()) == r.definedInBp 786} 787 788func StartsWith(prefix string) ValueMatcher { 789 return &startsWithMatcher{prefix} 790} 791 792func Regexp(re string) ValueMatcher { 793 r, err := regexp.Compile(re) 794 if err != nil { 795 panic(err) 796 } 797 return ®exMatcher{r} 798} 799 800func NotInList(allowed []string) ValueMatcher { 801 return ¬InListMatcher{allowed} 802} 803 804func InAllowedList(allowed []string) ValueMatcher { 805 return &InListMatcher{allowed} 806} 807 808// assorted utils 809 810func cleanPaths(paths []string) []string { 811 res := make([]string, len(paths)) 812 for i, v := range paths { 813 res[i] = filepath.Clean(v) + "/" 814 } 815 return res 816} 817 818func fieldNamesForProperties(propertyNames string) []string { 819 names := strings.Split(propertyNames, ".") 820 for i, v := range names { 821 names[i] = proptools.FieldNameForProperty(v) 822 } 823 return names 824} 825 826func hasAnyProperty(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool { 827 for _, v := range props { 828 if hasProperty(ctx, properties, v) { 829 return true 830 } 831 } 832 return false 833} 834 835func hasAllProperties(ctx BottomUpMutatorContext, properties []interface{}, props []ruleProperty) bool { 836 for _, v := range props { 837 if !hasProperty(ctx, properties, v) { 838 return false 839 } 840 } 841 return true 842} 843 844func hasProperty(ctx BottomUpMutatorContext, properties []interface{}, prop ruleProperty) bool { 845 for _, propertyStruct := range properties { 846 propertiesValue := reflect.ValueOf(propertyStruct).Elem() 847 for _, v := range prop.fields { 848 if !propertiesValue.IsValid() { 849 break 850 } 851 propertiesValue = propertiesValue.FieldByName(v) 852 } 853 if !propertiesValue.IsValid() { 854 continue 855 } 856 857 check := func(value string) bool { 858 return prop.matcher.Test(value) 859 } 860 861 if matchValue(ctx, propertiesValue, check) { 862 return true 863 } 864 } 865 return false 866} 867 868func matchValue(ctx BottomUpMutatorContext, value reflect.Value, check func(string) bool) bool { 869 if !value.IsValid() { 870 return false 871 } 872 873 if value.Kind() == reflect.Ptr { 874 if value.IsNil() { 875 return check("") 876 } 877 value = value.Elem() 878 } 879 880 switch v := value.Interface().(type) { 881 case string: 882 return check(v) 883 case bool: 884 return check(strconv.FormatBool(v)) 885 case int: 886 return check(strconv.FormatInt((int64)(v), 10)) 887 case []string: 888 for _, v := range v { 889 if check(v) { 890 return true 891 } 892 } 893 return false 894 case proptools.Configurable[string]: 895 return check(v.GetOrDefault(ctx, "")) 896 case proptools.Configurable[bool]: 897 return check(strconv.FormatBool(v.GetOrDefault(ctx, false))) 898 case proptools.Configurable[[]string]: 899 for _, v := range v.GetOrDefault(ctx, nil) { 900 if check(v) { 901 return true 902 } 903 } 904 return false 905 } 906 907 panic("Can't handle type: " + value.Kind().String()) 908} 909 910var neverallowRulesKey = NewOnceKey("neverallowRules") 911 912func neverallowRules(config Config) []Rule { 913 return config.Once(neverallowRulesKey, func() interface{} { 914 // No test rules were set by setTestNeverallowRules, use the global rules 915 return neverallows 916 }).([]Rule) 917} 918 919// Overrides the default neverallow rules for the supplied config. 920// 921// For testing only. 922func setTestNeverallowRules(config Config, testRules []Rule) { 923 config.Once(neverallowRulesKey, func() interface{} { return testRules }) 924} 925 926// Prepares for a test by setting neverallow rules and enabling the mutator. 927// 928// If the supplied rules are nil then the default rules are used. 929func PrepareForTestWithNeverallowRules(testRules []Rule) FixturePreparer { 930 return GroupFixturePreparers( 931 FixtureModifyConfig(func(config Config) { 932 if testRules != nil { 933 setTestNeverallowRules(config, testRules) 934 } 935 }), 936 FixtureRegisterWithContext(func(ctx RegistrationContext) { 937 ctx.PostDepsMutators(registerNeverallowMutator) 938 }), 939 ) 940} 941