• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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	"os"
19	"sort"
20	"strconv"
21	"strings"
22
23	"github.com/google/blueprint/proptools"
24
25	"android/soong/android"
26)
27
28const (
29	MlsSens    = 1
30	MlsCats    = 1024
31	PolicyVers = 30
32)
33
34// This order should be kept. checkpolicy syntax requires it.
35var policyConfOrder = []string{
36	"security_classes",
37	"initial_sids",
38	"access_vectors",
39	"global_macros",
40	"neverallow_macros",
41	"mls_macros",
42	"mls_decl",
43	"mls",
44	"policy_capabilities",
45	"te_macros",
46	"ioctl_defines",
47	"ioctl_macros",
48	"attributes|*.te",
49	"roles_decl",
50	"roles",
51	"users",
52	"initial_sid_contexts",
53	"fs_use",
54	"genfs_contexts",
55	"port_contexts",
56}
57
58func init() {
59	android.RegisterModuleType("se_policy_conf", policyConfFactory)
60	android.RegisterModuleType("se_policy_conf_defaults", policyConfDefaultFactory)
61	android.RegisterModuleType("se_policy_cil", policyCilFactory)
62	android.RegisterModuleType("se_policy_binary", policyBinaryFactory)
63}
64
65type policyConfProperties struct {
66	// Name of the output. Default is {module_name}
67	Stem *string
68
69	// Policy files to be compiled to cil file.
70	Srcs []string `android:"path"`
71
72	// Target build variant (user / userdebug / eng). Default follows the current lunch target
73	Build_variant *string
74
75	// Whether to exclude build test or not. Default is false
76	Exclude_build_test *bool
77
78	// Whether to include asan specific policies or not. Default follows the current lunch target
79	With_asan *bool
80
81	// Whether to build CTS specific policy or not. Default is false
82	Cts *bool
83
84	// Whether to build recovery specific policy or not. Default is false
85	Target_recovery *bool
86
87	// Whether this module is directly installable to one of the partitions. Default is true
88	Installable *bool
89
90	// Desired number of MLS categories. Defaults to 1024
91	Mls_cats *int64
92
93	// Whether to turn on board_api_level guard or not. Defaults to false
94	Board_api_level_guard *bool
95}
96
97type policyConf struct {
98	android.ModuleBase
99	android.DefaultableModuleBase
100	flaggableModuleBase
101
102	properties policyConfProperties
103
104	installSource android.Path
105	installPath   android.InstallPath
106}
107
108var _ flaggableModule = (*policyConf)(nil)
109
110// se_policy_conf merges collection of policy files into a policy.conf file to be processed by
111// checkpolicy.
112func policyConfFactory() android.Module {
113	c := &policyConf{}
114	c.AddProperties(&c.properties)
115	initFlaggableModule(c)
116	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
117	android.InitDefaultableModule(c)
118	return c
119}
120
121type policyConfDefaults struct {
122	android.ModuleBase
123	android.DefaultsModuleBase
124}
125
126// se_policy_conf_defaults provides a set of properties that can be inherited by other
127// se_policy_conf_defaults modules. A module can use the properties from a se_policy_conf_defaults
128// using `defaults: ["<:default_module_name>"]`. Properties of both modules are merged (when
129// possible) by prepending the default module's values to the depending module's values.
130func policyConfDefaultFactory() android.Module {
131	c := &policyConfDefaults{}
132	c.AddProperties(
133		&policyConfProperties{},
134		&flaggableModuleProperties{},
135	)
136	android.InitDefaultsModule(c)
137	return c
138}
139
140func (c *policyConf) installable() bool {
141	return proptools.BoolDefault(c.properties.Installable, true)
142}
143
144func (c *policyConf) stem() string {
145	return proptools.StringDefault(c.properties.Stem, c.Name())
146}
147
148func (c *policyConf) buildVariant(ctx android.ModuleContext) string {
149	if variant := proptools.String(c.properties.Build_variant); variant != "" {
150		return variant
151	}
152	if ctx.Config().Eng() {
153		return "eng"
154	}
155	if ctx.Config().Debuggable() {
156		return "userdebug"
157	}
158	return "user"
159}
160
161func (c *policyConf) cts() bool {
162	return proptools.Bool(c.properties.Cts)
163}
164
165func (c *policyConf) isTargetRecovery() bool {
166	return proptools.Bool(c.properties.Target_recovery)
167}
168
169func (c *policyConf) withAsan(ctx android.ModuleContext) string {
170	isAsanDevice := android.InList("address", ctx.Config().SanitizeDevice())
171	return strconv.FormatBool(proptools.BoolDefault(c.properties.With_asan, isAsanDevice))
172}
173
174func (c *policyConf) sepolicySplit(ctx android.ModuleContext) string {
175	if c.cts() {
176		return "cts"
177	}
178	if c.isTargetRecovery() {
179		return "false"
180	}
181	return strconv.FormatBool(true)
182}
183
184func (c *policyConf) compatibleProperty(ctx android.ModuleContext) string {
185	if c.cts() {
186		return "cts"
187	}
188	if c.isTargetRecovery() {
189		return "false"
190	}
191	return "true"
192}
193
194func (c *policyConf) trebleSyspropNeverallow(ctx android.ModuleContext) string {
195	if c.cts() {
196		return "cts"
197	}
198	if c.isTargetRecovery() {
199		return "false"
200	}
201	return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenTrebleSyspropNeverallow())
202}
203
204func (c *policyConf) enforceSyspropOwner(ctx android.ModuleContext) string {
205	if c.cts() {
206		return "cts"
207	}
208	if c.isTargetRecovery() {
209		return "false"
210	}
211	return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenEnforceSyspropOwner())
212}
213
214func (c *policyConf) enforceDebugfsRestrictions(ctx android.ModuleContext) string {
215	if c.cts() {
216		return "cts"
217	}
218	return strconv.FormatBool(ctx.DeviceConfig().BuildDebugfsRestrictionsEnabled())
219}
220
221func (c *policyConf) mlsCats() int {
222	return proptools.IntDefault(c.properties.Mls_cats, MlsCats)
223}
224
225func (c *policyConf) boardApiLevel(ctx android.ModuleContext) string {
226	if proptools.Bool(c.properties.Board_api_level_guard) {
227		return ctx.Config().VendorApiLevel()
228	}
229	// aribtrary value greater than any other vendor API levels
230	return "1000000"
231}
232
233func findPolicyConfOrder(name string) int {
234	for idx, pattern := range policyConfOrder {
235		// We could use regexp but it seems like an overkill
236		if pattern == "attributes|*.te" && (name == "attributes" || strings.HasSuffix(name, ".te")) {
237			return idx
238		} else if pattern == name {
239			return idx
240		}
241	}
242	// name is not matched
243	return len(policyConfOrder)
244}
245
246func (c *policyConf) transformPolicyToConf(ctx android.ModuleContext) android.OutputPath {
247	conf := pathForModuleOut(ctx, c.stem())
248	rule := android.NewRuleBuilder(pctx, ctx)
249
250	srcs := android.PathsForModuleSrc(ctx, c.properties.Srcs)
251	sort.SliceStable(srcs, func(x, y int) bool {
252		return findPolicyConfOrder(srcs[x].Base()) < findPolicyConfOrder(srcs[y].Base())
253	})
254
255	flags := c.getBuildFlags(ctx)
256	rule.Command().Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
257		Flag("--fatal-warnings").
258		FlagForEachArg("-D ", ctx.DeviceConfig().SepolicyM4Defs()).
259		FlagWithArg("-D mls_num_sens=", strconv.Itoa(MlsSens)).
260		FlagWithArg("-D mls_num_cats=", strconv.Itoa(c.mlsCats())).
261		FlagWithArg("-D target_arch=", ctx.DeviceConfig().DeviceArch()).
262		FlagWithArg("-D target_with_asan=", c.withAsan(ctx)).
263		FlagWithArg("-D target_with_dexpreopt=", strconv.FormatBool(ctx.DeviceConfig().WithDexpreopt())).
264		FlagWithArg("-D target_with_native_coverage=", strconv.FormatBool(ctx.DeviceConfig().ClangCoverageEnabled() || ctx.DeviceConfig().GcovCoverageEnabled())).
265		FlagWithArg("-D target_build_variant=", c.buildVariant(ctx)).
266		FlagWithArg("-D target_full_treble=", c.sepolicySplit(ctx)).
267		FlagWithArg("-D target_compatible_property=", c.compatibleProperty(ctx)).
268		FlagWithArg("-D target_treble_sysprop_neverallow=", c.trebleSyspropNeverallow(ctx)).
269		FlagWithArg("-D target_enforce_sysprop_owner=", c.enforceSyspropOwner(ctx)).
270		FlagWithArg("-D target_exclude_build_test=", strconv.FormatBool(proptools.Bool(c.properties.Exclude_build_test))).
271		FlagWithArg("-D target_requires_insecure_execmem_for_swiftshader=", strconv.FormatBool(ctx.DeviceConfig().RequiresInsecureExecmemForSwiftshader())).
272		FlagWithArg("-D target_enforce_debugfs_restriction=", c.enforceDebugfsRestrictions(ctx)).
273		FlagWithArg("-D target_recovery=", strconv.FormatBool(c.isTargetRecovery())).
274		FlagWithArg("-D target_board_api_level=", c.boardApiLevel(ctx)).
275		Flags(flagsToM4Macros(flags)).
276		Flag("-s").
277		Inputs(srcs).
278		Text("> ").Output(conf)
279
280	rule.Build("conf", "Transform policy to conf: "+ctx.ModuleName())
281	return conf
282}
283
284func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) {
285	c.flagDeps(ctx)
286}
287
288func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
289	if !c.installable() {
290		c.SkipInstall()
291	}
292
293	c.installSource = c.transformPolicyToConf(ctx)
294	c.installPath = android.PathForModuleInstall(ctx, "etc")
295	ctx.InstallFile(c.installPath, c.stem(), c.installSource)
296
297	ctx.SetOutputFiles(android.Paths{c.installSource}, "")
298}
299
300func (c *policyConf) AndroidMkEntries() []android.AndroidMkEntries {
301	return []android.AndroidMkEntries{android.AndroidMkEntries{
302		OutputFile: android.OptionalPathForPath(c.installSource),
303		Class:      "ETC",
304		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
305			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
306				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.installable())
307				entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
308				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
309			},
310		},
311	}}
312}
313
314type policyCilProperties struct {
315	// Name of the output. Default is {module_name}
316	Stem *string
317
318	// Policy file to be compiled to cil file.
319	Src *string `android:"path"`
320
321	// If true, the input policy file is a binary policy that will be decompiled to a cil file.
322	// Defaults to false.
323	Decompile_binary *bool
324
325	// Additional cil files to be added in the end of the output. This is to support workarounds
326	// which are not supported by the policy language.
327	Additional_cil_files []string `android:"path"`
328
329	// Cil files to be filtered out by the filter_out tool of "build_sepolicy". Used to build
330	// exported policies
331	Filter_out []string `android:"path"`
332
333	// Whether to remove line markers (denoted by ;;) out of compiled cil files. Defaults to false
334	Remove_line_marker *bool
335
336	// Whether to run secilc to check compiled policy or not. Defaults to true
337	Secilc_check *bool
338
339	// Whether to ignore neverallow when running secilc check. Defaults to
340	// SELINUX_IGNORE_NEVERALLOWS.
341	Ignore_neverallow *bool
342
343	// Whether this module is directly installable to one of the partitions. Default is true
344	Installable *bool
345}
346
347type policyCil struct {
348	android.ModuleBase
349
350	properties policyCilProperties
351
352	installSource android.Path
353	installPath   android.InstallPath
354}
355
356// se_policy_cil compiles a policy.conf file to a cil file with checkpolicy, and optionally runs
357// secilc to check the output cil file. Affected by SELINUX_IGNORE_NEVERALLOWS.
358func policyCilFactory() android.Module {
359	c := &policyCil{}
360	c.AddProperties(&c.properties)
361	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
362	return c
363}
364
365func (c *policyCil) Installable() bool {
366	return proptools.BoolDefault(c.properties.Installable, true)
367}
368
369func (c *policyCil) stem() string {
370	return proptools.StringDefault(c.properties.Stem, c.Name())
371}
372
373func (c *policyCil) compileConfToCil(ctx android.ModuleContext, conf android.Path) android.OutputPath {
374	cil := pathForModuleOut(ctx, c.stem())
375	rule := android.NewRuleBuilder(pctx, ctx)
376	checkpolicyCmd := rule.Command().BuiltTool("checkpolicy").
377		Flag("-C"). // Write CIL
378		Flag("-M"). // Enable MLS
379		FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
380		FlagWithOutput("-o ", cil).
381		Input(conf)
382
383	if proptools.Bool(c.properties.Decompile_binary) {
384		checkpolicyCmd.Flag("-b") // Read binary
385	}
386
387	if len(c.properties.Filter_out) > 0 {
388		rule.Command().BuiltTool("build_sepolicy").
389			Text("filter_out").
390			Flag("-f").
391			Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)).
392			FlagWithOutput("-t ", cil)
393	}
394
395	if len(c.properties.Additional_cil_files) > 0 {
396		rule.Command().Text("cat").
397			Inputs(android.PathsForModuleSrc(ctx, c.properties.Additional_cil_files)).
398			Text(">> ").Output(cil)
399	}
400
401	if proptools.Bool(c.properties.Remove_line_marker) {
402		rule.Command().Text("grep -v").
403			Text(proptools.ShellEscape(";;")).
404			Text(cil.String()).
405			Text(">").
406			Text(cil.String() + ".tmp").
407			Text("&& mv").
408			Text(cil.String() + ".tmp").
409			Text(cil.String())
410	}
411
412	if proptools.BoolDefault(c.properties.Secilc_check, true) {
413		secilcCmd := rule.Command().BuiltTool("secilc").
414			Flag("-m").                 // Multiple decls
415			FlagWithArg("-M ", "true"). // Enable MLS
416			Flag("-G").                 // expand and remove auto generated attributes
417			FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
418			Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). // Also add cil files which are filtered out
419			Text(cil.String()).
420			FlagWithArg("-o ", os.DevNull).
421			FlagWithArg("-f ", os.DevNull)
422
423		if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) {
424			secilcCmd.Flag("-N")
425		}
426	}
427
428	rule.Build("cil", "Building cil for "+ctx.ModuleName())
429	return cil
430}
431
432func (c *policyCil) GenerateAndroidBuildActions(ctx android.ModuleContext) {
433	if proptools.String(c.properties.Src) == "" {
434		ctx.PropertyErrorf("src", "must be specified")
435		return
436	}
437	conf := android.PathForModuleSrc(ctx, *c.properties.Src)
438	cil := c.compileConfToCil(ctx, conf)
439
440	if !c.Installable() {
441		c.SkipInstall()
442	}
443
444	if c.InstallInDebugRamdisk() {
445		// for userdebug_plat_sepolicy.cil
446		c.installPath = android.PathForModuleInstall(ctx)
447	} else {
448		c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
449	}
450	c.installSource = cil
451	ctx.InstallFile(c.installPath, c.stem(), c.installSource)
452
453	ctx.SetOutputFiles(android.Paths{c.installSource}, "")
454}
455
456func (c *policyCil) AndroidMkEntries() []android.AndroidMkEntries {
457	return []android.AndroidMkEntries{android.AndroidMkEntries{
458		OutputFile: android.OptionalPathForPath(c.installSource),
459		Class:      "ETC",
460		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
461			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
462				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable())
463				entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
464				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
465			},
466		},
467	}}
468}
469
470type policyBinaryProperties struct {
471	// Name of the output. Default is {module_name}
472	Stem *string
473
474	// Cil files to be compiled.
475	Srcs []string `android:"path"`
476
477	// Whether to ignore neverallow when running secilc check. Defaults to
478	// SELINUX_IGNORE_NEVERALLOWS.
479	Ignore_neverallow *bool
480
481	// Whether this module is directly installable to one of the partitions. Default is true
482	Installable *bool
483
484	// List of domains that are allowed to be in permissive mode on user builds.
485	Permissive_domains_on_user_builds []string
486}
487
488type policyBinary struct {
489	android.ModuleBase
490
491	properties policyBinaryProperties
492
493	installSource android.Path
494	installPath   android.InstallPath
495}
496
497// se_policy_binary compiles cil files to a binary sepolicy file with secilc.  Usually sources of
498// se_policy_binary come from outputs of se_policy_cil modules.
499func policyBinaryFactory() android.Module {
500	c := &policyBinary{}
501	c.AddProperties(&c.properties)
502	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
503	return c
504}
505
506func (c *policyBinary) InstallInRoot() bool {
507	return c.InstallInRecovery()
508}
509
510func (c *policyBinary) Installable() bool {
511	return proptools.BoolDefault(c.properties.Installable, true)
512}
513
514func (c *policyBinary) stem() string {
515	return proptools.StringDefault(c.properties.Stem, c.Name())
516}
517
518func (c *policyBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
519	if len(c.properties.Srcs) == 0 {
520		ctx.PropertyErrorf("srcs", "must be specified")
521		return
522	}
523	bin := pathForModuleOut(ctx, c.stem()+"_policy")
524	rule := android.NewRuleBuilder(pctx, ctx)
525	secilcCmd := rule.Command().BuiltTool("secilc").
526		Flag("-m").                 // Multiple decls
527		FlagWithArg("-M ", "true"). // Enable MLS
528		Flag("-G").                 // expand and remove auto generated attributes
529		FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
530		Inputs(android.PathsForModuleSrc(ctx, c.properties.Srcs)).
531		FlagWithOutput("-o ", bin).
532		FlagWithArg("-f ", os.DevNull)
533
534	if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) {
535		secilcCmd.Flag("-N")
536	}
537	rule.Temporary(bin)
538
539	// permissive check is performed only in user build (not debuggable).
540	if !ctx.Config().Debuggable() {
541		permissiveDomains := pathForModuleOut(ctx, c.stem()+"_permissive")
542		cmd := rule.Command().BuiltTool("sepolicy-analyze").
543			Input(bin).
544			Text("permissive")
545		// Filter-out domains listed in permissive_domains_on_user_builds
546		allowedDomains := c.properties.Permissive_domains_on_user_builds
547		if len(allowedDomains) != 0 {
548			cmd.Text("| { grep -Fxv")
549			for _, d := range allowedDomains {
550				cmd.FlagWithArg("-e ", proptools.ShellEscape(d))
551			}
552			cmd.Text(" || true; }") // no match doesn't fail the cmd
553		}
554		cmd.Text(" > ").Output(permissiveDomains)
555		rule.Temporary(permissiveDomains)
556
557		msg := `==========\n` +
558			`ERROR: permissive domains not allowed in user builds\n` +
559			`List of invalid domains:`
560
561		rule.Command().Text("if test").
562			FlagWithInput("-s ", permissiveDomains).
563			Text("; then echo").
564			Flag("-e").
565			Text(`"` + msg + `"`).
566			Text("&& cat ").
567			Input(permissiveDomains).
568			Text("; exit 1; fi")
569	}
570
571	out := pathForModuleOut(ctx, c.stem())
572	rule.Command().Text("cp").
573		Flag("-f").
574		Input(bin).
575		Output(out)
576
577	rule.DeleteTemporaryFiles()
578	rule.Build("secilc", "Compiling cil files for "+ctx.ModuleName())
579
580	if !c.Installable() {
581		c.SkipInstall()
582	}
583
584	if c.InstallInRecovery() {
585		// install in root
586		c.installPath = android.PathForModuleInstall(ctx)
587	} else {
588		c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
589	}
590	c.installSource = out
591	ctx.InstallFile(c.installPath, c.stem(), c.installSource)
592
593	ctx.SetOutputFiles(android.Paths{c.installSource}, "")
594}
595
596func (c *policyBinary) AndroidMkEntries() []android.AndroidMkEntries {
597	return []android.AndroidMkEntries{android.AndroidMkEntries{
598		OutputFile: android.OptionalPathForPath(c.installSource),
599		Class:      "ETC",
600		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
601			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
602				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable())
603				entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
604				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
605			},
606		},
607	}}
608}
609