blob: 3308e2ce8f86f7cc7ec662c4ed2eca19654068e2 [file] [log] [blame]
Inseob Kim7e8bd1e2021-03-17 18:59:43 +09001// Copyright (C) 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 "os"
Inseob Kim0a707fa2021-12-09 23:35:11 +090020 "sort"
Inseob Kim7e8bd1e2021-03-17 18:59:43 +090021 "strconv"
Inseob Kim0a707fa2021-12-09 23:35:11 +090022 "strings"
Inseob Kim7e8bd1e2021-03-17 18:59:43 +090023
24 "github.com/google/blueprint/proptools"
25
26 "android/soong/android"
27)
28
29const (
30 // TODO: sync with Android.mk
31 MlsSens = 1
32 MlsCats = 1024
33 PolicyVers = 30
34)
35
Inseob Kim0a707fa2021-12-09 23:35:11 +090036// This order should be kept. checkpolicy syntax requires it.
37var policyConfOrder = []string{
38 "security_classes",
39 "initial_sids",
40 "access_vectors",
41 "global_macros",
42 "neverallow_macros",
43 "mls_macros",
44 "mls_decl",
45 "mls",
46 "policy_capabilities",
47 "te_macros",
48 "attributes",
49 "ioctl_defines",
50 "ioctl_macros",
51 "*.te",
52 "roles_decl",
53 "roles",
54 "users",
55 "initial_sid_contexts",
56 "fs_use",
57 "genfs_contexts",
58 "port_contexts",
59}
60
Inseob Kim7e8bd1e2021-03-17 18:59:43 +090061func init() {
62 android.RegisterModuleType("se_policy_conf", policyConfFactory)
Inseob Kimdf1a0de2021-03-17 19:05:02 +090063 android.RegisterModuleType("se_policy_cil", policyCilFactory)
Inseob Kimb9d05112021-09-27 13:13:46 +000064 android.RegisterModuleType("se_policy_binary", policyBinaryFactory)
Inseob Kim7e8bd1e2021-03-17 18:59:43 +090065}
66
67type policyConfProperties struct {
68 // Name of the output. Default is {module_name}
69 Stem *string
70
71 // Policy files to be compiled to cil file.
72 Srcs []string `android:"path"`
73
74 // Target build variant (user / userdebug / eng). Default follows the current lunch target
75 Build_variant *string
76
77 // Whether to exclude build test or not. Default is false
78 Exclude_build_test *bool
79
80 // Whether to include asan specific policies or not. Default follows the current lunch target
81 With_asan *bool
82
83 // Whether to build CTS specific policy or not. Default is false
84 Cts *bool
85
86 // Whether this module is directly installable to one of the partitions. Default is true
87 Installable *bool
88}
89
90type policyConf struct {
91 android.ModuleBase
92
93 properties policyConfProperties
94
95 installSource android.Path
96 installPath android.InstallPath
97}
98
99// se_policy_conf merges collection of policy files into a policy.conf file to be processed by
100// checkpolicy.
101func policyConfFactory() android.Module {
102 c := &policyConf{}
103 c.AddProperties(&c.properties)
104 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
105 return c
106}
107
108func (c *policyConf) installable() bool {
109 return proptools.BoolDefault(c.properties.Installable, true)
110}
111
112func (c *policyConf) stem() string {
113 return proptools.StringDefault(c.properties.Stem, c.Name())
114}
115
116func (c *policyConf) buildVariant(ctx android.ModuleContext) string {
117 if variant := proptools.String(c.properties.Build_variant); variant != "" {
118 return variant
119 }
120 if ctx.Config().Eng() {
121 return "eng"
122 }
123 if ctx.Config().Debuggable() {
124 return "userdebug"
125 }
126 return "user"
127}
128
129func (c *policyConf) cts() bool {
130 return proptools.Bool(c.properties.Cts)
131}
132
133func (c *policyConf) withAsan(ctx android.ModuleContext) string {
134 isAsanDevice := android.InList("address", ctx.Config().SanitizeDevice())
135 return strconv.FormatBool(proptools.BoolDefault(c.properties.With_asan, isAsanDevice))
136}
137
138func (c *policyConf) sepolicySplit(ctx android.ModuleContext) string {
139 if c.cts() {
140 return "cts"
141 }
142 return strconv.FormatBool(ctx.DeviceConfig().SepolicySplit())
143}
144
145func (c *policyConf) compatibleProperty(ctx android.ModuleContext) string {
146 if c.cts() {
147 return "cts"
148 }
149 return "true"
150}
151
152func (c *policyConf) trebleSyspropNeverallow(ctx android.ModuleContext) string {
153 if c.cts() {
154 return "cts"
155 }
156 return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenTrebleSyspropNeverallow())
157}
158
159func (c *policyConf) enforceSyspropOwner(ctx android.ModuleContext) string {
160 if c.cts() {
161 return "cts"
162 }
163 return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenEnforceSyspropOwner())
164}
165
Hridya Valsarajua885dd82021-04-26 16:32:17 -0700166func (c *policyConf) enforceDebugfsRestrictions(ctx android.ModuleContext) string {
167 if c.cts() {
168 return "cts"
169 }
170 return strconv.FormatBool(ctx.DeviceConfig().BuildDebugfsRestrictionsEnabled())
171}
172
Inseob Kim0a707fa2021-12-09 23:35:11 +0900173func findPolicyConfOrder(name string) int {
174 for idx, pattern := range policyConfOrder {
175 if pattern == name || (pattern == "*.te" && strings.HasSuffix(name, ".te")) {
176 return idx
177 }
178 }
179 // name is not matched
180 return len(policyConfOrder)
181}
182
Inseob Kim7e8bd1e2021-03-17 18:59:43 +0900183func (c *policyConf) transformPolicyToConf(ctx android.ModuleContext) android.OutputPath {
184 conf := android.PathForModuleOut(ctx, "conf").OutputPath
185 rule := android.NewRuleBuilder(pctx, ctx)
Inseob Kim0a707fa2021-12-09 23:35:11 +0900186
187 srcs := android.PathsForModuleSrc(ctx, c.properties.Srcs)
188 sort.SliceStable(srcs, func(x, y int) bool {
189 return findPolicyConfOrder(srcs[x].Base()) < findPolicyConfOrder(srcs[y].Base())
190 })
191
Inseob Kim7e8bd1e2021-03-17 18:59:43 +0900192 rule.Command().Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
193 Flag("--fatal-warnings").
194 FlagForEachArg("-D ", ctx.DeviceConfig().SepolicyM4Defs()).
195 FlagWithArg("-D mls_num_sens=", strconv.Itoa(MlsSens)).
196 FlagWithArg("-D mls_num_cats=", strconv.Itoa(MlsCats)).
197 FlagWithArg("-D target_arch=", ctx.DeviceConfig().DeviceArch()).
198 FlagWithArg("-D target_with_asan=", c.withAsan(ctx)).
Inseob Kim4360c192021-03-23 20:52:53 +0900199 FlagWithArg("-D target_with_dexpreopt=", strconv.FormatBool(ctx.DeviceConfig().WithDexpreopt())).
Inseob Kim7e8bd1e2021-03-17 18:59:43 +0900200 FlagWithArg("-D target_with_native_coverage=", strconv.FormatBool(ctx.DeviceConfig().ClangCoverageEnabled() || ctx.DeviceConfig().GcovCoverageEnabled())).
201 FlagWithArg("-D target_build_variant=", c.buildVariant(ctx)).
202 FlagWithArg("-D target_full_treble=", c.sepolicySplit(ctx)).
203 FlagWithArg("-D target_compatible_property=", c.compatibleProperty(ctx)).
204 FlagWithArg("-D target_treble_sysprop_neverallow=", c.trebleSyspropNeverallow(ctx)).
205 FlagWithArg("-D target_enforce_sysprop_owner=", c.enforceSyspropOwner(ctx)).
206 FlagWithArg("-D target_exclude_build_test=", strconv.FormatBool(proptools.Bool(c.properties.Exclude_build_test))).
207 FlagWithArg("-D target_requires_insecure_execmem_for_swiftshader=", strconv.FormatBool(ctx.DeviceConfig().RequiresInsecureExecmemForSwiftshader())).
Hridya Valsarajua885dd82021-04-26 16:32:17 -0700208 FlagWithArg("-D target_enforce_debugfs_restriction=", c.enforceDebugfsRestrictions(ctx)).
Inseob Kim7e8bd1e2021-03-17 18:59:43 +0900209 Flag("-s").
Inseob Kim0a707fa2021-12-09 23:35:11 +0900210 Inputs(srcs).
Inseob Kim7e8bd1e2021-03-17 18:59:43 +0900211 Text("> ").Output(conf)
212
213 rule.Build("conf", "Transform policy to conf: "+ctx.ModuleName())
214 return conf
215}
216
217func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) {
218 // do nothing
219}
220
221func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Inseob Kim7e8bd1e2021-03-17 18:59:43 +0900222 if !c.installable() {
223 c.SkipInstall()
224 }
Inseob Kim31db2742021-06-08 10:31:09 +0900225
226 c.installSource = c.transformPolicyToConf(ctx)
227 c.installPath = android.PathForModuleInstall(ctx, "etc")
228 ctx.InstallFile(c.installPath, c.stem(), c.installSource)
Inseob Kim7e8bd1e2021-03-17 18:59:43 +0900229}
230
231func (c *policyConf) AndroidMkEntries() []android.AndroidMkEntries {
232 return []android.AndroidMkEntries{android.AndroidMkEntries{
233 OutputFile: android.OptionalPathForPath(c.installSource),
234 Class: "ETC",
235 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
236 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
237 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.installable())
238 entries.SetPath("LOCAL_MODULE_PATH", c.installPath.ToMakePath())
239 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
240 },
241 },
242 }}
243}
244
245func (c *policyConf) OutputFiles(tag string) (android.Paths, error) {
246 if tag == "" {
247 return android.Paths{c.installSource}, nil
248 }
249 return nil, fmt.Errorf("Unknown tag %q", tag)
250}
251
252var _ android.OutputFileProducer = (*policyConf)(nil)
Inseob Kimdf1a0de2021-03-17 19:05:02 +0900253
254type policyCilProperties struct {
255 // Name of the output. Default is {module_name}
256 Stem *string
257
258 // Policy file to be compiled to cil file.
259 Src *string `android:"path"`
260
261 // Additional cil files to be added in the end of the output. This is to support workarounds
262 // which are not supported by the policy language.
263 Additional_cil_files []string `android:"path"`
264
265 // Cil files to be filtered out by the filter_out tool of "build_sepolicy". Used to build
266 // exported policies
267 Filter_out []string `android:"path"`
268
269 // Whether to remove line markers (denoted by ;;) out of compiled cil files. Defaults to false
270 Remove_line_marker *bool
271
272 // Whether to run secilc to check compiled policy or not. Defaults to true
273 Secilc_check *bool
274
275 // Whether to ignore neverallow when running secilc check. Defaults to
276 // SELINUX_IGNORE_NEVERALLOWS.
277 Ignore_neverallow *bool
278
279 // Whether this module is directly installable to one of the partitions. Default is true
280 Installable *bool
281}
282
283type policyCil struct {
284 android.ModuleBase
285
286 properties policyCilProperties
287
288 installSource android.Path
289 installPath android.InstallPath
290}
291
292// se_policy_cil compiles a policy.conf file to a cil file with checkpolicy, and optionally runs
293// secilc to check the output cil file. Affected by SELINUX_IGNORE_NEVERALLOWS.
294func policyCilFactory() android.Module {
295 c := &policyCil{}
296 c.AddProperties(&c.properties)
297 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
298 return c
299}
300
301func (c *policyCil) Installable() bool {
302 return proptools.BoolDefault(c.properties.Installable, true)
303}
304
305func (c *policyCil) stem() string {
306 return proptools.StringDefault(c.properties.Stem, c.Name())
307}
308
309func (c *policyCil) compileConfToCil(ctx android.ModuleContext, conf android.Path) android.OutputPath {
310 cil := android.PathForModuleOut(ctx, c.stem()).OutputPath
311 rule := android.NewRuleBuilder(pctx, ctx)
312 rule.Command().BuiltTool("checkpolicy").
313 Flag("-C"). // Write CIL
314 Flag("-M"). // Enable MLS
315 FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
316 FlagWithOutput("-o ", cil).
317 Input(conf)
318
319 if len(c.properties.Additional_cil_files) > 0 {
320 rule.Command().Text("cat").
321 Inputs(android.PathsForModuleSrc(ctx, c.properties.Additional_cil_files)).
322 Text(">> ").Output(cil)
323 }
324
325 if len(c.properties.Filter_out) > 0 {
326 rule.Command().BuiltTool("build_sepolicy").
327 Text("filter_out").
328 Flag("-f").
329 Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)).
330 FlagWithOutput("-t ", cil)
331 }
332
333 if proptools.Bool(c.properties.Remove_line_marker) {
334 rule.Command().Text("grep -v").
335 Text(proptools.ShellEscape(";;")).
336 Text(cil.String()).
337 Text(">").
338 Text(cil.String() + ".tmp").
339 Text("&& mv").
340 Text(cil.String() + ".tmp").
341 Text(cil.String())
342 }
343
344 if proptools.BoolDefault(c.properties.Secilc_check, true) {
345 secilcCmd := rule.Command().BuiltTool("secilc").
346 Flag("-m"). // Multiple decls
347 FlagWithArg("-M ", "true"). // Enable MLS
348 Flag("-G"). // expand and remove auto generated attributes
349 FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
350 Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). // Also add cil files which are filtered out
351 Text(cil.String()).
352 FlagWithArg("-o ", os.DevNull).
353 FlagWithArg("-f ", os.DevNull)
354
355 if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) {
356 secilcCmd.Flag("-N")
357 }
358 }
359
360 rule.Build("cil", "Building cil for "+ctx.ModuleName())
361 return cil
362}
363
364func (c *policyCil) GenerateAndroidBuildActions(ctx android.ModuleContext) {
365 if proptools.String(c.properties.Src) == "" {
366 ctx.PropertyErrorf("src", "must be specified")
367 return
368 }
369 conf := android.PathForModuleSrc(ctx, *c.properties.Src)
370 cil := c.compileConfToCil(ctx, conf)
371
Inseob Kim31db2742021-06-08 10:31:09 +0900372 if !c.Installable() {
373 c.SkipInstall()
374 }
375
Inseob Kim6cc75f42021-04-29 13:53:20 +0000376 if c.InstallInDebugRamdisk() {
377 // for userdebug_plat_sepolicy.cil
378 c.installPath = android.PathForModuleInstall(ctx)
379 } else {
380 c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
381 }
Inseob Kimdf1a0de2021-03-17 19:05:02 +0900382 c.installSource = cil
383 ctx.InstallFile(c.installPath, c.stem(), c.installSource)
Inseob Kimdf1a0de2021-03-17 19:05:02 +0900384}
385
386func (c *policyCil) AndroidMkEntries() []android.AndroidMkEntries {
387 return []android.AndroidMkEntries{android.AndroidMkEntries{
388 OutputFile: android.OptionalPathForPath(c.installSource),
389 Class: "ETC",
390 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
391 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
392 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable())
393 entries.SetPath("LOCAL_MODULE_PATH", c.installPath.ToMakePath())
394 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
395 },
396 },
397 }}
398}
399
400func (c *policyCil) OutputFiles(tag string) (android.Paths, error) {
401 if tag == "" {
402 return android.Paths{c.installSource}, nil
403 }
404 return nil, fmt.Errorf("Unknown tag %q", tag)
405}
406
407var _ android.OutputFileProducer = (*policyCil)(nil)
Inseob Kimb9d05112021-09-27 13:13:46 +0000408
409type policyBinaryProperties struct {
410 // Name of the output. Default is {module_name}
411 Stem *string
412
413 // Cil files to be compiled.
414 Srcs []string `android:"path"`
415
416 // Whether to ignore neverallow when running secilc check. Defaults to
417 // SELINUX_IGNORE_NEVERALLOWS.
418 Ignore_neverallow *bool
419
420 // Whether this module is directly installable to one of the partitions. Default is true
421 Installable *bool
422}
423
424type policyBinary struct {
425 android.ModuleBase
426
427 properties policyBinaryProperties
428
429 installSource android.Path
430 installPath android.InstallPath
431}
432
433// se_policy_binary compiles cil files to a binary sepolicy file with secilc. Usually sources of
434// se_policy_binary come from outputs of se_policy_cil modules.
435func policyBinaryFactory() android.Module {
436 c := &policyBinary{}
437 c.AddProperties(&c.properties)
438 android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
439 return c
440}
441
442func (c *policyBinary) Installable() bool {
443 return proptools.BoolDefault(c.properties.Installable, true)
444}
445
446func (c *policyBinary) stem() string {
447 return proptools.StringDefault(c.properties.Stem, c.Name())
448}
449
450func (c *policyBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
451 if len(c.properties.Srcs) == 0 {
452 ctx.PropertyErrorf("srcs", "must be specified")
453 return
454 }
Inseob Kim3d5f9252021-12-21 20:42:35 +0900455 bin := android.PathForModuleOut(ctx, c.stem()+"_policy")
Inseob Kimb9d05112021-09-27 13:13:46 +0000456 rule := android.NewRuleBuilder(pctx, ctx)
457 secilcCmd := rule.Command().BuiltTool("secilc").
458 Flag("-m"). // Multiple decls
459 FlagWithArg("-M ", "true"). // Enable MLS
460 Flag("-G"). // expand and remove auto generated attributes
461 FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
462 Inputs(android.PathsForModuleSrc(ctx, c.properties.Srcs)).
463 FlagWithOutput("-o ", bin).
464 FlagWithArg("-f ", os.DevNull)
465
466 if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) {
467 secilcCmd.Flag("-N")
468 }
Inseob Kim3d5f9252021-12-21 20:42:35 +0900469 rule.Temporary(bin)
Inseob Kimb9d05112021-09-27 13:13:46 +0000470
Inseob Kim3d5f9252021-12-21 20:42:35 +0900471 // permissive check is performed only in user build (not debuggable).
472 if !ctx.Config().Debuggable() {
473 permissiveDomains := android.PathForModuleOut(ctx, c.stem()+"_permissive")
474 rule.Command().BuiltTool("sepolicy-analyze").
475 Input(bin).
476 Text("permissive").
477 Text(" > ").
478 Output(permissiveDomains)
479 rule.Temporary(permissiveDomains)
480
481 msg := `==========\n` +
482 `ERROR: permissive domains not allowed in user builds\n` +
483 `List of invalid domains:`
484
485 rule.Command().Text("if test").
486 FlagWithInput("-s ", permissiveDomains).
487 Text("; then echo").
488 Flag("-e").
489 Text(`"` + msg + `"`).
490 Text("&& cat ").
491 Input(permissiveDomains).
492 Text("; exit 1; fi")
493 }
494
495 out := android.PathForModuleOut(ctx, c.stem())
496 rule.Command().Text("cp").
497 Flag("-f").
498 Input(bin).
499 Output(out)
500
501 rule.DeleteTemporaryFiles()
Inseob Kimb9d05112021-09-27 13:13:46 +0000502 rule.Build("secilc", "Compiling cil files for "+ctx.ModuleName())
503
504 if !c.Installable() {
505 c.SkipInstall()
506 }
507
508 c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
Inseob Kim3d5f9252021-12-21 20:42:35 +0900509 c.installSource = out
Inseob Kimb9d05112021-09-27 13:13:46 +0000510 ctx.InstallFile(c.installPath, c.stem(), c.installSource)
511}
512
513func (c *policyBinary) AndroidMkEntries() []android.AndroidMkEntries {
514 return []android.AndroidMkEntries{android.AndroidMkEntries{
515 OutputFile: android.OptionalPathForPath(c.installSource),
516 Class: "ETC",
517 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
518 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
519 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable())
520 entries.SetPath("LOCAL_MODULE_PATH", c.installPath.ToMakePath())
521 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
522 },
523 },
524 }}
525}
526
527func (c *policyBinary) OutputFiles(tag string) (android.Paths, error) {
528 if tag == "" {
529 return android.Paths{c.installSource}, nil
530 }
531 return nil, fmt.Errorf("Unknown tag %q", tag)
532}
533
534var _ android.OutputFileProducer = (*policyBinary)(nil)