// Copyright (C) 2023 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package selinux import ( "maps" "android/soong/android" "github.com/google/blueprint" ) var ( flagsDepTag = dependencyTag{name: "flags"} buildFlagsDepTag = dependencyTag{name: "build_flags"} ) func init() { ctx := android.InitRegistrationContext ctx.RegisterModuleType("se_flags", flagsFactory) ctx.RegisterModuleType("se_flags_collector", flagsCollectorFactory) } type flagsProperties struct { // List of build time flags for flag-guarding. Flags []string // List of se_flags_collector modules to export flags to. Export_to []string } type flagsModule struct { android.ModuleBase properties flagsProperties } type flagsInfo struct { Flags []string } var flagsProviderKey = blueprint.NewProvider[flagsInfo]() // se_flags contains a list of build time flags for sepolicy. Build time flags are defined under // .scl files (e.g. build/release/build_flags.scl). By importing flags with se_flags modules, // sepolicy rules can be guarded by `is_flag_enabled` / `is_flag_disabled` macro. // // For example, an Android.bp file could have: // // se_flags { // name: "aosp_selinux_flags", // flags: ["RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT"], // export_to: ["all_selinux_flags"], // } // // And then one could flag-guard .te file rules: // // is_flag_enabled(RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT, ` // type vfio_handler, domain, coredomain; // binder_use(vfio_handler) // ') // // or contexts entries: // // is_flag_enabled(RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT, ` // android.system.virtualizationservice_internal.IVfioHandler u:object_r:vfio_handler_service:s0 // ') func flagsFactory() android.Module { module := &flagsModule{} module.AddProperties(&module.properties) android.InitAndroidModule(module) return module } func (f *flagsModule) DepsMutator(ctx android.BottomUpMutatorContext) { // dep se_flag_collector -> se_flags for _, export := range f.properties.Export_to { ctx.AddReverseDependency(ctx.Module(), flagsDepTag, export) } } func (f *flagsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { android.SetProvider(ctx, flagsProviderKey, flagsInfo{ Flags: f.properties.Flags, }) } type buildFlagsInfo struct { BuildFlags map[string]string } var buildFlagsProviderKey = blueprint.NewProvider[buildFlagsInfo]() type flagsCollectorModule struct { android.ModuleBase buildFlags map[string]string } // se_flags_collector module collects flags from exported se_flags modules (see export_to property // of se_flags modules), and then converts them into build-time flags. It will be used to generate // M4 macros to flag-guard sepolicy. func flagsCollectorFactory() android.Module { module := &flagsCollectorModule{} android.InitAndroidModule(module) return module } func (f *flagsCollectorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { var flags []string ctx.VisitDirectDepsWithTag(flagsDepTag, func(m android.Module) { if dep, ok := android.OtherModuleProvider(ctx, m, flagsProviderKey); ok { flags = append(flags, dep.Flags...) } else { ctx.ModuleErrorf("unknown dependency %q", ctx.OtherModuleName(m)) } }) buildFlags := make(map[string]string) for _, flag := range android.SortedUniqueStrings(flags) { if val, ok := ctx.Config().GetBuildFlag(flag); ok { buildFlags[flag] = val } } android.SetProvider(ctx, buildFlagsProviderKey, buildFlagsInfo{ BuildFlags: buildFlags, }) } type flaggableModuleProperties struct { // List of se_flag_collector modules to be passed to M4 macro. Build_flags []string } type flaggableModule interface { android.Module flagModuleBase() *flaggableModuleBase flagDeps(ctx android.BottomUpMutatorContext) getBuildFlags(ctx android.ModuleContext) map[string]string } type flaggableModuleBase struct { properties flaggableModuleProperties } func initFlaggableModule(m flaggableModule) { base := m.flagModuleBase() m.AddProperties(&base.properties) } func (f *flaggableModuleBase) flagModuleBase() *flaggableModuleBase { return f } func (f *flaggableModuleBase) flagDeps(ctx android.BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), buildFlagsDepTag, f.properties.Build_flags...) } // getBuildFlags returns a map from flag names to flag values. func (f *flaggableModuleBase) getBuildFlags(ctx android.ModuleContext) map[string]string { ret := make(map[string]string) ctx.VisitDirectDepsWithTag(buildFlagsDepTag, func(m android.Module) { if dep, ok := android.OtherModuleProvider(ctx, m, buildFlagsProviderKey); ok { maps.Copy(ret, dep.BuildFlags) } else { ctx.PropertyErrorf("build_flags", "unknown dependency %q", ctx.OtherModuleName(m)) } }) return ret }