diff --git a/android/neverallow.go b/android/neverallow.go index 8563ebdbe..2eba4a950 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -253,6 +253,10 @@ func neverallowMutator(ctx BottomUpMutatorContext) { continue } + if !n.appliesToBootclasspathJar(ctx) { + continue + } + ctx.ModuleErrorf("violates " + n.String()) } } @@ -311,6 +315,18 @@ func (m *regexMatcher) String() string { return ".regexp(" + m.re.String() + ")" } +type notInListMatcher struct { + allowed []string +} + +func (m *notInListMatcher) Test(value string) bool { + return !InList(value, m.allowed) +} + +func (m *notInListMatcher) String() string { + return ".not-in-list(" + strings.Join(m.allowed, ",") + ")" +} + type isSetMatcher struct{} func (m *isSetMatcher) Test(value string) bool { @@ -342,6 +358,8 @@ type Rule interface { NotModuleType(types ...string) Rule + BootclasspathJar() Rule + With(properties, value string) Rule WithMatcher(properties string, matcher ValueMatcher) Rule @@ -369,6 +387,8 @@ type rule struct { props []ruleProperty unlessProps []ruleProperty + + onlyBootclasspathJar bool } // Create a new NeverAllow rule. @@ -444,6 +464,11 @@ func (r *rule) Because(reason string) Rule { return r } +func (r *rule) BootclasspathJar() Rule { + r.onlyBootclasspathJar = true + return r +} + func (r *rule) String() string { s := "neverallow" for _, v := range r.paths { @@ -470,6 +495,9 @@ func (r *rule) String() string { for _, v := range r.osClasses { s += " os:" + v.String() } + if r.onlyBootclasspathJar { + s += " inBcp" + } if len(r.reason) != 0 { s += " which is restricted because " + r.reason } @@ -498,6 +526,14 @@ func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool { return matches } +func (r *rule) appliesToBootclasspathJar(ctx BottomUpMutatorContext) bool { + if !r.onlyBootclasspathJar { + return true + } + + return InList(ctx.ModuleName(), ctx.Config().BootJars()) +} + func (r *rule) appliesToOsClass(osClass OsClass) bool { if len(r.osClasses) == 0 { return true @@ -534,6 +570,10 @@ func Regexp(re string) ValueMatcher { return ®exMatcher{r} } +func NotInList(allowed []string) ValueMatcher { + return ¬InListMatcher{allowed} +} + // assorted utils func cleanPaths(paths []string) []string { diff --git a/apex/apex.go b/apex/apex.go index 3def89486..a63a8d60c 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -688,6 +688,55 @@ func makeApexAvailableBaseline() map[string][]string { return m } +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// Adding code to the bootclasspath in new packages will cause issues on module update. +func qModulesPackages() map[string][]string { + return map[string][]string{ + "com.android.conscrypt": []string{ + "android.net.ssl", + "com.android.org.conscrypt", + }, + "com.android.media": []string{ + "android.media", + }, + } +} + +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// Adding code to the bootclasspath in new packages will cause issues on module update. +func rModulesPackages() map[string][]string { + return map[string][]string{ + "com.android.mediaprovider": []string{ + "android.provider", + }, + "com.android.permission": []string{ + "android.permission", + "android.app.role", + "com.android.permission", + "com.android.role", + }, + "com.android.sdkext": []string{ + "android.os.ext", + }, + "com.android.os.statsd": []string{ + "android.app", + "android.os", + "android.util", + "com.android.internal.statsd", + "com.android.server.stats", + }, + "com.android.wifi": []string{ + "com.android.server.wifi", + "com.android.wifi.x", + "android.hardware.wifi", + "android.net.wifi", + }, + "com.android.tethering": []string{ + "android.net", + }, + } +} + func init() { android.RegisterModuleType("apex", BundleFactory) android.RegisterModuleType("apex_test", testApexBundleFactory) @@ -705,6 +754,24 @@ func init() { sort.Strings(*apexFileContextsInfos) ctx.Strict("APEX_FILE_CONTEXTS_INFOS", strings.Join(*apexFileContextsInfos, " ")) }) + + android.AddNeverAllowRules(createApexPermittedPackagesRules(qModulesPackages())...) + android.AddNeverAllowRules(createApexPermittedPackagesRules(rModulesPackages())...) +} + +func createApexPermittedPackagesRules(modules_packages map[string][]string) []android.Rule { + rules := make([]android.Rule, 0, len(modules_packages)) + for module_name, module_packages := range modules_packages { + permitted_packages_rule := android.NeverAllow(). + BootclasspathJar(). + With("apex_available", module_name). + WithMatcher("permitted_packages", android.NotInList(module_packages)). + Because("jars that are part of the " + module_name + + " module may only allow these packages: " + strings.Join(module_packages, ",") + + ". Please jarjar or move code around.") + rules = append(rules, permitted_packages_rule) + } + return rules } func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { diff --git a/apex/apex_test.go b/apex/apex_test.go index 770afd427..8803a5f97 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -4855,6 +4855,141 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { testNoUpdatableJarsInBootImage(t, "", bp, transform) } +func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) { + t.Helper() + android.ClearApexDependency() + bp += ` + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + }` + fs := map[string][]byte{ + "lib1/src/A.java": nil, + "lib2/src/B.java": nil, + "system/sepolicy/apex/myapex-file_contexts": nil, + } + + ctx := android.NewTestArchContext() + ctx.RegisterModuleType("apex", BundleFactory) + ctx.RegisterModuleType("apex_key", ApexKeyFactory) + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + cc.RegisterRequiredBuildComponentsForTest(ctx) + java.RegisterJavaBuildComponents(ctx) + java.RegisterSystemModulesBuildComponents(ctx) + java.RegisterDexpreoptBootJarsComponents(ctx) + ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) + ctx.PreDepsMutators(RegisterPreDepsMutators) + ctx.PostDepsMutators(RegisterPostDepsMutators) + ctx.PostDepsMutators(android.RegisterNeverallowMutator) + + config := android.TestArchConfig(buildDir, nil, bp, fs) + android.SetTestNeverallowRules(config, rules) + updatableBootJars := make([]string, 0, len(apexBootJars)) + for _, apexBootJar := range apexBootJars { + updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar) + } + config.TestProductVariables.UpdatableBootJars = updatableBootJars + + ctx.Register(config) + + _, errs := ctx.ParseBlueprintsFiles("Android.bp") + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + if errmsg == "" { + android.FailIfErrored(t, errs) + } else if len(errs) > 0 { + android.FailIfNoMatchingErrors(t, errmsg, errs) + return + } else { + t.Fatalf("missing expected error %q (0 errors are returned)", errmsg) + } +} + +func TestApexPermittedPackagesRules(t *testing.T) { + testcases := []struct { + name string + expectedError string + bp string + bootJars []string + modulesPackages map[string][]string + }{ + + { + name: "Non-Bootclasspath apex jar not satisfying allowed module packages.", + expectedError: "", + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + permitted_packages: ["foo.bar"], + apex_available: ["myapex"], + sdk_version: "none", + system_modules: "none", + } + java_library { + name: "nonbcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["a.b"], + sdk_version: "none", + system_modules: "none", + } + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["bcp_lib1", "nonbcp_lib2"], + }`, + bootJars: []string{"bcp_lib1"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + { + name: "Bootclasspath apex jar not satisfying allowed module packages.", + expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar. Please jarjar or move code around.`, + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar"], + sdk_version: "none", + system_modules: "none", + } + java_library { + name: "bcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar", "bar.baz"], + sdk_version: "none", + system_modules: "none", + } + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["bcp_lib1", "bcp_lib2"], + } + `, + bootJars: []string{"bcp_lib1", "bcp_lib2"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + rules := createApexPermittedPackagesRules(tc.modulesPackages) + testApexPermittedPackagesRules(t, tc.expectedError, tc.bp, tc.bootJars, rules) + }) + } +} + func TestTestFor(t *testing.T) { ctx, _ := testApex(t, ` apex {