1// Copyright (C) 2023 The Android Open Source Project
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 selinux
16
17import (
18	"maps"
19
20	"android/soong/android"
21
22	"github.com/google/blueprint"
23)
24
25var (
26	flagsDepTag      = dependencyTag{name: "flags"}
27	buildFlagsDepTag = dependencyTag{name: "build_flags"}
28)
29
30func init() {
31	ctx := android.InitRegistrationContext
32	ctx.RegisterModuleType("se_flags", flagsFactory)
33	ctx.RegisterModuleType("se_flags_collector", flagsCollectorFactory)
34}
35
36type flagsProperties struct {
37	// List of build time flags for flag-guarding.
38	Flags []string
39
40	// List of se_flags_collector modules to export flags to.
41	Export_to []string
42}
43
44type flagsModule struct {
45	android.ModuleBase
46	properties flagsProperties
47}
48
49type flagsInfo struct {
50	Flags []string
51}
52
53var flagsProviderKey = blueprint.NewProvider[flagsInfo]()
54
55// se_flags contains a list of build time flags for sepolicy.  Build time flags are defined under
56// .scl files (e.g. build/release/build_flags.scl). By importing flags with se_flags modules,
57// sepolicy rules can be guarded by `is_flag_enabled` / `is_flag_disabled` macro.
58//
59// For example, an Android.bp file could have:
60//
61//	se_flags {
62//		name: "aosp_selinux_flags",
63//		flags: ["RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT"],
64//		export_to: ["all_selinux_flags"],
65//	}
66//
67// And then one could flag-guard .te file rules:
68//
69//	is_flag_enabled(RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT, `
70//		type vfio_handler, domain, coredomain;
71//		binder_use(vfio_handler)
72//	')
73//
74// or contexts entries:
75//
76//	is_flag_enabled(RELEASE_AVF_ENABLE_DEVICE_ASSIGNMENT, `
77//		android.system.virtualizationservice_internal.IVfioHandler u:object_r:vfio_handler_service:s0
78//	')
79func flagsFactory() android.Module {
80	module := &flagsModule{}
81	module.AddProperties(&module.properties)
82	android.InitAndroidModule(module)
83	return module
84}
85
86func (f *flagsModule) DepsMutator(ctx android.BottomUpMutatorContext) {
87	// dep se_flag_collector -> se_flags
88	for _, export := range f.properties.Export_to {
89		ctx.AddReverseDependency(ctx.Module(), flagsDepTag, export)
90	}
91}
92
93func (f *flagsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
94	android.SetProvider(ctx, flagsProviderKey, flagsInfo{
95		Flags: f.properties.Flags,
96	})
97}
98
99type buildFlagsInfo struct {
100	BuildFlags map[string]string
101}
102
103var buildFlagsProviderKey = blueprint.NewProvider[buildFlagsInfo]()
104
105type flagsCollectorModule struct {
106	android.ModuleBase
107	buildFlags map[string]string
108}
109
110// se_flags_collector module collects flags from exported se_flags modules (see export_to property
111// of se_flags modules), and then converts them into build-time flags.  It will be used to generate
112// M4 macros to flag-guard sepolicy.
113func flagsCollectorFactory() android.Module {
114	module := &flagsCollectorModule{}
115	android.InitAndroidModule(module)
116	return module
117}
118
119func (f *flagsCollectorModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
120	var flags []string
121	ctx.VisitDirectDepsWithTag(flagsDepTag, func(m android.Module) {
122		if dep, ok := android.OtherModuleProvider(ctx, m, flagsProviderKey); ok {
123			flags = append(flags, dep.Flags...)
124		} else {
125			ctx.ModuleErrorf("unknown dependency %q", ctx.OtherModuleName(m))
126		}
127	})
128	buildFlags := make(map[string]string)
129	for _, flag := range android.SortedUniqueStrings(flags) {
130		if val, ok := ctx.Config().GetBuildFlag(flag); ok {
131			buildFlags[flag] = val
132		}
133	}
134	android.SetProvider(ctx, buildFlagsProviderKey, buildFlagsInfo{
135		BuildFlags: buildFlags,
136	})
137}
138
139type flaggableModuleProperties struct {
140	// List of se_flag_collector modules to be passed to M4 macro.
141	Build_flags []string
142}
143
144type flaggableModule interface {
145	android.Module
146	flagModuleBase() *flaggableModuleBase
147	flagDeps(ctx android.BottomUpMutatorContext)
148	getBuildFlags(ctx android.ModuleContext) map[string]string
149}
150
151type flaggableModuleBase struct {
152	properties flaggableModuleProperties
153}
154
155func initFlaggableModule(m flaggableModule) {
156	base := m.flagModuleBase()
157	m.AddProperties(&base.properties)
158}
159
160func (f *flaggableModuleBase) flagModuleBase() *flaggableModuleBase {
161	return f
162}
163
164func (f *flaggableModuleBase) flagDeps(ctx android.BottomUpMutatorContext) {
165	ctx.AddDependency(ctx.Module(), buildFlagsDepTag, f.properties.Build_flags...)
166}
167
168// getBuildFlags returns a map from flag names to flag values.
169func (f *flaggableModuleBase) getBuildFlags(ctx android.ModuleContext) map[string]string {
170	ret := make(map[string]string)
171	ctx.VisitDirectDepsWithTag(buildFlagsDepTag, func(m android.Module) {
172		if dep, ok := android.OtherModuleProvider(ctx, m, buildFlagsProviderKey); ok {
173			maps.Copy(ret, dep.BuildFlags)
174		} else {
175			ctx.PropertyErrorf("build_flags", "unknown dependency %q", ctx.OtherModuleName(m))
176		}
177	})
178	return ret
179}
180