• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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	"sort"
19
20	"android/soong/android"
21)
22
23func init() {
24	ctx := android.InitRegistrationContext
25	ctx.RegisterModuleType("se_freeze_test", freezeTestFactory)
26}
27
28// se_freeze_test compares the plat sepolicy with the prebuilt sepolicy.  Additional directories can
29// be specified via Makefile variables: SEPOLICY_FREEZE_TEST_EXTRA_DIRS and
30// SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS.
31func freezeTestFactory() android.Module {
32	f := &freezeTestModule{}
33	f.AddProperties(&f.properties)
34	android.InitAndroidArchModule(f, android.DeviceSupported, android.MultilibCommon)
35	return f
36}
37
38type freezeTestProperties struct {
39	// Frozen SEPolicy version to compare
40	Board_api_level *string
41
42	// Path to the base platform public policy cil
43	Current_cil *string `android:"path"`
44
45	// Path to the prebuilt cil of given board API level
46	Prebuilt_cil *string `android:"path"`
47}
48
49type freezeTestModule struct {
50	android.ModuleBase
51
52	properties freezeTestProperties
53
54	freezeTestTimestamp android.ModuleOutPath
55}
56
57func (f *freezeTestModule) shouldCompareExtraDirs(ctx android.EarlyModuleContext) bool {
58	val, _ := ctx.Config().GetBuildFlag("RELEASE_BOARD_API_LEVEL_FROZEN")
59	return val == "true"
60}
61
62func (f *freezeTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
63	if ctx.ModuleName() != "se_freeze_test" || ctx.ModuleDir() != "system/sepolicy" {
64		// two freeze test modules don't make sense.
65		ctx.ModuleErrorf("There can only be 1 se_freeze_test module named se_freeze_test in system/sepolicy")
66	}
67
68	f.freezeTestTimestamp = android.PathForModuleOut(ctx, "freeze_test")
69
70	// Freeze test 1: compare ToT sepolicy and prebuilt sepolicy
71	currentCil := android.PathForModuleSrc(ctx, String(f.properties.Current_cil))
72	prebuiltCil := android.PathForModuleSrc(ctx, String(f.properties.Prebuilt_cil))
73	if ctx.Failed() {
74		return
75	}
76
77	rule := android.NewRuleBuilder(pctx, ctx)
78	rule.Command().BuiltTool("sepolicy_freeze_test").
79		FlagWithInput("-c ", currentCil).
80		FlagWithInput("-p ", prebuiltCil)
81
82	// Freeze test 2: compare extra directories
83	// We don't know the exact structure of extra directories, so just directly compare them
84	extraDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraDirs()
85	extraPrebuiltDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraPrebuiltDirs()
86
87	var implicits []string
88	if f.shouldCompareExtraDirs(ctx) {
89		if len(extraDirs) != len(extraPrebuiltDirs) {
90			ctx.ModuleErrorf("SEPOLICY_FREEZE_TEST_EXTRA_DIRS and SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS must have the same number of directories.")
91			return
92		}
93
94		for _, dir := range append(extraDirs, extraPrebuiltDirs...) {
95			glob, err := ctx.GlobWithDeps(dir+"/**/*", []string{"bug_map"} /* exclude */)
96			if err != nil {
97				ctx.ModuleErrorf("failed to glob sepolicy dir %q: %s", dir, err.Error())
98				return
99			}
100			implicits = append(implicits, glob...)
101		}
102		sort.Strings(implicits)
103
104		for idx, _ := range extraDirs {
105			rule.Command().Text("diff").
106				Flag("-r").
107				Flag("-q").
108				FlagWithArg("-x ", "bug_map"). // exclude
109				Text(extraDirs[idx]).
110				Text(extraPrebuiltDirs[idx])
111		}
112	} else {
113		if len(extraDirs) > 0 || len(extraPrebuiltDirs) > 0 {
114			ctx.ModuleErrorf("SEPOLICY_FREEZE_TEST_EXTRA_DIRS or SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS cannot be set before system/sepolicy freezes.")
115			return
116		}
117	}
118
119	rule.Command().Text("touch").
120		Output(f.freezeTestTimestamp).
121		Implicits(android.PathsForSource(ctx, implicits))
122
123	rule.Build("sepolicy_freeze_test", "sepolicy_freeze_test")
124}
125
126func (f *freezeTestModule) AndroidMkEntries() []android.AndroidMkEntries {
127	return []android.AndroidMkEntries{android.AndroidMkEntries{
128		Class: "FAKE",
129		// OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it.
130		// Without OutputFile this module won't be exported to Makefile.
131		OutputFile: android.OptionalPathForPath(f.freezeTestTimestamp),
132		Include:    "$(BUILD_PHONY_PACKAGE)",
133		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
134			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
135				entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", f.freezeTestTimestamp.String())
136			},
137		},
138	}}
139}
140