xref: /aosp_15_r20/system/sepolicy/build/soong/sepolicy_neverallow.go (revision e4a36f4174b17bbab9dc043f4a65dc8d87377290)
1*e4a36f41SAndroid Build Coastguard Worker// Copyright 2021 The Android Open Source Project
2*e4a36f41SAndroid Build Coastguard Worker//
3*e4a36f41SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*e4a36f41SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*e4a36f41SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*e4a36f41SAndroid Build Coastguard Worker//
7*e4a36f41SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*e4a36f41SAndroid Build Coastguard Worker//
9*e4a36f41SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*e4a36f41SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*e4a36f41SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e4a36f41SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*e4a36f41SAndroid Build Coastguard Worker// limitations under the License.
14*e4a36f41SAndroid Build Coastguard Worker
15*e4a36f41SAndroid Build Coastguard Workerpackage selinux
16*e4a36f41SAndroid Build Coastguard Worker
17*e4a36f41SAndroid Build Coastguard Workerimport (
18*e4a36f41SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
19*e4a36f41SAndroid Build Coastguard Worker
20*e4a36f41SAndroid Build Coastguard Worker	"fmt"
21*e4a36f41SAndroid Build Coastguard Worker	"strconv"
22*e4a36f41SAndroid Build Coastguard Worker
23*e4a36f41SAndroid Build Coastguard Worker	"android/soong/android"
24*e4a36f41SAndroid Build Coastguard Worker)
25*e4a36f41SAndroid Build Coastguard Worker
26*e4a36f41SAndroid Build Coastguard Workerfunc init() {
27*e4a36f41SAndroid Build Coastguard Worker	ctx := android.InitRegistrationContext
28*e4a36f41SAndroid Build Coastguard Worker	ctx.RegisterModuleType("se_neverallow_test", neverallowTestFactory)
29*e4a36f41SAndroid Build Coastguard Worker}
30*e4a36f41SAndroid Build Coastguard Worker
31*e4a36f41SAndroid Build Coastguard Workertype neverallowTestProperties struct {
32*e4a36f41SAndroid Build Coastguard Worker	// Default modules for conf
33*e4a36f41SAndroid Build Coastguard Worker	Defaults []string
34*e4a36f41SAndroid Build Coastguard Worker
35*e4a36f41SAndroid Build Coastguard Worker	// Policy files to be tested.
36*e4a36f41SAndroid Build Coastguard Worker	Srcs []string `android:"path"`
37*e4a36f41SAndroid Build Coastguard Worker}
38*e4a36f41SAndroid Build Coastguard Worker
39*e4a36f41SAndroid Build Coastguard Workertype neverallowTestModule struct {
40*e4a36f41SAndroid Build Coastguard Worker	android.ModuleBase
41*e4a36f41SAndroid Build Coastguard Worker	properties    neverallowTestProperties
42*e4a36f41SAndroid Build Coastguard Worker	testTimestamp android.OutputPath
43*e4a36f41SAndroid Build Coastguard Worker}
44*e4a36f41SAndroid Build Coastguard Worker
45*e4a36f41SAndroid Build Coastguard Workertype nameProperties struct {
46*e4a36f41SAndroid Build Coastguard Worker	Name *string
47*e4a36f41SAndroid Build Coastguard Worker}
48*e4a36f41SAndroid Build Coastguard Worker
49*e4a36f41SAndroid Build Coastguard Workervar checkpolicyTag = dependencyTag{name: "checkpolicy"}
50*e4a36f41SAndroid Build Coastguard Workervar sepolicyAnalyzeTag = dependencyTag{name: "sepolicy_analyze"}
51*e4a36f41SAndroid Build Coastguard Worker
52*e4a36f41SAndroid Build Coastguard Worker// se_neverallow_test builds given policy files and checks whether any neverallow violations exist.
53*e4a36f41SAndroid Build Coastguard Worker// This module creates two conf files, one with build test and one without build test. Policy with
54*e4a36f41SAndroid Build Coastguard Worker// build test will be compiled with checkpolicy, and policy without build test will be tested with
55*e4a36f41SAndroid Build Coastguard Worker// sepolicy-analyze's neverallow tool.  This module's check can be skipped by setting
56*e4a36f41SAndroid Build Coastguard Worker// SELINUX_IGNORE_NEVERALLOWS := true.
57*e4a36f41SAndroid Build Coastguard Workerfunc neverallowTestFactory() android.Module {
58*e4a36f41SAndroid Build Coastguard Worker	n := &neverallowTestModule{}
59*e4a36f41SAndroid Build Coastguard Worker	n.AddProperties(&n.properties)
60*e4a36f41SAndroid Build Coastguard Worker	android.InitAndroidArchModule(n, android.DeviceSupported, android.MultilibCommon)
61*e4a36f41SAndroid Build Coastguard Worker	android.AddLoadHook(n, func(ctx android.LoadHookContext) {
62*e4a36f41SAndroid Build Coastguard Worker		n.loadHook(ctx)
63*e4a36f41SAndroid Build Coastguard Worker	})
64*e4a36f41SAndroid Build Coastguard Worker	return n
65*e4a36f41SAndroid Build Coastguard Worker}
66*e4a36f41SAndroid Build Coastguard Worker
67*e4a36f41SAndroid Build Coastguard Worker// Child conf module name for checkpolicy test.
68*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) checkpolicyConfModuleName() string {
69*e4a36f41SAndroid Build Coastguard Worker	return n.Name() + ".checkpolicy.conf"
70*e4a36f41SAndroid Build Coastguard Worker}
71*e4a36f41SAndroid Build Coastguard Worker
72*e4a36f41SAndroid Build Coastguard Worker// Child conf module name for sepolicy-analyze test.
73*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) sepolicyAnalyzeConfModuleName() string {
74*e4a36f41SAndroid Build Coastguard Worker	return n.Name() + ".sepolicy_analyze.conf"
75*e4a36f41SAndroid Build Coastguard Worker}
76*e4a36f41SAndroid Build Coastguard Worker
77*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) loadHook(ctx android.LoadHookContext) {
78*e4a36f41SAndroid Build Coastguard Worker	checkpolicyConf := n.checkpolicyConfModuleName()
79*e4a36f41SAndroid Build Coastguard Worker	ctx.CreateModule(policyConfFactory, &nameProperties{
80*e4a36f41SAndroid Build Coastguard Worker		Name: proptools.StringPtr(checkpolicyConf),
81*e4a36f41SAndroid Build Coastguard Worker	}, &policyConfProperties{
82*e4a36f41SAndroid Build Coastguard Worker		Srcs:          n.properties.Srcs,
83*e4a36f41SAndroid Build Coastguard Worker		Build_variant: proptools.StringPtr("user"),
84*e4a36f41SAndroid Build Coastguard Worker		Installable:   proptools.BoolPtr(false),
85*e4a36f41SAndroid Build Coastguard Worker	}, &struct {
86*e4a36f41SAndroid Build Coastguard Worker		Defaults []string
87*e4a36f41SAndroid Build Coastguard Worker	}{
88*e4a36f41SAndroid Build Coastguard Worker		Defaults: n.properties.Defaults,
89*e4a36f41SAndroid Build Coastguard Worker	})
90*e4a36f41SAndroid Build Coastguard Worker
91*e4a36f41SAndroid Build Coastguard Worker	sepolicyAnalyzeConf := n.sepolicyAnalyzeConfModuleName()
92*e4a36f41SAndroid Build Coastguard Worker	ctx.CreateModule(policyConfFactory, &nameProperties{
93*e4a36f41SAndroid Build Coastguard Worker		Name: proptools.StringPtr(sepolicyAnalyzeConf),
94*e4a36f41SAndroid Build Coastguard Worker	}, &policyConfProperties{
95*e4a36f41SAndroid Build Coastguard Worker		Srcs:               n.properties.Srcs,
96*e4a36f41SAndroid Build Coastguard Worker		Build_variant:      proptools.StringPtr("user"),
97*e4a36f41SAndroid Build Coastguard Worker		Exclude_build_test: proptools.BoolPtr(true),
98*e4a36f41SAndroid Build Coastguard Worker		Installable:        proptools.BoolPtr(false),
99*e4a36f41SAndroid Build Coastguard Worker	}, &struct {
100*e4a36f41SAndroid Build Coastguard Worker		Defaults []string
101*e4a36f41SAndroid Build Coastguard Worker	}{
102*e4a36f41SAndroid Build Coastguard Worker		Defaults: n.properties.Defaults,
103*e4a36f41SAndroid Build Coastguard Worker	})
104*e4a36f41SAndroid Build Coastguard Worker}
105*e4a36f41SAndroid Build Coastguard Worker
106*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
107*e4a36f41SAndroid Build Coastguard Worker	ctx.AddDependency(n, checkpolicyTag, n.checkpolicyConfModuleName())
108*e4a36f41SAndroid Build Coastguard Worker	ctx.AddDependency(n, sepolicyAnalyzeTag, n.sepolicyAnalyzeConfModuleName())
109*e4a36f41SAndroid Build Coastguard Worker}
110*e4a36f41SAndroid Build Coastguard Worker
111*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
112*e4a36f41SAndroid Build Coastguard Worker	n.testTimestamp = pathForModuleOut(ctx, "timestamp")
113*e4a36f41SAndroid Build Coastguard Worker	if ctx.Config().SelinuxIgnoreNeverallows() {
114*e4a36f41SAndroid Build Coastguard Worker		// just touch
115*e4a36f41SAndroid Build Coastguard Worker		android.WriteFileRule(ctx, n.testTimestamp, "")
116*e4a36f41SAndroid Build Coastguard Worker		return
117*e4a36f41SAndroid Build Coastguard Worker	}
118*e4a36f41SAndroid Build Coastguard Worker
119*e4a36f41SAndroid Build Coastguard Worker	var checkpolicyConfPaths android.Paths
120*e4a36f41SAndroid Build Coastguard Worker	var sepolicyAnalyzeConfPaths android.Paths
121*e4a36f41SAndroid Build Coastguard Worker
122*e4a36f41SAndroid Build Coastguard Worker	ctx.VisitDirectDeps(func(child android.Module) {
123*e4a36f41SAndroid Build Coastguard Worker		depTag := ctx.OtherModuleDependencyTag(child)
124*e4a36f41SAndroid Build Coastguard Worker		if depTag != checkpolicyTag && depTag != sepolicyAnalyzeTag {
125*e4a36f41SAndroid Build Coastguard Worker			return
126*e4a36f41SAndroid Build Coastguard Worker		}
127*e4a36f41SAndroid Build Coastguard Worker
128*e4a36f41SAndroid Build Coastguard Worker		outputs := android.OutputFilesForModule(ctx, child, "")
129*e4a36f41SAndroid Build Coastguard Worker
130*e4a36f41SAndroid Build Coastguard Worker		switch ctx.OtherModuleDependencyTag(child) {
131*e4a36f41SAndroid Build Coastguard Worker		case checkpolicyTag:
132*e4a36f41SAndroid Build Coastguard Worker			checkpolicyConfPaths = outputs
133*e4a36f41SAndroid Build Coastguard Worker		case sepolicyAnalyzeTag:
134*e4a36f41SAndroid Build Coastguard Worker			sepolicyAnalyzeConfPaths = outputs
135*e4a36f41SAndroid Build Coastguard Worker		}
136*e4a36f41SAndroid Build Coastguard Worker	})
137*e4a36f41SAndroid Build Coastguard Worker
138*e4a36f41SAndroid Build Coastguard Worker	if len(checkpolicyConfPaths) != 1 {
139*e4a36f41SAndroid Build Coastguard Worker		panic(fmt.Errorf("Module %q should produce exactly one output", n.checkpolicyConfModuleName()))
140*e4a36f41SAndroid Build Coastguard Worker	}
141*e4a36f41SAndroid Build Coastguard Worker
142*e4a36f41SAndroid Build Coastguard Worker	if len(sepolicyAnalyzeConfPaths) != 1 {
143*e4a36f41SAndroid Build Coastguard Worker		panic(fmt.Errorf("Module %q should produce exactly one output", n.sepolicyAnalyzeConfModuleName()))
144*e4a36f41SAndroid Build Coastguard Worker	}
145*e4a36f41SAndroid Build Coastguard Worker
146*e4a36f41SAndroid Build Coastguard Worker	checkpolicyConfPath := checkpolicyConfPaths[0]
147*e4a36f41SAndroid Build Coastguard Worker	sepolicyAnalyzeConfPath := sepolicyAnalyzeConfPaths[0]
148*e4a36f41SAndroid Build Coastguard Worker
149*e4a36f41SAndroid Build Coastguard Worker	rule := android.NewRuleBuilder(pctx, ctx)
150*e4a36f41SAndroid Build Coastguard Worker
151*e4a36f41SAndroid Build Coastguard Worker	// Step 1. Build a binary policy from the conf file including build test
152*e4a36f41SAndroid Build Coastguard Worker	binaryPolicy := pathForModuleOut(ctx, "policy")
153*e4a36f41SAndroid Build Coastguard Worker	rule.Command().BuiltTool("checkpolicy").
154*e4a36f41SAndroid Build Coastguard Worker		Flag("-M").
155*e4a36f41SAndroid Build Coastguard Worker		FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
156*e4a36f41SAndroid Build Coastguard Worker		FlagWithOutput("-o ", binaryPolicy).
157*e4a36f41SAndroid Build Coastguard Worker		Input(checkpolicyConfPath)
158*e4a36f41SAndroid Build Coastguard Worker	rule.Build("neverallow_checkpolicy", "Neverallow check: "+ctx.ModuleName())
159*e4a36f41SAndroid Build Coastguard Worker
160*e4a36f41SAndroid Build Coastguard Worker	// Step 2. Run sepolicy-analyze with the conf file without the build test and binary policy
161*e4a36f41SAndroid Build Coastguard Worker	// file from Step 1
162*e4a36f41SAndroid Build Coastguard Worker	rule = android.NewRuleBuilder(pctx, ctx)
163*e4a36f41SAndroid Build Coastguard Worker	msg := `sepolicy-analyze failed. This is most likely due to the use\n` +
164*e4a36f41SAndroid Build Coastguard Worker		`of an expanded attribute in a neverallow assertion. Please fix\n` +
165*e4a36f41SAndroid Build Coastguard Worker		`the policy.`
166*e4a36f41SAndroid Build Coastguard Worker
167*e4a36f41SAndroid Build Coastguard Worker	rule.Command().BuiltTool("sepolicy-analyze").
168*e4a36f41SAndroid Build Coastguard Worker		Input(binaryPolicy).
169*e4a36f41SAndroid Build Coastguard Worker		Text("neverallow").
170*e4a36f41SAndroid Build Coastguard Worker		Flag("-w").
171*e4a36f41SAndroid Build Coastguard Worker		FlagWithInput("-f ", sepolicyAnalyzeConfPath).
172*e4a36f41SAndroid Build Coastguard Worker		Text("|| (echo").
173*e4a36f41SAndroid Build Coastguard Worker		Flag("-e").
174*e4a36f41SAndroid Build Coastguard Worker		Text(`"` + msg + `"`).
175*e4a36f41SAndroid Build Coastguard Worker		Text("; exit 1)")
176*e4a36f41SAndroid Build Coastguard Worker
177*e4a36f41SAndroid Build Coastguard Worker	rule.Command().Text("touch").Output(n.testTimestamp)
178*e4a36f41SAndroid Build Coastguard Worker	rule.Build("neverallow_sepolicy-analyze", "Neverallow check: "+ctx.ModuleName())
179*e4a36f41SAndroid Build Coastguard Worker}
180*e4a36f41SAndroid Build Coastguard Worker
181*e4a36f41SAndroid Build Coastguard Workerfunc (n *neverallowTestModule) AndroidMkEntries() []android.AndroidMkEntries {
182*e4a36f41SAndroid Build Coastguard Worker	return []android.AndroidMkEntries{android.AndroidMkEntries{
183*e4a36f41SAndroid Build Coastguard Worker		OutputFile: android.OptionalPathForPath(n.testTimestamp),
184*e4a36f41SAndroid Build Coastguard Worker		Class:      "FAKE",
185*e4a36f41SAndroid Build Coastguard Worker		Include:    "$(BUILD_PHONY_PACKAGE)",
186*e4a36f41SAndroid Build Coastguard Worker		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
187*e4a36f41SAndroid Build Coastguard Worker			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
188*e4a36f41SAndroid Build Coastguard Worker				entries.SetPath("LOCAL_ADDITIONAL_DEPENDENCIES", n.testTimestamp)
189*e4a36f41SAndroid Build Coastguard Worker			},
190*e4a36f41SAndroid Build Coastguard Worker		},
191*e4a36f41SAndroid Build Coastguard Worker	}}
192*e4a36f41SAndroid Build Coastguard Worker}
193