• 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	"fmt"
19	"os"
20	"sort"
21	"strconv"
22	"strings"
23
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
36// 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
61func init() {
62	android.RegisterModuleType("se_policy_conf", policyConfFactory)
63	android.RegisterModuleType("se_policy_cil", policyCilFactory)
64	android.RegisterModuleType("se_policy_binary", policyBinaryFactory)
65}
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 to build recovery specific policy or not. Default is false
87	Target_recovery *bool
88
89	// Whether this module is directly installable to one of the partitions. Default is true
90	Installable *bool
91
92	// Desired number of MLS categories. Defaults to 1024
93	Mls_cats *int64
94}
95
96type policyConf struct {
97	android.ModuleBase
98
99	properties policyConfProperties
100
101	installSource android.Path
102	installPath   android.InstallPath
103}
104
105// se_policy_conf merges collection of policy files into a policy.conf file to be processed by
106// checkpolicy.
107func policyConfFactory() android.Module {
108	c := &policyConf{}
109	c.AddProperties(&c.properties)
110	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
111	return c
112}
113
114func (c *policyConf) installable() bool {
115	return proptools.BoolDefault(c.properties.Installable, true)
116}
117
118func (c *policyConf) stem() string {
119	return proptools.StringDefault(c.properties.Stem, c.Name())
120}
121
122func (c *policyConf) buildVariant(ctx android.ModuleContext) string {
123	if variant := proptools.String(c.properties.Build_variant); variant != "" {
124		return variant
125	}
126	if ctx.Config().Eng() {
127		return "eng"
128	}
129	if ctx.Config().Debuggable() {
130		return "userdebug"
131	}
132	return "user"
133}
134
135func (c *policyConf) cts() bool {
136	return proptools.Bool(c.properties.Cts)
137}
138
139func (c *policyConf) isTargetRecovery() bool {
140	return proptools.Bool(c.properties.Target_recovery)
141}
142
143func (c *policyConf) withAsan(ctx android.ModuleContext) string {
144	isAsanDevice := android.InList("address", ctx.Config().SanitizeDevice())
145	return strconv.FormatBool(proptools.BoolDefault(c.properties.With_asan, isAsanDevice))
146}
147
148func (c *policyConf) sepolicySplit(ctx android.ModuleContext) string {
149	if c.cts() {
150		return "cts"
151	}
152	if c.isTargetRecovery() {
153		return "false"
154	}
155	return strconv.FormatBool(ctx.DeviceConfig().SepolicySplit())
156}
157
158func (c *policyConf) compatibleProperty(ctx android.ModuleContext) string {
159	if c.cts() {
160		return "cts"
161	}
162	if c.isTargetRecovery() {
163		return "false"
164	}
165	return "true"
166}
167
168func (c *policyConf) trebleSyspropNeverallow(ctx android.ModuleContext) string {
169	if c.cts() {
170		return "cts"
171	}
172	if c.isTargetRecovery() {
173		return "false"
174	}
175	return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenTrebleSyspropNeverallow())
176}
177
178func (c *policyConf) enforceSyspropOwner(ctx android.ModuleContext) string {
179	if c.cts() {
180		return "cts"
181	}
182	if c.isTargetRecovery() {
183		return "false"
184	}
185	return strconv.FormatBool(!ctx.DeviceConfig().BuildBrokenEnforceSyspropOwner())
186}
187
188func (c *policyConf) enforceDebugfsRestrictions(ctx android.ModuleContext) string {
189	if c.cts() {
190		return "cts"
191	}
192	return strconv.FormatBool(ctx.DeviceConfig().BuildDebugfsRestrictionsEnabled())
193}
194
195func (c *policyConf) mlsCats() int {
196	return proptools.IntDefault(c.properties.Mls_cats, MlsCats)
197}
198
199func findPolicyConfOrder(name string) int {
200	for idx, pattern := range policyConfOrder {
201		if pattern == name || (pattern == "*.te" && strings.HasSuffix(name, ".te")) {
202			return idx
203		}
204	}
205	// name is not matched
206	return len(policyConfOrder)
207}
208
209func (c *policyConf) transformPolicyToConf(ctx android.ModuleContext) android.OutputPath {
210	conf := android.PathForModuleOut(ctx, c.stem()).OutputPath
211	rule := android.NewRuleBuilder(pctx, ctx)
212
213	srcs := android.PathsForModuleSrc(ctx, c.properties.Srcs)
214	sort.SliceStable(srcs, func(x, y int) bool {
215		return findPolicyConfOrder(srcs[x].Base()) < findPolicyConfOrder(srcs[y].Base())
216	})
217
218	rule.Command().Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
219		Flag("--fatal-warnings").
220		FlagForEachArg("-D ", ctx.DeviceConfig().SepolicyM4Defs()).
221		FlagWithArg("-D mls_num_sens=", strconv.Itoa(MlsSens)).
222		FlagWithArg("-D mls_num_cats=", strconv.Itoa(c.mlsCats())).
223		FlagWithArg("-D target_arch=", ctx.DeviceConfig().DeviceArch()).
224		FlagWithArg("-D target_with_asan=", c.withAsan(ctx)).
225		FlagWithArg("-D target_with_dexpreopt=", strconv.FormatBool(ctx.DeviceConfig().WithDexpreopt())).
226		FlagWithArg("-D target_with_native_coverage=", strconv.FormatBool(ctx.DeviceConfig().ClangCoverageEnabled() || ctx.DeviceConfig().GcovCoverageEnabled())).
227		FlagWithArg("-D target_build_variant=", c.buildVariant(ctx)).
228		FlagWithArg("-D target_full_treble=", c.sepolicySplit(ctx)).
229		FlagWithArg("-D target_compatible_property=", c.compatibleProperty(ctx)).
230		FlagWithArg("-D target_treble_sysprop_neverallow=", c.trebleSyspropNeverallow(ctx)).
231		FlagWithArg("-D target_enforce_sysprop_owner=", c.enforceSyspropOwner(ctx)).
232		FlagWithArg("-D target_exclude_build_test=", strconv.FormatBool(proptools.Bool(c.properties.Exclude_build_test))).
233		FlagWithArg("-D target_requires_insecure_execmem_for_swiftshader=", strconv.FormatBool(ctx.DeviceConfig().RequiresInsecureExecmemForSwiftshader())).
234		FlagWithArg("-D target_enforce_debugfs_restriction=", c.enforceDebugfsRestrictions(ctx)).
235		FlagWithArg("-D target_recovery=", strconv.FormatBool(c.isTargetRecovery())).
236		Flag("-s").
237		Inputs(srcs).
238		Text("> ").Output(conf)
239
240	rule.Build("conf", "Transform policy to conf: "+ctx.ModuleName())
241	return conf
242}
243
244func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) {
245	// do nothing
246}
247
248func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
249	if !c.installable() {
250		c.SkipInstall()
251	}
252
253	c.installSource = c.transformPolicyToConf(ctx)
254	c.installPath = android.PathForModuleInstall(ctx, "etc")
255	ctx.InstallFile(c.installPath, c.stem(), c.installSource)
256}
257
258func (c *policyConf) AndroidMkEntries() []android.AndroidMkEntries {
259	return []android.AndroidMkEntries{android.AndroidMkEntries{
260		OutputFile: android.OptionalPathForPath(c.installSource),
261		Class:      "ETC",
262		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
263			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
264				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.installable())
265				entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
266				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
267			},
268		},
269	}}
270}
271
272func (c *policyConf) OutputFiles(tag string) (android.Paths, error) {
273	if tag == "" {
274		return android.Paths{c.installSource}, nil
275	}
276	return nil, fmt.Errorf("Unknown tag %q", tag)
277}
278
279var _ android.OutputFileProducer = (*policyConf)(nil)
280
281type policyCilProperties struct {
282	// Name of the output. Default is {module_name}
283	Stem *string
284
285	// Policy file to be compiled to cil file.
286	Src *string `android:"path"`
287
288	// Additional cil files to be added in the end of the output. This is to support workarounds
289	// which are not supported by the policy language.
290	Additional_cil_files []string `android:"path"`
291
292	// Cil files to be filtered out by the filter_out tool of "build_sepolicy". Used to build
293	// exported policies
294	Filter_out []string `android:"path"`
295
296	// Whether to remove line markers (denoted by ;;) out of compiled cil files. Defaults to false
297	Remove_line_marker *bool
298
299	// Whether to run secilc to check compiled policy or not. Defaults to true
300	Secilc_check *bool
301
302	// Whether to ignore neverallow when running secilc check. Defaults to
303	// SELINUX_IGNORE_NEVERALLOWS.
304	Ignore_neverallow *bool
305
306	// Whether this module is directly installable to one of the partitions. Default is true
307	Installable *bool
308}
309
310type policyCil struct {
311	android.ModuleBase
312
313	properties policyCilProperties
314
315	installSource android.Path
316	installPath   android.InstallPath
317}
318
319// se_policy_cil compiles a policy.conf file to a cil file with checkpolicy, and optionally runs
320// secilc to check the output cil file. Affected by SELINUX_IGNORE_NEVERALLOWS.
321func policyCilFactory() android.Module {
322	c := &policyCil{}
323	c.AddProperties(&c.properties)
324	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
325	return c
326}
327
328func (c *policyCil) Installable() bool {
329	return proptools.BoolDefault(c.properties.Installable, true)
330}
331
332func (c *policyCil) stem() string {
333	return proptools.StringDefault(c.properties.Stem, c.Name())
334}
335
336func (c *policyCil) compileConfToCil(ctx android.ModuleContext, conf android.Path) android.OutputPath {
337	cil := android.PathForModuleOut(ctx, c.stem()).OutputPath
338	rule := android.NewRuleBuilder(pctx, ctx)
339	rule.Command().BuiltTool("checkpolicy").
340		Flag("-C"). // Write CIL
341		Flag("-M"). // Enable MLS
342		FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
343		FlagWithOutput("-o ", cil).
344		Input(conf)
345
346	if len(c.properties.Additional_cil_files) > 0 {
347		rule.Command().Text("cat").
348			Inputs(android.PathsForModuleSrc(ctx, c.properties.Additional_cil_files)).
349			Text(">> ").Output(cil)
350	}
351
352	if len(c.properties.Filter_out) > 0 {
353		rule.Command().BuiltTool("build_sepolicy").
354			Text("filter_out").
355			Flag("-f").
356			Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)).
357			FlagWithOutput("-t ", cil)
358	}
359
360	if proptools.Bool(c.properties.Remove_line_marker) {
361		rule.Command().Text("grep -v").
362			Text(proptools.ShellEscape(";;")).
363			Text(cil.String()).
364			Text(">").
365			Text(cil.String() + ".tmp").
366			Text("&& mv").
367			Text(cil.String() + ".tmp").
368			Text(cil.String())
369	}
370
371	if proptools.BoolDefault(c.properties.Secilc_check, true) {
372		secilcCmd := rule.Command().BuiltTool("secilc").
373			Flag("-m").                 // Multiple decls
374			FlagWithArg("-M ", "true"). // Enable MLS
375			Flag("-G").                 // expand and remove auto generated attributes
376			FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
377			Inputs(android.PathsForModuleSrc(ctx, c.properties.Filter_out)). // Also add cil files which are filtered out
378			Text(cil.String()).
379			FlagWithArg("-o ", os.DevNull).
380			FlagWithArg("-f ", os.DevNull)
381
382		if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) {
383			secilcCmd.Flag("-N")
384		}
385	}
386
387	rule.Build("cil", "Building cil for "+ctx.ModuleName())
388	return cil
389}
390
391func (c *policyCil) GenerateAndroidBuildActions(ctx android.ModuleContext) {
392	if proptools.String(c.properties.Src) == "" {
393		ctx.PropertyErrorf("src", "must be specified")
394		return
395	}
396	conf := android.PathForModuleSrc(ctx, *c.properties.Src)
397	cil := c.compileConfToCil(ctx, conf)
398
399	if !c.Installable() {
400		c.SkipInstall()
401	}
402
403	if c.InstallInDebugRamdisk() {
404		// for userdebug_plat_sepolicy.cil
405		c.installPath = android.PathForModuleInstall(ctx)
406	} else {
407		c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
408	}
409	c.installSource = cil
410	ctx.InstallFile(c.installPath, c.stem(), c.installSource)
411}
412
413func (c *policyCil) AndroidMkEntries() []android.AndroidMkEntries {
414	return []android.AndroidMkEntries{android.AndroidMkEntries{
415		OutputFile: android.OptionalPathForPath(c.installSource),
416		Class:      "ETC",
417		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
418			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
419				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable())
420				entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
421				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
422			},
423		},
424	}}
425}
426
427func (c *policyCil) OutputFiles(tag string) (android.Paths, error) {
428	if tag == "" {
429		return android.Paths{c.installSource}, nil
430	}
431	return nil, fmt.Errorf("Unknown tag %q", tag)
432}
433
434var _ android.OutputFileProducer = (*policyCil)(nil)
435
436type policyBinaryProperties struct {
437	// Name of the output. Default is {module_name}
438	Stem *string
439
440	// Cil files to be compiled.
441	Srcs []string `android:"path"`
442
443	// Whether to ignore neverallow when running secilc check. Defaults to
444	// SELINUX_IGNORE_NEVERALLOWS.
445	Ignore_neverallow *bool
446
447	// Whether this module is directly installable to one of the partitions. Default is true
448	Installable *bool
449}
450
451type policyBinary struct {
452	android.ModuleBase
453
454	properties policyBinaryProperties
455
456	installSource android.Path
457	installPath   android.InstallPath
458}
459
460// se_policy_binary compiles cil files to a binary sepolicy file with secilc.  Usually sources of
461// se_policy_binary come from outputs of se_policy_cil modules.
462func policyBinaryFactory() android.Module {
463	c := &policyBinary{}
464	c.AddProperties(&c.properties)
465	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
466	return c
467}
468
469func (c *policyBinary) InstallInRoot() bool {
470	return c.InstallInRecovery()
471}
472
473func (c *policyBinary) Installable() bool {
474	return proptools.BoolDefault(c.properties.Installable, true)
475}
476
477func (c *policyBinary) stem() string {
478	return proptools.StringDefault(c.properties.Stem, c.Name())
479}
480
481func (c *policyBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
482	if len(c.properties.Srcs) == 0 {
483		ctx.PropertyErrorf("srcs", "must be specified")
484		return
485	}
486	bin := android.PathForModuleOut(ctx, c.stem()+"_policy")
487	rule := android.NewRuleBuilder(pctx, ctx)
488	secilcCmd := rule.Command().BuiltTool("secilc").
489		Flag("-m").                 // Multiple decls
490		FlagWithArg("-M ", "true"). // Enable MLS
491		Flag("-G").                 // expand and remove auto generated attributes
492		FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
493		Inputs(android.PathsForModuleSrc(ctx, c.properties.Srcs)).
494		FlagWithOutput("-o ", bin).
495		FlagWithArg("-f ", os.DevNull)
496
497	if proptools.BoolDefault(c.properties.Ignore_neverallow, ctx.Config().SelinuxIgnoreNeverallows()) {
498		secilcCmd.Flag("-N")
499	}
500	rule.Temporary(bin)
501
502	// permissive check is performed only in user build (not debuggable).
503	if !ctx.Config().Debuggable() {
504		permissiveDomains := android.PathForModuleOut(ctx, c.stem()+"_permissive")
505		rule.Command().BuiltTool("sepolicy-analyze").
506			Input(bin).
507			Text("permissive").
508			Text(" > ").
509			Output(permissiveDomains)
510		rule.Temporary(permissiveDomains)
511
512		msg := `==========\n` +
513			`ERROR: permissive domains not allowed in user builds\n` +
514			`List of invalid domains:`
515
516		rule.Command().Text("if test").
517			FlagWithInput("-s ", permissiveDomains).
518			Text("; then echo").
519			Flag("-e").
520			Text(`"` + msg + `"`).
521			Text("&& cat ").
522			Input(permissiveDomains).
523			Text("; exit 1; fi")
524	}
525
526	out := android.PathForModuleOut(ctx, c.stem())
527	rule.Command().Text("cp").
528		Flag("-f").
529		Input(bin).
530		Output(out)
531
532	rule.DeleteTemporaryFiles()
533	rule.Build("secilc", "Compiling cil files for "+ctx.ModuleName())
534
535	if !c.Installable() {
536		c.SkipInstall()
537	}
538
539	if c.InstallInRecovery() {
540		// install in root
541		c.installPath = android.PathForModuleInstall(ctx)
542	} else {
543		c.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
544	}
545	c.installSource = out
546	ctx.InstallFile(c.installPath, c.stem(), c.installSource)
547}
548
549func (c *policyBinary) AndroidMkEntries() []android.AndroidMkEntries {
550	return []android.AndroidMkEntries{android.AndroidMkEntries{
551		OutputFile: android.OptionalPathForPath(c.installSource),
552		Class:      "ETC",
553		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
554			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
555				entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !c.Installable())
556				entries.SetPath("LOCAL_MODULE_PATH", c.installPath)
557				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", c.stem())
558			},
559		},
560	}}
561}
562
563func (c *policyBinary) OutputFiles(tag string) (android.Paths, error) {
564	if tag == "" {
565		return android.Paths{c.installSource}, nil
566	}
567	return nil, fmt.Errorf("Unknown tag %q", tag)
568}
569
570var _ android.OutputFileProducer = (*policyBinary)(nil)
571