blob: 6a7123bd29f86b0c4674e192054adc6c4bc1a9d4 [file] [log] [blame]
Inseob Kimb554e592019-04-15 20:10:46 +09001// Copyright (C) 2019 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 "io"
20 "strings"
21
22 "github.com/google/blueprint/proptools"
23
24 "android/soong/android"
25)
26
27const (
28 coreMode = "core"
29 recoveryMode = "recovery"
30)
31
32type selinuxContextsProperties struct {
33 // Filenames under sepolicy directories, which will be used to generate contexts file.
34 Srcs []string `android:"path"`
35
36 Product_variables struct {
37 Debuggable struct {
38 Srcs []string
39 }
40
41 Address_sanitize struct {
42 Srcs []string
43 }
44 }
45
46 // Whether reqd_mask directory is included to sepolicy directories or not.
47 Reqd_mask *bool
48
49 // Whether the comments in generated contexts file will be removed or not.
50 Remove_comment *bool
51
52 // Whether the result context file is sorted with fc_sort or not.
53 Fc_sort *bool
54
55 // Make this module available when building for recovery
56 Recovery_available *bool
57
58 InRecovery bool `blueprint:"mutated"`
59}
60
61type fileContextsProperties struct {
62 // flatten_apex can be used to specify additional sources of file_contexts.
63 // Apex paths, /system/apex/{apex_name}, will be amended to the paths of file_contexts
64 // entries.
65 Flatten_apex struct {
66 Srcs []string
67 }
68}
69
70type selinuxContextsModule struct {
71 android.ModuleBase
72
73 properties selinuxContextsProperties
74 fileContextsProperties fileContextsProperties
75 build func(ctx android.ModuleContext, inputs android.Paths)
76 outputPath android.ModuleGenPath
Colin Cross040f1512019-10-02 10:36:09 -070077 installPath android.InstallPath
Inseob Kimb554e592019-04-15 20:10:46 +090078}
79
80var (
81 reuseContextsDepTag = dependencyTag{name: "reuseContexts"}
82)
83
84func init() {
85 pctx.HostBinToolVariable("fc_sort", "fc_sort")
86
87 android.RegisterModuleType("file_contexts", fileFactory)
88 android.RegisterModuleType("hwservice_contexts", hwServiceFactory)
89 android.RegisterModuleType("property_contexts", propertyFactory)
90 android.RegisterModuleType("service_contexts", serviceFactory)
91
92 android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
93 ctx.BottomUp("selinux_contexts", selinuxContextsMutator).Parallel()
94 })
95}
96
97func (m *selinuxContextsModule) inRecovery() bool {
98 return m.properties.InRecovery || m.ModuleBase.InstallInRecovery()
99}
100
101func (m *selinuxContextsModule) onlyInRecovery() bool {
102 return m.ModuleBase.InstallInRecovery()
103}
104
105func (m *selinuxContextsModule) InstallInRecovery() bool {
106 return m.inRecovery()
107}
108
Colin Cross040f1512019-10-02 10:36:09 -0700109func (m *selinuxContextsModule) InstallInRoot() bool {
110 return m.inRecovery()
111}
112
Inseob Kimb554e592019-04-15 20:10:46 +0900113func (m *selinuxContextsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Colin Cross040f1512019-10-02 10:36:09 -0700114 if m.inRecovery() {
115 // Installing context files at the root of the recovery partition
116 m.installPath = android.PathForModuleInstall(ctx)
Inseob Kimb554e592019-04-15 20:10:46 +0900117 } else {
118 m.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
119 }
120
121 if m.inRecovery() && !m.onlyInRecovery() {
122 dep := ctx.GetDirectDepWithTag(m.Name(), reuseContextsDepTag)
123
124 if reuseDeps, ok := dep.(*selinuxContextsModule); ok {
125 m.outputPath = reuseDeps.outputPath
126 ctx.InstallFile(m.installPath, m.Name(), m.outputPath)
127 return
128 }
129 }
130
131 var inputs android.Paths
132
133 ctx.VisitDirectDepsWithTag(android.SourceDepTag, func(dep android.Module) {
134 segroup, ok := dep.(*fileGroup)
135 if !ok {
136 ctx.ModuleErrorf("srcs dependency %q is not an selinux filegroup",
137 ctx.OtherModuleName(dep))
138 return
139 }
140
141 if ctx.ProductSpecific() {
142 inputs = append(inputs, segroup.ProductPrivateSrcs()...)
143 } else if ctx.SocSpecific() {
144 inputs = append(inputs, segroup.SystemVendorSrcs()...)
145 inputs = append(inputs, segroup.VendorSrcs()...)
146 } else if ctx.DeviceSpecific() {
147 inputs = append(inputs, segroup.OdmSrcs()...)
Bowgo Tsai86a048d2019-09-09 22:04:06 +0800148 } else if ctx.SystemExtSpecific() {
149 inputs = append(inputs, segroup.SystemExtPrivateSrcs()...)
Inseob Kimb554e592019-04-15 20:10:46 +0900150 } else {
151 inputs = append(inputs, segroup.SystemPrivateSrcs()...)
Felix342b58a2020-03-02 16:13:12 +0100152 inputs = append(inputs, segroup.SystemPublicSrcs()...)
Inseob Kimb554e592019-04-15 20:10:46 +0900153 }
154
155 if proptools.Bool(m.properties.Reqd_mask) {
156 inputs = append(inputs, segroup.SystemReqdMaskSrcs()...)
157 }
158 })
159
160 for _, src := range m.properties.Srcs {
161 // Module sources are handled above with VisitDirectDepsWithTag
162 if android.SrcIsModule(src) == "" {
163 inputs = append(inputs, android.PathForModuleSrc(ctx, src))
164 }
165 }
166
167 m.build(ctx, inputs)
168}
169
170func newModule() *selinuxContextsModule {
171 m := &selinuxContextsModule{}
172 m.AddProperties(
173 &m.properties,
174 )
175 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
176 android.AddLoadHook(m, func(ctx android.LoadHookContext) {
177 m.selinuxContextsHook(ctx)
178 })
179 return m
180}
181
182func (m *selinuxContextsModule) selinuxContextsHook(ctx android.LoadHookContext) {
183 // TODO: clean this up to use build/soong/android/variable.go after b/79249983
184 var srcs []string
185
186 if ctx.Config().Debuggable() {
187 srcs = append(srcs, m.properties.Product_variables.Debuggable.Srcs...)
188 }
189
190 for _, sanitize := range ctx.Config().SanitizeDevice() {
191 if sanitize == "address" {
192 srcs = append(srcs, m.properties.Product_variables.Address_sanitize.Srcs...)
193 break
194 }
195 }
196
197 m.properties.Srcs = append(m.properties.Srcs, srcs...)
198}
199
200func (m *selinuxContextsModule) AndroidMk() android.AndroidMkData {
201 return android.AndroidMkData{
202 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
203 nameSuffix := ""
204 if m.inRecovery() && !m.onlyInRecovery() {
205 nameSuffix = ".recovery"
206 }
207 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
208 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
209 fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix)
210 fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
211 if m.Owner() != "" {
212 fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", m.Owner())
213 }
214 fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
215 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", m.outputPath.String())
Colin Cross040f1512019-10-02 10:36:09 -0700216 fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", m.installPath.ToMakePath().String())
Inseob Kimb554e592019-04-15 20:10:46 +0900217 fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name)
218 fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
219 },
220 }
221}
222
223func selinuxContextsMutator(ctx android.BottomUpMutatorContext) {
224 m, ok := ctx.Module().(*selinuxContextsModule)
225 if !ok {
226 return
227 }
228
229 var coreVariantNeeded bool = true
230 var recoveryVariantNeeded bool = false
231 if proptools.Bool(m.properties.Recovery_available) {
232 recoveryVariantNeeded = true
233 }
234
235 if m.ModuleBase.InstallInRecovery() {
236 recoveryVariantNeeded = true
237 coreVariantNeeded = false
238 }
239
240 var variants []string
241 if coreVariantNeeded {
242 variants = append(variants, coreMode)
243 }
244 if recoveryVariantNeeded {
245 variants = append(variants, recoveryMode)
246 }
247 mod := ctx.CreateVariations(variants...)
248
249 for i, v := range variants {
250 if v == recoveryMode {
251 m := mod[i].(*selinuxContextsModule)
252 m.properties.InRecovery = true
253
254 if coreVariantNeeded {
255 ctx.AddInterVariantDependency(reuseContextsDepTag, m, mod[i-1])
256 }
257 }
258 }
259}
260
261func (m *selinuxContextsModule) buildGeneralContexts(ctx android.ModuleContext, inputs android.Paths) {
262 m.outputPath = android.PathForModuleGen(ctx, ctx.ModuleName()+"_m4out")
263
264 rule := android.NewRuleBuilder()
265
266 rule.Command().
Dan Willemsen3c3e59b2019-06-19 10:52:50 -0700267 Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
268 Text("--fatal-warnings -s").
Inseob Kimb554e592019-04-15 20:10:46 +0900269 FlagForEachArg("-D", ctx.DeviceConfig().SepolicyM4Defs()).
270 Inputs(inputs).
271 FlagWithOutput("> ", m.outputPath)
272
273 if proptools.Bool(m.properties.Remove_comment) {
274 rule.Temporary(m.outputPath)
275
276 remove_comment_output := android.PathForModuleGen(ctx, ctx.ModuleName()+"_remove_comment")
277
278 rule.Command().
279 Text("sed -e 's/#.*$//' -e '/^$/d'").
280 Input(m.outputPath).
281 FlagWithOutput("> ", remove_comment_output)
282
283 m.outputPath = remove_comment_output
284 }
285
286 if proptools.Bool(m.properties.Fc_sort) {
287 rule.Temporary(m.outputPath)
288
289 sorted_output := android.PathForModuleGen(ctx, ctx.ModuleName()+"_sorted")
290
291 rule.Command().
292 Tool(ctx.Config().HostToolPath(ctx, "fc_sort")).
293 FlagWithInput("-i ", m.outputPath).
294 FlagWithOutput("-o ", sorted_output)
295
296 m.outputPath = sorted_output
297 }
298
299 rule.Build(pctx, ctx, "selinux_contexts", m.Name())
300
301 rule.DeleteTemporaryFiles()
302
303 ctx.InstallFile(m.installPath, ctx.ModuleName(), m.outputPath)
304}
305
306func (m *selinuxContextsModule) buildFileContexts(ctx android.ModuleContext, inputs android.Paths) {
307 if m.properties.Fc_sort == nil {
308 m.properties.Fc_sort = proptools.BoolPtr(true)
309 }
310
311 rule := android.NewRuleBuilder()
312
313 if ctx.Config().FlattenApex() {
314 for _, src := range m.fileContextsProperties.Flatten_apex.Srcs {
315 if m := android.SrcIsModule(src); m != "" {
316 ctx.ModuleErrorf(
317 "Module srcs dependency %q is not supported for flatten_apex.srcs", m)
318 return
319 }
320 for _, path := range android.PathsForModuleSrcExcludes(ctx, []string{src}, nil) {
321 out := android.PathForModuleGen(ctx, "flattened_apex", path.Rel())
322 apex_path := "/system/apex/" + strings.Replace(
323 strings.TrimSuffix(path.Base(), "-file_contexts"),
324 ".", "\\\\.", -1)
325
326 rule.Command().
327 Text("awk '/object_r/{printf(\""+apex_path+"%s\\n\",$0)}'").
328 Input(path).
329 FlagWithOutput("> ", out)
330
331 inputs = append(inputs, out)
332 }
333 }
334 }
335
336 rule.Build(pctx, ctx, m.Name(), "flattened_apex_file_contexts")
337 m.buildGeneralContexts(ctx, inputs)
338}
339
340func fileFactory() android.Module {
341 m := newModule()
342 m.AddProperties(&m.fileContextsProperties)
343 m.build = m.buildFileContexts
344 return m
345}
346
347func (m *selinuxContextsModule) buildHwServiceContexts(ctx android.ModuleContext, inputs android.Paths) {
348 if m.properties.Remove_comment == nil {
349 m.properties.Remove_comment = proptools.BoolPtr(true)
350 }
351
352 m.buildGeneralContexts(ctx, inputs)
353}
354
355func hwServiceFactory() android.Module {
356 m := newModule()
357 m.build = m.buildHwServiceContexts
358 return m
359}
360
361func propertyFactory() android.Module {
362 m := newModule()
363 m.build = m.buildGeneralContexts
364 return m
365}
366
367func serviceFactory() android.Module {
368 m := newModule()
369 m.build = m.buildGeneralContexts
370 return m
371}