blob: 98dd3cf03fe785a6a54c248596ce51bb7f334c2c [file] [log] [blame]
Inseob Kim0de7fcc2021-12-22 23:06:53 +09001// Copyright 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 "github.com/google/blueprint/proptools"
19
20 "fmt"
21 "strconv"
22
23 "android/soong/android"
24)
25
26func init() {
27 ctx := android.InitRegistrationContext
28 ctx.RegisterModuleType("se_neverallow_test", neverallowTestFactory)
29}
30
31type neverallowTestProperties struct {
32 // Policy files to be tested.
33 Srcs []string `android:"path"`
34}
35
36type neverallowTestModule struct {
37 android.ModuleBase
38 properties neverallowTestProperties
39 testTimestamp android.ModuleOutPath
40}
41
42type nameProperties struct {
43 Name *string
44}
45
46var checkpolicyTag = dependencyTag{name: "checkpolicy"}
47var sepolicyAnalyzeTag = dependencyTag{name: "sepolicy_analyze"}
48
49// se_neverallow_test builds given policy files and checks whether any neverallow violations exist.
50// This module creates two conf files, one with build test and one without build test. Policy with
51// build test will be compiled with checkpolicy, and policy without build test will be tested with
52// sepolicy-analyze's neverallow tool. This module's check can be skipped by setting
53// SELINUX_IGNORE_NEVERALLOWS := true.
54func neverallowTestFactory() android.Module {
55 n := &neverallowTestModule{}
56 n.AddProperties(&n.properties)
57 android.InitAndroidModule(n)
58 android.AddLoadHook(n, func(ctx android.LoadHookContext) {
59 n.loadHook(ctx)
60 })
61 return n
62}
63
64// Child conf module name for checkpolicy test.
65func (n *neverallowTestModule) checkpolicyConfModuleName() string {
66 return n.Name() + ".checkpolicy.conf"
67}
68
69// Child conf module name for sepolicy-analyze test.
70func (n *neverallowTestModule) sepolicyAnalyzeConfModuleName() string {
71 return n.Name() + ".sepolicy_analyze.conf"
72}
73
74func (n *neverallowTestModule) loadHook(ctx android.LoadHookContext) {
75 checkpolicyConf := n.checkpolicyConfModuleName()
76 ctx.CreateModule(policyConfFactory, &nameProperties{
77 Name: proptools.StringPtr(checkpolicyConf),
78 }, &policyConfProperties{
79 Srcs: n.properties.Srcs,
80 Build_variant: proptools.StringPtr("user"),
81 Installable: proptools.BoolPtr(false),
82 })
83
84 sepolicyAnalyzeConf := n.sepolicyAnalyzeConfModuleName()
85 ctx.CreateModule(policyConfFactory, &nameProperties{
86 Name: proptools.StringPtr(sepolicyAnalyzeConf),
87 }, &policyConfProperties{
88 Srcs: n.properties.Srcs,
89 Build_variant: proptools.StringPtr("user"),
90 Exclude_build_test: proptools.BoolPtr(true),
91 Installable: proptools.BoolPtr(false),
92 })
93}
94
95func (n *neverallowTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
96 ctx.AddDependency(n, checkpolicyTag, n.checkpolicyConfModuleName())
97 ctx.AddDependency(n, sepolicyAnalyzeTag, n.sepolicyAnalyzeConfModuleName())
98}
99
100func (n *neverallowTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
101 n.testTimestamp = android.PathForModuleOut(ctx, "timestamp")
102 if ctx.Config().SelinuxIgnoreNeverallows() {
103 // just touch
104 android.WriteFileRule(ctx, n.testTimestamp, "")
105 return
106 }
107
108 var checkpolicyConfPaths android.Paths
109 var sepolicyAnalyzeConfPaths android.Paths
110
111 ctx.VisitDirectDeps(func(child android.Module) {
112 depTag := ctx.OtherModuleDependencyTag(child)
113 if depTag != checkpolicyTag && depTag != sepolicyAnalyzeTag {
114 return
115 }
116
117 o, ok := child.(android.OutputFileProducer)
118 if !ok {
119 panic(fmt.Errorf("Module %q isn't an OutputFileProducer", ctx.OtherModuleName(child)))
120 }
121
122 outputs, err := o.OutputFiles("")
123 if err != nil {
124 panic(fmt.Errorf("Module %q error while producing output: %v", ctx.OtherModuleName(child), err))
125 }
126
127 switch ctx.OtherModuleDependencyTag(child) {
128 case checkpolicyTag:
129 checkpolicyConfPaths = outputs
130 case sepolicyAnalyzeTag:
131 sepolicyAnalyzeConfPaths = outputs
132 }
133 })
134
135 if len(checkpolicyConfPaths) != 1 {
136 panic(fmt.Errorf("Module %q should produce exactly one output", n.checkpolicyConfModuleName()))
137 }
138
139 if len(sepolicyAnalyzeConfPaths) != 1 {
140 panic(fmt.Errorf("Module %q should produce exactly one output", n.sepolicyAnalyzeConfModuleName()))
141 }
142
143 checkpolicyConfPath := checkpolicyConfPaths[0]
144 sepolicyAnalyzeConfPath := sepolicyAnalyzeConfPaths[0]
145
146 rule := android.NewRuleBuilder(pctx, ctx)
147
148 // Step 1. Build a binary policy from the conf file including build test
149 binaryPolicy := android.PathForModuleOut(ctx, "policy")
150 rule.Command().BuiltTool("checkpolicy").
151 Flag("-M").
152 FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
153 FlagWithOutput("-o ", binaryPolicy).
154 Input(checkpolicyConfPath)
Thiébaud Weksteen9ebf0c82022-01-25 21:07:00 +1100155 rule.Build("neverallow_checkpolicy", "Neverallow check: "+ctx.ModuleName())
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900156
157 // Step 2. Run sepolicy-analyze with the conf file without the build test and binary policy
158 // file from Step 1
Thiébaud Weksteen9ebf0c82022-01-25 21:07:00 +1100159 rule = android.NewRuleBuilder(pctx, ctx)
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900160 msg := `sepolicy-analyze failed. This is most likely due to the use\n` +
161 `of an expanded attribute in a neverallow assertion. Please fix\n` +
162 `the policy.`
163
164 rule.Command().BuiltTool("sepolicy-analyze").
165 Input(binaryPolicy).
166 Text("neverallow").
167 Flag("-w").
168 FlagWithInput("-f ", sepolicyAnalyzeConfPath).
169 Text("|| (echo").
170 Flag("-e").
171 Text(`"` + msg + `"`).
172 Text("; exit 1)")
173
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900174 rule.Command().Text("touch").Output(n.testTimestamp)
Thiébaud Weksteen9ebf0c82022-01-25 21:07:00 +1100175 rule.Build("neverallow_sepolicy-analyze", "Neverallow check: "+ctx.ModuleName())
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900176}
177
178func (n *neverallowTestModule) AndroidMkEntries() []android.AndroidMkEntries {
179 return []android.AndroidMkEntries{android.AndroidMkEntries{
180 OutputFile: android.OptionalPathForPath(n.testTimestamp),
181 Class: "ETC",
182 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
183 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
184 entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
185 },
186 },
187 }}
188}