blob: c2a21dd3d87c17c2113a8ba8ae28a5b312a5ba5f [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 {
Inseob Kim085f22f2023-11-09 11:13:01 +090032 // Default modules for conf
33 Defaults []string
34
Inseob Kim0de7fcc2021-12-22 23:06:53 +090035 // Policy files to be tested.
36 Srcs []string `android:"path"`
37}
38
39type neverallowTestModule struct {
40 android.ModuleBase
41 properties neverallowTestProperties
Inseob Kim6c6f53b2023-04-26 11:03:35 +090042 testTimestamp android.OutputPath
Inseob Kim0de7fcc2021-12-22 23:06:53 +090043}
44
45type nameProperties struct {
46 Name *string
47}
48
49var checkpolicyTag = dependencyTag{name: "checkpolicy"}
50var sepolicyAnalyzeTag = dependencyTag{name: "sepolicy_analyze"}
51
52// se_neverallow_test builds given policy files and checks whether any neverallow violations exist.
53// This module creates two conf files, one with build test and one without build test. Policy with
54// build test will be compiled with checkpolicy, and policy without build test will be tested with
55// sepolicy-analyze's neverallow tool. This module's check can be skipped by setting
56// SELINUX_IGNORE_NEVERALLOWS := true.
57func neverallowTestFactory() android.Module {
58 n := &neverallowTestModule{}
59 n.AddProperties(&n.properties)
Cole Faust09e326f2024-10-07 16:54:31 -070060 android.InitAndroidArchModule(n, android.DeviceSupported, android.MultilibCommon)
Inseob Kim0de7fcc2021-12-22 23:06:53 +090061 android.AddLoadHook(n, func(ctx android.LoadHookContext) {
62 n.loadHook(ctx)
63 })
64 return n
65}
66
67// Child conf module name for checkpolicy test.
68func (n *neverallowTestModule) checkpolicyConfModuleName() string {
69 return n.Name() + ".checkpolicy.conf"
70}
71
72// Child conf module name for sepolicy-analyze test.
73func (n *neverallowTestModule) sepolicyAnalyzeConfModuleName() string {
74 return n.Name() + ".sepolicy_analyze.conf"
75}
76
77func (n *neverallowTestModule) loadHook(ctx android.LoadHookContext) {
78 checkpolicyConf := n.checkpolicyConfModuleName()
79 ctx.CreateModule(policyConfFactory, &nameProperties{
80 Name: proptools.StringPtr(checkpolicyConf),
81 }, &policyConfProperties{
82 Srcs: n.properties.Srcs,
83 Build_variant: proptools.StringPtr("user"),
84 Installable: proptools.BoolPtr(false),
Inseob Kim085f22f2023-11-09 11:13:01 +090085 }, &struct {
86 Defaults []string
87 }{
88 Defaults: n.properties.Defaults,
Inseob Kim0de7fcc2021-12-22 23:06:53 +090089 })
90
91 sepolicyAnalyzeConf := n.sepolicyAnalyzeConfModuleName()
92 ctx.CreateModule(policyConfFactory, &nameProperties{
93 Name: proptools.StringPtr(sepolicyAnalyzeConf),
94 }, &policyConfProperties{
95 Srcs: n.properties.Srcs,
96 Build_variant: proptools.StringPtr("user"),
97 Exclude_build_test: proptools.BoolPtr(true),
98 Installable: proptools.BoolPtr(false),
Inseob Kim085f22f2023-11-09 11:13:01 +090099 }, &struct {
100 Defaults []string
101 }{
102 Defaults: n.properties.Defaults,
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900103 })
104}
105
106func (n *neverallowTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
107 ctx.AddDependency(n, checkpolicyTag, n.checkpolicyConfModuleName())
108 ctx.AddDependency(n, sepolicyAnalyzeTag, n.sepolicyAnalyzeConfModuleName())
109}
110
111func (n *neverallowTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Inseob Kim6c6f53b2023-04-26 11:03:35 +0900112 n.testTimestamp = pathForModuleOut(ctx, "timestamp")
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900113 if ctx.Config().SelinuxIgnoreNeverallows() {
114 // just touch
115 android.WriteFileRule(ctx, n.testTimestamp, "")
116 return
117 }
118
119 var checkpolicyConfPaths android.Paths
120 var sepolicyAnalyzeConfPaths android.Paths
121
122 ctx.VisitDirectDeps(func(child android.Module) {
123 depTag := ctx.OtherModuleDependencyTag(child)
124 if depTag != checkpolicyTag && depTag != sepolicyAnalyzeTag {
125 return
126 }
127
mrziwangcb3f5502024-06-06 10:04:23 -0700128 outputs := android.OutputFilesForModule(ctx, child, "")
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900129
130 switch ctx.OtherModuleDependencyTag(child) {
131 case checkpolicyTag:
132 checkpolicyConfPaths = outputs
133 case sepolicyAnalyzeTag:
134 sepolicyAnalyzeConfPaths = outputs
135 }
136 })
137
138 if len(checkpolicyConfPaths) != 1 {
139 panic(fmt.Errorf("Module %q should produce exactly one output", n.checkpolicyConfModuleName()))
140 }
141
142 if len(sepolicyAnalyzeConfPaths) != 1 {
143 panic(fmt.Errorf("Module %q should produce exactly one output", n.sepolicyAnalyzeConfModuleName()))
144 }
145
146 checkpolicyConfPath := checkpolicyConfPaths[0]
147 sepolicyAnalyzeConfPath := sepolicyAnalyzeConfPaths[0]
148
149 rule := android.NewRuleBuilder(pctx, ctx)
150
151 // Step 1. Build a binary policy from the conf file including build test
Inseob Kim6c6f53b2023-04-26 11:03:35 +0900152 binaryPolicy := pathForModuleOut(ctx, "policy")
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900153 rule.Command().BuiltTool("checkpolicy").
154 Flag("-M").
155 FlagWithArg("-c ", strconv.Itoa(PolicyVers)).
156 FlagWithOutput("-o ", binaryPolicy).
157 Input(checkpolicyConfPath)
Thiébaud Weksteen9ebf0c82022-01-25 21:07:00 +1100158 rule.Build("neverallow_checkpolicy", "Neverallow check: "+ctx.ModuleName())
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900159
160 // Step 2. Run sepolicy-analyze with the conf file without the build test and binary policy
161 // file from Step 1
Thiébaud Weksteen9ebf0c82022-01-25 21:07:00 +1100162 rule = android.NewRuleBuilder(pctx, ctx)
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900163 msg := `sepolicy-analyze failed. This is most likely due to the use\n` +
164 `of an expanded attribute in a neverallow assertion. Please fix\n` +
165 `the policy.`
166
167 rule.Command().BuiltTool("sepolicy-analyze").
168 Input(binaryPolicy).
169 Text("neverallow").
170 Flag("-w").
171 FlagWithInput("-f ", sepolicyAnalyzeConfPath).
172 Text("|| (echo").
173 Flag("-e").
174 Text(`"` + msg + `"`).
175 Text("; exit 1)")
176
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900177 rule.Command().Text("touch").Output(n.testTimestamp)
Thiébaud Weksteen9ebf0c82022-01-25 21:07:00 +1100178 rule.Build("neverallow_sepolicy-analyze", "Neverallow check: "+ctx.ModuleName())
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900179}
180
181func (n *neverallowTestModule) AndroidMkEntries() []android.AndroidMkEntries {
182 return []android.AndroidMkEntries{android.AndroidMkEntries{
183 OutputFile: android.OptionalPathForPath(n.testTimestamp),
Inseob Kim021596b2024-04-15 11:07:07 +0900184 Class: "FAKE",
185 Include: "$(BUILD_PHONY_PACKAGE)",
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900186 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
187 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
Inseob Kim021596b2024-04-15 11:07:07 +0900188 entries.SetPath("LOCAL_ADDITIONAL_DEPENDENCIES", n.testTimestamp)
Inseob Kim0de7fcc2021-12-22 23:06:53 +0900189 },
190 },
191 }}
192}