blob: e7b3af26521cf0d92b0520f5e68eb0a6eadf2cd6 [file] [log] [blame]
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +08001// 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 (
Inseob Kim16d3be32022-01-07 09:15:27 +090018 "fmt"
19
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +080020 "github.com/google/blueprint/proptools"
21
22 "android/soong/android"
23)
24
Inseob Kim16d3be32022-01-07 09:15:27 +090025var (
26 compatTestDepTag = dependencyTag{name: "compat_test"}
27)
28
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +080029func init() {
Inseob Kim16d3be32022-01-07 09:15:27 +090030 ctx := android.InitRegistrationContext
31 ctx.RegisterModuleType("se_compat_cil", compatCilFactory)
32 ctx.RegisterSingletonModuleType("se_compat_test", compatTestFactory)
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +080033}
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.Path
47 installPath android.InstallPath
48}
49
50type compatCilProperties struct {
51 // List of source files. Can reference se_filegroup type modules with the ":module" syntax.
Paul Duffin532bde12021-07-09 22:53:03 +010052 Srcs []string `android:"path"`
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +080053
54 // Output file name. Defaults to module name if unspecified.
55 Stem *string
56}
57
58func (c *compatCil) stem() string {
59 return proptools.StringDefault(c.properties.Stem, c.Name())
60}
61
62func (c *compatCil) expandSeSources(ctx android.ModuleContext) android.Paths {
63 srcPaths := make(android.Paths, 0, len(c.properties.Srcs))
64 for _, src := range c.properties.Srcs {
65 if m := android.SrcIsModule(src); m != "" {
Paul Duffin532bde12021-07-09 22:53:03 +010066 module := android.GetModuleFromPathDep(ctx, m, "")
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +080067 if module == nil {
68 // Error would have been handled by ExtractSourcesDeps
69 continue
70 }
71 if fg, ok := module.(*fileGroup); ok {
72 if c.SystemExtSpecific() {
73 srcPaths = append(srcPaths, fg.SystemExtPrivateSrcs()...)
74 } else {
75 srcPaths = append(srcPaths, fg.SystemPrivateSrcs()...)
76 }
77 } else {
78 ctx.PropertyErrorf("srcs", "%q is not an se_filegroup", m)
79 }
80 } else {
81 srcPaths = append(srcPaths, android.PathForModuleSrc(ctx, src))
82 }
83 }
84 return srcPaths
85}
86
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +080087func (c *compatCil) GenerateAndroidBuildActions(ctx android.ModuleContext) {
88 if c.ProductSpecific() || c.SocSpecific() || c.DeviceSpecific() {
89 ctx.ModuleErrorf("Compat cil files only support system and system_ext partitions")
90 }
91
92 srcPaths := c.expandSeSources(ctx)
93 out := android.PathForModuleGen(ctx, c.Name())
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +080094 ctx.Build(pctx, android.BuildParams{
95 Rule: android.Cat,
96 Inputs: srcPaths,
97 Output: out,
98 Description: "Combining compat cil for " + c.Name(),
99 })
100
101 c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux", "mapping")
102 c.installSource = out
103 ctx.InstallFile(c.installPath, c.stem(), c.installSource)
104}
105
106func (c *compatCil) AndroidMkEntries() []android.AndroidMkEntries {
107 return []android.AndroidMkEntries{android.AndroidMkEntries{
108 Class: "ETC",
109 OutputFile: android.OptionalPathForPath(c.installSource),
110 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
111 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
Colin Cross6c7f9372022-01-11 19:35:43 -0800112 entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
Yi-Yo Chiang41c34d62021-04-13 02:44:41 +0800113 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
114 },
115 },
116 }}
117}
Inseob Kim16d3be32022-01-07 09:15:27 +0900118
119func (c *compatCil) OutputFiles(tag string) (android.Paths, error) {
120 switch tag {
121 case "":
122 return android.Paths{c.installSource}, nil
123 default:
124 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
125 }
126}
127
128var _ android.OutputFileProducer = (*compatCil)(nil)
129
130// se_compat_test checks if compat files ({ver}.cil, {ver}.compat.cil) files are compatible with
131// current policy.
132func compatTestFactory() android.SingletonModule {
133 f := &compatTestModule{}
134 android.InitAndroidModule(f)
135 android.AddLoadHook(f, func(ctx android.LoadHookContext) {
136 f.loadHook(ctx)
137 })
138 return f
139}
140
141type compatTestModule struct {
142 android.SingletonModuleBase
143
144 compatTestTimestamp android.ModuleOutPath
145}
146
147func (f *compatTestModule) createPlatPubVersionedModule(ctx android.LoadHookContext, ver string) {
148 confName := fmt.Sprintf("pub_policy_%s.conf", ver)
149 cilName := fmt.Sprintf("pub_policy_%s.cil", ver)
150 platPubVersionedName := fmt.Sprintf("plat_pub_versioned_%s.cil", ver)
151
152 ctx.CreateModule(policyConfFactory, &nameProperties{
153 Name: proptools.StringPtr(confName),
154 }, &policyConfProperties{
155 Srcs: []string{
156 fmt.Sprintf(":se_build_files{.plat_public_%s}", ver),
Inseob Kim73f43ff2022-02-14 23:01:04 +0900157 fmt.Sprintf(":se_build_files{.system_ext_public_%s}", ver),
158 fmt.Sprintf(":se_build_files{.product_public_%s}", ver),
Inseob Kim16d3be32022-01-07 09:15:27 +0900159 ":se_build_files{.reqd_mask}",
160 },
161 Installable: proptools.BoolPtr(false),
162 })
163
164 ctx.CreateModule(policyCilFactory, &nameProperties{
165 Name: proptools.StringPtr(cilName),
166 }, &policyCilProperties{
167 Src: proptools.StringPtr(":" + confName),
168 Filter_out: []string{":reqd_policy_mask.cil"},
169 Secilc_check: proptools.BoolPtr(false),
170 Installable: proptools.BoolPtr(false),
171 })
172
173 ctx.CreateModule(versionedPolicyFactory, &nameProperties{
174 Name: proptools.StringPtr(platPubVersionedName),
175 }, &versionedPolicyProperties{
176 Base: proptools.StringPtr(":" + cilName),
177 Target_policy: proptools.StringPtr(":" + cilName),
178 Version: proptools.StringPtr(ver),
179 Installable: proptools.BoolPtr(false),
180 })
181}
182
183func (f *compatTestModule) createCompatTestModule(ctx android.LoadHookContext, ver string) {
184 srcs := []string{
185 ":plat_sepolicy.cil",
186 ":system_ext_sepolicy.cil",
187 ":product_sepolicy.cil",
188 fmt.Sprintf(":plat_%s.cil", ver),
189 fmt.Sprintf(":%s.compat.cil", ver),
190 fmt.Sprintf(":system_ext_%s.cil", ver),
191 fmt.Sprintf(":system_ext_%s.compat.cil", ver),
192 fmt.Sprintf(":product_%s.cil", ver),
193 }
194
195 if ver == ctx.DeviceConfig().BoardSepolicyVers() {
196 srcs = append(srcs,
197 ":plat_pub_versioned.cil",
198 ":vendor_sepolicy.cil",
199 ":odm_sepolicy.cil",
200 )
201 } else {
202 srcs = append(srcs, fmt.Sprintf(":plat_pub_versioned_%s.cil", ver))
203 }
204
205 compatTestName := fmt.Sprintf("%s_compat_test", ver)
206 ctx.CreateModule(policyBinaryFactory, &nameProperties{
207 Name: proptools.StringPtr(compatTestName),
208 }, &policyBinaryProperties{
209 Srcs: srcs,
210 Ignore_neverallow: proptools.BoolPtr(true),
211 Installable: proptools.BoolPtr(false),
212 })
213}
214
215func (f *compatTestModule) loadHook(ctx android.LoadHookContext) {
216 for _, ver := range ctx.DeviceConfig().PlatformSepolicyCompatVersions() {
217 f.createPlatPubVersionedModule(ctx, ver)
218 f.createCompatTestModule(ctx, ver)
219 }
220}
221
222func (f *compatTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
223 for _, ver := range ctx.DeviceConfig().PlatformSepolicyCompatVersions() {
224 ctx.AddDependency(f, compatTestDepTag, fmt.Sprintf("%s_compat_test", ver))
225 }
226}
227
228func (f *compatTestModule) GenerateSingletonBuildActions(ctx android.SingletonContext) {
229 // does nothing; se_compat_test is a singeton because two compat test modules don't make sense.
230}
231
232func (f *compatTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
233 var inputs android.Paths
234 ctx.VisitDirectDepsWithTag(compatTestDepTag, func(child android.Module) {
235 o, ok := child.(android.OutputFileProducer)
236 if !ok {
237 panic(fmt.Errorf("Module %q should be an OutputFileProducer but it isn't", ctx.OtherModuleName(child)))
238 }
239
240 outputs, err := o.OutputFiles("")
241 if err != nil {
242 panic(fmt.Errorf("Module %q error while producing output: %v", ctx.OtherModuleName(child), err))
243 }
244 if len(outputs) != 1 {
245 panic(fmt.Errorf("Module %q should produce exactly one output, but did %q", ctx.OtherModuleName(child), outputs.Strings()))
246 }
247
248 inputs = append(inputs, outputs[0])
249 })
250
251 f.compatTestTimestamp = android.PathForModuleOut(ctx, "timestamp")
252 rule := android.NewRuleBuilder(pctx, ctx)
253 rule.Command().Text("touch").Output(f.compatTestTimestamp).Implicits(inputs)
254 rule.Build("compat", "compat test timestamp for: "+f.Name())
255}
256
257func (f *compatTestModule) AndroidMkEntries() []android.AndroidMkEntries {
258 return []android.AndroidMkEntries{android.AndroidMkEntries{
259 Class: "FAKE",
260 // OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it.
261 // Without OutputFile this module won't be exported to Makefile.
262 OutputFile: android.OptionalPathForPath(f.compatTestTimestamp),
263 Include: "$(BUILD_PHONY_PACKAGE)",
264 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
265 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
266 entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", f.compatTestTimestamp.String())
267 },
268 },
269 }}
270}