xref: /aosp_15_r20/system/sepolicy/build/soong/compat_cil.go (revision e4a36f4174b17bbab9dc043f4a65dc8d87377290)
1// Copyright 2021 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	"fmt"
19
20	"github.com/google/blueprint/proptools"
21
22	"android/soong/android"
23)
24
25var (
26	compatTestDepTag = dependencyTag{name: "compat_test"}
27)
28
29func init() {
30	ctx := android.InitRegistrationContext
31	ctx.RegisterModuleType("se_compat_cil", compatCilFactory)
32	ctx.RegisterModuleType("se_compat_test", compatTestFactory)
33}
34
35// se_compat_cil collects and installs backwards compatibility cil files.
36func compatCilFactory() android.Module {
37	c := &compatCil{}
38	c.AddProperties(&c.properties)
39	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
40	return c
41}
42
43type compatCil struct {
44	android.ModuleBase
45	properties    compatCilProperties
46	installSource android.OptionalPath
47	installPath   android.InstallPath
48}
49
50type compatCilProperties struct {
51	// List of source files. Can reference se_build_files type modules with the ":module" syntax.
52	Srcs []string `android:"path"`
53
54	// Output file name. Defaults to module name if unspecified.
55	Stem *string
56
57	// Target version that this module supports. This module will be ignored if platform sepolicy
58	// version is same as this module's version.
59	Version *string
60}
61
62func (c *compatCil) stem() string {
63	return proptools.StringDefault(c.properties.Stem, c.Name())
64}
65
66func (c *compatCil) expandSeSources(ctx android.ModuleContext) android.Paths {
67	return android.PathsForModuleSrc(ctx, c.properties.Srcs)
68}
69
70func (c *compatCil) shouldSkipBuild(ctx android.ModuleContext) bool {
71	return proptools.String(c.properties.Version) == ctx.DeviceConfig().PlatformSepolicyVersion()
72}
73
74func (c *compatCil) GenerateAndroidBuildActions(ctx android.ModuleContext) {
75	if c.ProductSpecific() || c.SocSpecific() || c.DeviceSpecific() {
76		ctx.ModuleErrorf("Compat cil files only support system and system_ext partitions")
77	}
78
79	if c.shouldSkipBuild(ctx) {
80		return
81	}
82
83	srcPaths := c.expandSeSources(ctx)
84	out := android.PathForModuleGen(ctx, c.Name())
85	ctx.Build(pctx, android.BuildParams{
86		Rule:        android.Cat,
87		Inputs:      srcPaths,
88		Output:      out,
89		Description: "Combining compat cil for " + c.Name(),
90	})
91
92	c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux", "mapping")
93	c.installSource = android.OptionalPathForPath(out)
94	ctx.InstallFile(c.installPath, c.stem(), out)
95
96	if c.installSource.Valid() {
97		ctx.SetOutputFiles(android.Paths{c.installSource.Path()}, "")
98	}
99}
100
101func (c *compatCil) AndroidMkEntries() []android.AndroidMkEntries {
102	if !c.installSource.Valid() {
103		return nil
104	}
105	return []android.AndroidMkEntries{android.AndroidMkEntries{
106		Class:      "ETC",
107		OutputFile: c.installSource,
108		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
109			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
110				entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
111				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
112			},
113		},
114	}}
115}
116
117// se_compat_test checks if compat files ({ver}.cil, {ver}.compat.cil) files are compatible with
118// current policy.
119func compatTestFactory() android.Module {
120	f := &compatTestModule{}
121	f.AddProperties(&f.properties)
122	android.InitAndroidArchModule(f, android.DeviceSupported, android.MultilibCommon)
123	android.AddLoadHook(f, func(ctx android.LoadHookContext) {
124		f.loadHook(ctx)
125	})
126	return f
127}
128
129type compatTestModule struct {
130	android.ModuleBase
131	properties struct {
132		// Default modules for conf
133		Defaults []string
134	}
135
136	compatTestTimestamp android.ModuleOutPath
137}
138
139func (f *compatTestModule) createCompatTestModule(ctx android.LoadHookContext, ver string) {
140	srcs := []string{
141		":plat_sepolicy.cil",
142		":system_ext_sepolicy.cil",
143		":product_sepolicy.cil",
144		fmt.Sprintf(":plat_%s.cil", ver),
145		fmt.Sprintf(":%s.compat.cil", ver),
146		fmt.Sprintf(":system_ext_%s.cil", ver),
147		fmt.Sprintf(":system_ext_%s.compat.cil", ver),
148		fmt.Sprintf(":product_%s.cil", ver),
149	}
150
151	if ver == ctx.DeviceConfig().BoardSepolicyVers() {
152		srcs = append(srcs,
153			":plat_pub_versioned.cil",
154			":vendor_sepolicy.cil",
155			":odm_sepolicy.cil",
156		)
157	} else {
158		srcs = append(srcs, fmt.Sprintf(":%s_plat_pub_versioned.cil", ver))
159	}
160
161	compatTestName := fmt.Sprintf("%s_compat_test", ver)
162	ctx.CreateModule(policyBinaryFactory, &nameProperties{
163		Name: proptools.StringPtr(compatTestName),
164	}, &policyBinaryProperties{
165		Srcs:              srcs,
166		Ignore_neverallow: proptools.BoolPtr(true),
167		Installable:       proptools.BoolPtr(false),
168	})
169}
170
171func (f *compatTestModule) loadHook(ctx android.LoadHookContext) {
172	for _, ver := range ctx.DeviceConfig().PlatformSepolicyCompatVersions() {
173		f.createCompatTestModule(ctx, ver)
174	}
175}
176
177func (f *compatTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
178	for _, ver := range ctx.DeviceConfig().PlatformSepolicyCompatVersions() {
179		ctx.AddDependency(f, compatTestDepTag, fmt.Sprintf("%s_compat_test", ver))
180	}
181}
182
183func (f *compatTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
184	if ctx.ModuleName() != "sepolicy_compat_test" || ctx.ModuleDir() != "system/sepolicy/compat" {
185		// two compat test modules don't make sense.
186		ctx.ModuleErrorf("There can only be 1 se_compat_test module named sepolicy_compat_test in system/sepolicy/compat")
187	}
188	var inputs android.Paths
189	ctx.VisitDirectDepsWithTag(compatTestDepTag, func(child android.Module) {
190		outputs := android.OutputFilesForModule(ctx, child, "")
191		if len(outputs) != 1 {
192			panic(fmt.Errorf("Module %q should produce exactly one output, but did %q", ctx.OtherModuleName(child), outputs.Strings()))
193		}
194
195		inputs = append(inputs, outputs[0])
196	})
197
198	f.compatTestTimestamp = android.PathForModuleOut(ctx, "timestamp")
199	rule := android.NewRuleBuilder(pctx, ctx)
200	rule.Command().Text("touch").Output(f.compatTestTimestamp).Implicits(inputs)
201	rule.Build("compat", "compat test timestamp for: "+f.Name())
202}
203
204func (f *compatTestModule) AndroidMkEntries() []android.AndroidMkEntries {
205	return []android.AndroidMkEntries{android.AndroidMkEntries{
206		Class: "FAKE",
207		// OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it.
208		// Without OutputFile this module won't be exported to Makefile.
209		OutputFile: android.OptionalPathForPath(f.compatTestTimestamp),
210		Include:    "$(BUILD_PHONY_PACKAGE)",
211		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
212			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
213				entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", f.compatTestTimestamp.String())
214			},
215		},
216	}}
217}
218