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).Parallel() 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(createMakefileGoalRules()...) 59 AddNeverAllowRules(createInitFirstStageRules()...) 60 AddNeverAllowRules(createProhibitFrameworkAccessRules()...) 61} 62 63// Add a NeverAllow rule to the set of rules to apply. 64func AddNeverAllowRules(rules ...Rule) { 65 neverallows = append(neverallows, rules...) 66} 67 68func createIncludeDirsRules() []Rule { 69 notInIncludeDir := []string{ 70 "art", 71 "art/libnativebridge", 72 "art/libnativeloader", 73 "libcore", 74 "libnativehelper", 75 "external/apache-harmony", 76 "external/apache-xml", 77 "external/boringssl", 78 "external/bouncycastle", 79 "external/conscrypt", 80 "external/icu", 81 "external/okhttp", 82 "external/vixl", 83 "external/wycheproof", 84 } 85 noUseIncludeDir := []string{ 86 "frameworks/av/apex", 87 "frameworks/av/tools", 88 "frameworks/native/cmds", 89 "system/apex", 90 "system/bpf", 91 "system/gatekeeper", 92 "system/hwservicemanager", 93 "system/libbase", 94 "system/libfmq", 95 "system/libvintf", 96 } 97 98 rules := make([]Rule, 0, len(notInIncludeDir)+len(noUseIncludeDir)) 99 100 for _, path := range notInIncludeDir { 101 rule := 102 NeverAllow(). 103 WithMatcher("include_dirs", StartsWith(path+"/")). 104 Because("include_dirs is deprecated, all usages of '" + path + "' have been migrated" + 105 " to use alternate mechanisms and so can no longer be used.") 106 107 rules = append(rules, rule) 108 } 109 110 for _, path := range noUseIncludeDir { 111 rule := NeverAllow().In(path+"/").WithMatcher("include_dirs", isSetMatcherInstance). 112 Because("include_dirs is deprecated, all usages of them in '" + path + "' have been migrated" + 113 " to use alternate mechanisms and so can no longer be used.") 114 rules = append(rules, rule) 115 } 116 117 return rules 118} 119 120func createTrebleRules() []Rule { 121 return []Rule{ 122 NeverAllow(). 123 In("vendor", "device"). 124 With("vndk.enabled", "true"). 125 Without("vendor", "true"). 126 Without("product_specific", "true"). 127 Because("the VNDK can never contain a library that is device dependent."), 128 NeverAllow(). 129 With("vndk.enabled", "true"). 130 Without("vendor", "true"). 131 Without("owner", ""). 132 Because("a VNDK module can never have an owner."), 133 134 // TODO(b/67974785): always enforce the manifest 135 NeverAllow(). 136 Without("name", "libhidlbase-combined-impl"). 137 Without("name", "libhidlbase"). 138 With("product_variables.enforce_vintf_manifest.cflags", "*"). 139 Because("manifest enforcement should be independent of ."), 140 141 // TODO(b/67975799): vendor code should always use /vendor/bin/sh 142 NeverAllow(). 143 Without("name", "libc_bionic_ndk"). 144 With("product_variables.treble_linker_namespaces.cflags", "*"). 145 Because("nothing should care if linker namespaces are enabled or not"), 146 147 // Example: 148 // *NeverAllow().with("Srcs", "main.cpp")) 149 } 150} 151 152func createJavaDeviceForHostRules() []Rule { 153 javaDeviceForHostProjectsAllowedList := []string{ 154 "development/build", 155 "external/guava", 156 "external/kotlinx.coroutines", 157 "external/robolectric-shadows", 158 "external/robolectric", 159 "frameworks/layoutlib", 160 } 161 162 return []Rule{ 163 NeverAllow(). 164 NotIn(javaDeviceForHostProjectsAllowedList...). 165 ModuleType("java_device_for_host", "java_host_for_device"). 166 Because("java_device_for_host can only be used in allowed projects"), 167 } 168} 169 170func createCcSdkVariantRules() []Rule { 171 sdkVersionOnlyAllowedList := []string{ 172 // derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk. 173 // This sometimes works because the APEX modules that contain derive_sdk and 174 // derive_sdk_prefer32 suppress the platform installation rules, but fails when 175 // the APEX modules contain the SDK variant and the platform variant still exists. 176 "packages/modules/SdkExtensions/derive_sdk", 177 // These are for apps and shouldn't be used by non-SDK variant modules. 178 "prebuilts/ndk", 179 "tools/test/graphicsbenchmark/apps/sample_app", 180 "tools/test/graphicsbenchmark/functional_tests/java", 181 "vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests", 182 "external/libtextclassifier/native", 183 } 184 185 platformVariantPropertiesAllowedList := []string{ 186 // android_native_app_glue and libRSSupport use native_window.h but target old 187 // sdk versions (minimum and 9 respectively) where libnativewindow didn't exist, 188 // so they can't add libnativewindow to shared_libs to get the header directory 189 // for the platform variant. Allow them to use the platform variant 190 // property to set shared_libs. 191 "prebuilts/ndk", 192 "frameworks/rs", 193 } 194 195 return []Rule{ 196 NeverAllow(). 197 NotIn(sdkVersionOnlyAllowedList...). 198 WithMatcher("sdk_variant_only", isSetMatcherInstance). 199 Because("sdk_variant_only can only be used in allowed projects"), 200 NeverAllow(). 201 NotIn(platformVariantPropertiesAllowedList...). 202 WithMatcher("platform.shared_libs", isSetMatcherInstance). 203 Because("platform variant properties can only be used in allowed projects"), 204 } 205} 206 207func createUncompressDexRules() []Rule { 208 return []Rule{ 209 NeverAllow(). 210 NotIn("art"). 211 WithMatcher("uncompress_dex", isSetMatcherInstance). 212 Because("uncompress_dex is only allowed for certain jars for test in art."), 213 } 214} 215 216func createMakefileGoalRules() []Rule { 217 return []Rule{ 218 NeverAllow(). 219 ModuleType("makefile_goal"). 220 WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")). 221 Because("Only boot images may be imported as a makefile goal."), 222 } 223} 224 225func createInitFirstStageRules() []Rule { 226 return []Rule{ 227 NeverAllow(). 228 Without("name", "init_first_stage"). 229 With("install_in_root", "true"). 230 Because("install_in_root is only for init_first_stage."), 231 } 232} 233 234func createProhibitFrameworkAccessRules() []Rule { 235 return []Rule{ 236 NeverAllow(). 237 With("libs", "framework"). 238 WithoutMatcher("sdk_version", Regexp("(core_.*|^$)")). 239 Because("framework can't be used when building against SDK"), 240 } 241} 242 243func neverallowMutator(ctx BottomUpMutatorContext) { 244 m, ok := ctx.Module().(Module) 245 if !ok { 246 return 247 } 248 249 dir := ctx.ModuleDir() + "/" 250 properties := m.GetProperties() 251 252 osClass := ctx.Module().Target().Os.Class 253 254 for _, r := range neverallowRules(ctx.Config()) { 255 n := r.(*rule) 256 if !n.appliesToPath(dir) { 257 continue 258 } 259 260 if !n.appliesToModuleType(ctx.ModuleType()) { 261 continue 262 } 263 264 if !n.appliesToProperties(properties) { 265 continue 266 } 267 268 if !n.appliesToOsClass(osClass) { 269 continue 270 } 271 272 if !n.appliesToDirectDeps(ctx) { 273 continue 274 } 275 276 ctx.ModuleErrorf("violates " + n.String()) 277 } 278} 279 280type ValueMatcher interface { 281 Test(string) bool 282 String() string 283} 284 285type equalMatcher struct { 286 expected string 287} 288 289func (m *equalMatcher) Test(value string) bool { 290 return m.expected == value 291} 292 293func (m *equalMatcher) String() string { 294 return "=" + m.expected 295} 296 297type anyMatcher struct { 298} 299 300func (m *anyMatcher) Test(value string) bool { 301 return true 302} 303 304func (m *anyMatcher) String() string { 305 return "=*" 306} 307 308var anyMatcherInstance = &anyMatcher{} 309 310type startsWithMatcher struct { 311 prefix string 312} 313 314func (m *startsWithMatcher) Test(value string) bool { 315 return strings.HasPrefix(value, m.prefix) 316} 317 318func (m *startsWithMatcher) String() string { 319 return ".starts-with(" + m.prefix + ")" 320} 321 322type regexMatcher struct { 323 re *regexp.Regexp 324} 325 326func (m *regexMatcher) Test(value string) bool { 327 return m.re.MatchString(value) 328} 329 330func (m *regexMatcher) String() string { 331 return ".regexp(" + m.re.String() + ")" 332} 333 334type notInListMatcher struct { 335 allowed []string 336} 337 338func (m *notInListMatcher) Test(value string) bool { 339 return !InList(value, m.allowed) 340} 341 342func (m *notInListMatcher) String() string { 343 return ".not-in-list(" + strings.Join(m.allowed, ",") + ")" 344} 345 346type isSetMatcher struct{} 347 348func (m *isSetMatcher) Test(value string) bool { 349 return value != "" 350} 351 352func (m *isSetMatcher) String() string { 353 return ".is-set" 354} 355 356var isSetMatcherInstance = &isSetMatcher{} 357 358type ruleProperty struct { 359 fields []string // e.x.: Vndk.Enabled 360 matcher ValueMatcher 361} 362 363func (r *ruleProperty) String() string { 364 return fmt.Sprintf("%q matches: %s", strings.Join(r.fields, "."), r.matcher) 365} 366 367type ruleProperties []ruleProperty 368 369func (r ruleProperties) String() string { 370 var s []string 371 for _, r := range r { 372 s = append(s, r.String()) 373 } 374 return strings.Join(s, " ") 375} 376 377// A NeverAllow rule. 378type Rule interface { 379 In(path ...string) Rule 380 381 NotIn(path ...string) Rule 382 383 InDirectDeps(deps ...string) Rule 384 385 WithOsClass(osClasses ...OsClass) Rule 386 387 ModuleType(types ...string) Rule 388 389 NotModuleType(types ...string) Rule 390 391 With(properties, value string) Rule 392 393 WithMatcher(properties string, matcher ValueMatcher) Rule 394 395 Without(properties, value string) Rule 396 397 WithoutMatcher(properties string, matcher ValueMatcher) Rule 398 399 Because(reason string) Rule 400} 401 402type rule struct { 403 // User string for why this is a thing. 404 reason string 405 406 paths []string 407 unlessPaths []string 408 409 directDeps map[string]bool 410 411 osClasses []OsClass 412 413 moduleTypes []string 414 unlessModuleTypes []string 415 416 props ruleProperties 417 unlessProps ruleProperties 418 419 onlyBootclasspathJar bool 420} 421 422// Create a new NeverAllow rule. 423func NeverAllow() Rule { 424 return &rule{directDeps: make(map[string]bool)} 425} 426 427// In adds path(s) where this rule applies. 428func (r *rule) In(path ...string) Rule { 429 r.paths = append(r.paths, cleanPaths(path)...) 430 return r 431} 432 433// NotIn adds path(s) to that this rule does not apply to. 434func (r *rule) NotIn(path ...string) Rule { 435 r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...) 436 return r 437} 438 439// InDirectDeps adds dep(s) that are not allowed with this rule. 440func (r *rule) InDirectDeps(deps ...string) Rule { 441 for _, d := range deps { 442 r.directDeps[d] = true 443 } 444 return r 445} 446 447// WithOsClass adds osClass(es) that this rule applies to. 448func (r *rule) WithOsClass(osClasses ...OsClass) Rule { 449 r.osClasses = append(r.osClasses, osClasses...) 450 return r 451} 452 453// ModuleType adds type(s) that this rule applies to. 454func (r *rule) ModuleType(types ...string) Rule { 455 r.moduleTypes = append(r.moduleTypes, types...) 456 return r 457} 458 459// NotModuleType adds type(s) that this rule does not apply to.. 460func (r *rule) NotModuleType(types ...string) Rule { 461 r.unlessModuleTypes = append(r.unlessModuleTypes, types...) 462 return r 463} 464 465// With specifies property/value combinations that are restricted for this rule. 466func (r *rule) With(properties, value string) Rule { 467 return r.WithMatcher(properties, selectMatcher(value)) 468} 469 470// WithMatcher specifies property/matcher combinations that are restricted for this rule. 471func (r *rule) WithMatcher(properties string, matcher ValueMatcher) Rule { 472 r.props = append(r.props, ruleProperty{ 473 fields: fieldNamesForProperties(properties), 474 matcher: matcher, 475 }) 476 return r 477} 478 479// Without specifies property/value combinations that this rule does not apply to. 480func (r *rule) Without(properties, value string) Rule { 481 return r.WithoutMatcher(properties, selectMatcher(value)) 482} 483 484// Without specifies property/matcher combinations that this rule does not apply to. 485func (r *rule) WithoutMatcher(properties string, matcher ValueMatcher) Rule { 486 r.unlessProps = append(r.unlessProps, ruleProperty{ 487 fields: fieldNamesForProperties(properties), 488 matcher: matcher, 489 }) 490 return r 491} 492 493func selectMatcher(expected string) ValueMatcher { 494 if expected == "*" { 495 return anyMatcherInstance 496 } 497 return &equalMatcher{expected: expected} 498} 499 500// Because specifies a reason for this rule. 501func (r *rule) Because(reason string) Rule { 502 r.reason = reason 503 return r 504} 505 506func (r *rule) String() string { 507 s := []string{"neverallow requirements. Not allowed:"} 508 if len(r.paths) > 0 { 509 s = append(s, fmt.Sprintf("in dirs: %q", r.paths)) 510 } 511 if len(r.moduleTypes) > 0 { 512 s = append(s, fmt.Sprintf("module types: %q", r.moduleTypes)) 513 } 514 if len(r.props) > 0 { 515 s = append(s, fmt.Sprintf("properties matching: %s", r.props)) 516 } 517 if len(r.directDeps) > 0 { 518 s = append(s, fmt.Sprintf("dep(s): %q", SortedStringKeys(r.directDeps))) 519 } 520 if len(r.osClasses) > 0 { 521 s = append(s, fmt.Sprintf("os class(es): %q", r.osClasses)) 522 } 523 if len(r.unlessPaths) > 0 { 524 s = append(s, fmt.Sprintf("EXCEPT in dirs: %q", r.unlessPaths)) 525 } 526 if len(r.unlessModuleTypes) > 0 { 527 s = append(s, fmt.Sprintf("EXCEPT module types: %q", r.unlessModuleTypes)) 528 } 529 if len(r.unlessProps) > 0 { 530 s = append(s, fmt.Sprintf("EXCEPT properties matching: %q", r.unlessProps)) 531 } 532 if len(r.reason) != 0 { 533 s = append(s, " which is restricted because "+r.reason) 534 } 535 if len(s) == 1 { 536 s[0] = "neverallow requirements (empty)" 537 } 538 return strings.Join(s, "\n\t") 539} 540 541func (r *rule) appliesToPath(dir string) bool { 542 includePath := len(r.paths) == 0 || HasAnyPrefix(dir, r.paths) 543 excludePath := HasAnyPrefix(dir, r.unlessPaths) 544 return includePath && !excludePath 545} 546 547func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool { 548 if len(r.directDeps) == 0 { 549 return true 550 } 551 552 matches := false 553 ctx.VisitDirectDeps(func(m Module) { 554 if !matches { 555 name := ctx.OtherModuleName(m) 556 matches = r.directDeps[name] 557 } 558 }) 559 560 return matches 561} 562 563func (r *rule) appliesToOsClass(osClass OsClass) bool { 564 if len(r.osClasses) == 0 { 565 return true 566 } 567 568 for _, c := range r.osClasses { 569 if c == osClass { 570 return true 571 } 572 } 573 574 return false 575} 576 577func (r *rule) appliesToModuleType(moduleType string) bool { 578 return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes) 579} 580 581func (r *rule) appliesToProperties(properties []interface{}) bool { 582 includeProps := hasAllProperties(properties, r.props) 583 excludeProps := hasAnyProperty(properties, r.unlessProps) 584 return includeProps && !excludeProps 585} 586 587func StartsWith(prefix string) ValueMatcher { 588 return &startsWithMatcher{prefix} 589} 590 591func Regexp(re string) ValueMatcher { 592 r, err := regexp.Compile(re) 593 if err != nil { 594 panic(err) 595 } 596 return ®exMatcher{r} 597} 598 599func NotInList(allowed []string) ValueMatcher { 600 return ¬InListMatcher{allowed} 601} 602 603// assorted utils 604 605func cleanPaths(paths []string) []string { 606 res := make([]string, len(paths)) 607 for i, v := range paths { 608 res[i] = filepath.Clean(v) + "/" 609 } 610 return res 611} 612 613func fieldNamesForProperties(propertyNames string) []string { 614 names := strings.Split(propertyNames, ".") 615 for i, v := range names { 616 names[i] = proptools.FieldNameForProperty(v) 617 } 618 return names 619} 620 621func hasAnyProperty(properties []interface{}, props []ruleProperty) bool { 622 for _, v := range props { 623 if hasProperty(properties, v) { 624 return true 625 } 626 } 627 return false 628} 629 630func hasAllProperties(properties []interface{}, props []ruleProperty) bool { 631 for _, v := range props { 632 if !hasProperty(properties, v) { 633 return false 634 } 635 } 636 return true 637} 638 639func hasProperty(properties []interface{}, prop ruleProperty) bool { 640 for _, propertyStruct := range properties { 641 propertiesValue := reflect.ValueOf(propertyStruct).Elem() 642 for _, v := range prop.fields { 643 if !propertiesValue.IsValid() { 644 break 645 } 646 propertiesValue = propertiesValue.FieldByName(v) 647 } 648 if !propertiesValue.IsValid() { 649 continue 650 } 651 652 check := func(value string) bool { 653 return prop.matcher.Test(value) 654 } 655 656 if matchValue(propertiesValue, check) { 657 return true 658 } 659 } 660 return false 661} 662 663func matchValue(value reflect.Value, check func(string) bool) bool { 664 if !value.IsValid() { 665 return false 666 } 667 668 if value.Kind() == reflect.Ptr { 669 if value.IsNil() { 670 return check("") 671 } 672 value = value.Elem() 673 } 674 675 switch value.Kind() { 676 case reflect.String: 677 return check(value.String()) 678 case reflect.Bool: 679 return check(strconv.FormatBool(value.Bool())) 680 case reflect.Int: 681 return check(strconv.FormatInt(value.Int(), 10)) 682 case reflect.Slice: 683 slice, ok := value.Interface().([]string) 684 if !ok { 685 panic("Can only handle slice of string") 686 } 687 for _, v := range slice { 688 if check(v) { 689 return true 690 } 691 } 692 return false 693 } 694 695 panic("Can't handle type: " + value.Kind().String()) 696} 697 698var neverallowRulesKey = NewOnceKey("neverallowRules") 699 700func neverallowRules(config Config) []Rule { 701 return config.Once(neverallowRulesKey, func() interface{} { 702 // No test rules were set by setTestNeverallowRules, use the global rules 703 return neverallows 704 }).([]Rule) 705} 706 707// Overrides the default neverallow rules for the supplied config. 708// 709// For testing only. 710func setTestNeverallowRules(config Config, testRules []Rule) { 711 config.Once(neverallowRulesKey, func() interface{} { return testRules }) 712} 713 714// Prepares for a test by setting neverallow rules and enabling the mutator. 715// 716// If the supplied rules are nil then the default rules are used. 717func PrepareForTestWithNeverallowRules(testRules []Rule) FixturePreparer { 718 return GroupFixturePreparers( 719 FixtureModifyConfig(func(config Config) { 720 if testRules != nil { 721 setTestNeverallowRules(config, testRules) 722 } 723 }), 724 FixtureRegisterWithContext(func(ctx RegistrationContext) { 725 ctx.PostDepsMutators(registerNeverallowMutator) 726 }), 727 ) 728} 729