Merge "Support multiple se_flags modules" into main

This commit is contained in:
Treehugger Robot 2024-02-19 04:30:04 +00:00 committed by Gerrit Code Review
commit f9f826fb30
6 changed files with 253 additions and 16 deletions

View file

@ -47,5 +47,6 @@ bootstrap_go_package {
"service_fuzzer_bindings.go",
"validate_bindings.go",
],
testSrcs: ["selinux_test.go"],
pluginFor: ["soong_build"],
}

View file

@ -15,22 +15,141 @@
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 flags to be passed to M4 macro.
// 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 flagsProperties
properties flaggableModuleProperties
}
func initFlaggableModule(m flaggableModule) {
@ -42,13 +161,19 @@ 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)
for _, flag := range android.SortedUniqueStrings(f.properties.Flags) {
if val, ok := ctx.Config().GetBuildFlag(flag); ok {
ret[flag] = val
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
}

View file

@ -129,7 +129,7 @@ func policyConfDefaultFactory() android.Module {
c := &policyConfDefaults{}
c.AddProperties(
&policyConfProperties{},
&flagsProperties{},
&flaggableModuleProperties{},
)
android.InitDefaultsModule(c)
return c
@ -270,6 +270,10 @@ func (c *policyConf) transformPolicyToConf(ctx android.ModuleContext) android.Ou
return conf
}
func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) {
c.flagDeps(ctx)
}
func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if !c.installable() {
c.SkipInstall()

View file

@ -110,6 +110,8 @@ func (m *selinuxContextsModule) onlyInRecovery() bool {
}
func (m *selinuxContextsModule) DepsMutator(ctx android.BottomUpMutatorContext) {
m.flagDeps(ctx)
if m.deps != nil {
m.deps(ctx)
}
@ -182,7 +184,7 @@ func contextsDefaultsFactory() android.Module {
m.AddProperties(
&selinuxContextsProperties{},
&seappProperties{},
&flagsProperties{},
&flaggableModuleProperties{},
)
android.InitDefaultsModule(m)
return m

View file

@ -0,0 +1,96 @@
// Copyright 2024 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 (
"os"
"reflect"
"testing"
"android/soong/android"
)
func TestMain(m *testing.M) {
os.Exit(m.Run())
}
var prepareForTest = android.GroupFixturePreparers(
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
buildFlags := make(map[string]string)
buildFlags["RELEASE_FLAGS_BAR"] = "true"
buildFlags["RELEASE_FLAGS_FOO1"] = "false"
// "RELEASE_FLAGS_FOO2" is missing
buildFlags["RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT"] = "true"
variables.BuildFlags = buildFlags
}),
android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("se_flags", flagsFactory)
ctx.RegisterModuleType("se_flags_collector", flagsCollectorFactory)
}),
)
func TestFlagCollector(t *testing.T) {
t.Parallel()
ctx := android.GroupFixturePreparers(
prepareForTest,
android.FixtureAddTextFile("package_bar/Android.bp", `
se_flags {
name: "se_flags_bar",
flags: ["RELEASE_FLAGS_BAR"],
export_to: ["se_flags_collector"],
}
`),
android.FixtureAddTextFile("package_foo/Android.bp", `
se_flags {
name: "se_flags_foo",
flags: ["RELEASE_FLAGS_FOO1", "RELEASE_FLAGS_FOO2"],
export_to: ["se_flags_collector"],
}
`),
android.FixtureAddTextFile("system/sepolicy/Android.bp", `
se_flags {
name: "se_flags",
flags: ["RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT"],
export_to: ["se_flags_collector"],
}
se_flags_collector {
name: "se_flags_collector",
}
`),
).RunTest(t).TestContext
collectorModule := ctx.ModuleForTests("se_flags_collector", "").Module()
collectorData, ok := android.OtherModuleProvider(ctx.OtherModuleProviderAdaptor(), collectorModule, buildFlagsProviderKey)
if !ok {
t.Errorf("se_flags_collector must provide buildFlags")
return
}
actual := flagsToM4Macros(collectorData.BuildFlags)
expected := []string{
"-D target_flag_RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT=true",
"-D target_flag_RELEASE_FLAGS_BAR=true",
"-D target_flag_RELEASE_FLAGS_FOO1=false",
}
if !reflect.DeepEqual(actual, expected) {
t.Errorf("M4 macros were not exported correctly"+
"\nactual: %v"+
"\nexpected: %v",
actual,
expected,
)
}
}

View file

@ -12,24 +12,33 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// This file contains a list of flags for sepolicy.
se_policy_conf_defaults {
name: "se_policy_conf_flags_defaults",
srcs: [":sepolicy_flagging_macros"],
// This module contains a list of build time flags (defined on AOSP) for sepolicy.
// Additional se_flags modules can be added anywhere for additional flags.
se_flags {
name: "aosp_selinux_flags",
flags: [
"RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT",
"RELEASE_HARDWARE_BLUETOOTH_RANGING_SERVICE",
],
export_to: ["all_selinux_flags"],
}
// se_flags_collector collects flags from exported se_flags modules and converts it to build flags.
se_flags_collector {
name: "all_selinux_flags",
}
se_policy_conf_defaults {
name: "se_policy_conf_flags_defaults",
srcs: [":sepolicy_flagging_macros"],
build_flags: ["all_selinux_flags"],
}
contexts_defaults {
name: "contexts_flags_defaults",
srcs: [":sepolicy_flagging_macros"],
neverallow_files: [":sepolicy_flagging_macros"], // for seapp_contexts
flags: [
"RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT",
"RELEASE_HARDWARE_BLUETOOTH_RANGING_SERVICE",
],
build_flags: ["all_selinux_flags"],
}
filegroup {