Relax freeze_test to check only compatibility
For now, freeze_test compares prebuilts against sources with diff, to ensure that sources are identical to prebuilts. However, it could be the case that the branch should be able to build both REL and ToT. In that case, changes to the sources are inevitable and the freeze test will fail. To fix the issue, freeze_test will now only check compatibility. To be specific, it will check if any public types or attributes are removed. Contexts files and neverallow rules are not checked, but they may be added later. Also to support the new freeze_test - build_files module is changed to use glob (because REL version won't be in compat versions list) - plat_pub_policy modules are added under prebuilts/api (because freeze_test needs that) Bug: 296875906 Test: m selinux_policy Change-Id: I39c40992965b98664facea3b760d9d6be1f6b87e
This commit is contained in:
parent
796ec5f0cb
commit
36d9d39e6e
11 changed files with 334 additions and 24 deletions
|
@ -913,7 +913,7 @@ se_neverallow_test {
|
|||
// SEPOLICY_FREEZE_TEST_EXTRA_DIRS and SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS.
|
||||
//////////////////////////////////
|
||||
se_freeze_test {
|
||||
name: "sepolicy_freeze_test",
|
||||
name: "se_freeze_test",
|
||||
}
|
||||
|
||||
//////////////////////////////////
|
||||
|
|
|
@ -16,6 +16,7 @@ package selinux
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
|
@ -103,8 +104,15 @@ func (b *buildFiles) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||
b.srcs[".vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().VendorSepolicyDirs()...)
|
||||
b.srcs[".odm"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().OdmSepolicyDirs()...)
|
||||
|
||||
prebuilt_directories, err := ctx.GlobWithDeps("system/sepolicy/prebuilts/api/*", nil)
|
||||
if err != nil {
|
||||
ctx.ModuleErrorf("error while globbing: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// directories used for compat tests and Treble tests
|
||||
for _, ver := range ctx.DeviceConfig().PlatformSepolicyCompatVersions() {
|
||||
for _, dir := range prebuilt_directories {
|
||||
ver := path.Base(dir)
|
||||
b.srcs[".plat_public_"+ver] = b.findSrcsInDirs(ctx, filepath.Join("system", "sepolicy", "prebuilts", "api", ver, "public"))
|
||||
b.srcs[".plat_private_"+ver] = b.findSrcsInDirs(ctx, filepath.Join("system", "sepolicy", "prebuilts", "api", ver, "private"))
|
||||
b.srcs[".system_ext_public_"+ver] = b.findSrcsInDirs(ctx, filepath.Join(ctx.DeviceConfig().SystemExtSepolicyPrebuiltApiDir(), "prebuilts", "api", ver, "public"))
|
||||
|
|
|
@ -15,12 +15,14 @@
|
|||
package selinux
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
var currentCilTag = dependencyTag{name: "current_cil"}
|
||||
var prebuiltCilTag = dependencyTag{name: "prebuilt_cil"}
|
||||
|
||||
func init() {
|
||||
ctx := android.InitRegistrationContext
|
||||
ctx.RegisterParallelSingletonModuleType("se_freeze_test", freezeTestFactory)
|
||||
|
@ -32,6 +34,9 @@ func init() {
|
|||
func freezeTestFactory() android.SingletonModule {
|
||||
f := &freezeTestModule{}
|
||||
android.InitAndroidModule(f)
|
||||
android.AddLoadHook(f, func(ctx android.LoadHookContext) {
|
||||
f.loadHook(ctx)
|
||||
})
|
||||
return f
|
||||
}
|
||||
|
||||
|
@ -40,26 +45,23 @@ type freezeTestModule struct {
|
|||
freezeTestTimestamp android.ModuleOutPath
|
||||
}
|
||||
|
||||
func (f *freezeTestModule) GenerateSingletonBuildActions(ctx android.SingletonContext) {
|
||||
// does nothing; se_freeze_test is a singeton because two freeze test modules don't make sense.
|
||||
}
|
||||
|
||||
func (f *freezeTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
func (f *freezeTestModule) shouldSkip(ctx android.EarlyModuleContext) bool {
|
||||
platformVersion := ctx.DeviceConfig().PlatformSepolicyVersion()
|
||||
totVersion := ctx.DeviceConfig().TotSepolicyVersion()
|
||||
|
||||
return platformVersion == totVersion
|
||||
}
|
||||
|
||||
func (f *freezeTestModule) loadHook(ctx android.LoadHookContext) {
|
||||
extraDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraDirs()
|
||||
extraPrebuiltDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraPrebuiltDirs()
|
||||
f.freezeTestTimestamp = android.PathForModuleOut(ctx, "freeze_test")
|
||||
|
||||
if platformVersion == totVersion {
|
||||
if f.shouldSkip(ctx) {
|
||||
if len(extraDirs) > 0 || len(extraPrebuiltDirs) > 0 {
|
||||
ctx.ModuleErrorf("SEPOLICY_FREEZE_TEST_EXTRA_DIRS or SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS cannot be set before system/sepolicy freezes.")
|
||||
return
|
||||
}
|
||||
|
||||
// we still build a rule to prevent possible regression
|
||||
android.WriteFileRule(ctx, f.freezeTestTimestamp, ";; no freeze tests needed before system/sepolicy freezes")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -67,17 +69,80 @@ func (f *freezeTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext
|
|||
ctx.ModuleErrorf("SEPOLICY_FREEZE_TEST_EXTRA_DIRS and SEPOLICY_FREEZE_TEST_EXTRA_PREBUILT_DIRS must have the same number of directories.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
platPublic := filepath.Join(ctx.ModuleDir(), "public")
|
||||
platPrivate := filepath.Join(ctx.ModuleDir(), "private")
|
||||
prebuiltPublic := filepath.Join(ctx.ModuleDir(), "prebuilts", "api", platformVersion, "public")
|
||||
prebuiltPrivate := filepath.Join(ctx.ModuleDir(), "prebuilts", "api", platformVersion, "private")
|
||||
func (f *freezeTestModule) prebuiltCilModuleName(ctx android.EarlyModuleContext) string {
|
||||
return ctx.DeviceConfig().PlatformSepolicyVersion() + "_plat_pub_policy.cil"
|
||||
}
|
||||
|
||||
sourceDirs := append(extraDirs, platPublic, platPrivate)
|
||||
prebuiltDirs := append(extraPrebuiltDirs, prebuiltPublic, prebuiltPrivate)
|
||||
func (f *freezeTestModule) DepsMutator(ctx android.BottomUpMutatorContext) {
|
||||
if f.shouldSkip(ctx) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.AddDependency(f, currentCilTag, "base_plat_pub_policy.cil")
|
||||
ctx.AddDependency(f, prebuiltCilTag, f.prebuiltCilModuleName(ctx))
|
||||
}
|
||||
|
||||
func (f *freezeTestModule) GenerateSingletonBuildActions(ctx android.SingletonContext) {
|
||||
// does nothing; se_freeze_test is a singeton because two freeze test modules don't make sense.
|
||||
}
|
||||
|
||||
func (f *freezeTestModule) outputFileOfDep(ctx android.ModuleContext, depTag dependencyTag) android.Path {
|
||||
deps := ctx.GetDirectDepsWithTag(depTag)
|
||||
if len(deps) != 1 {
|
||||
ctx.ModuleErrorf("%d deps having tag %q; expected only one dep", len(deps), depTag)
|
||||
return nil
|
||||
}
|
||||
|
||||
dep := deps[0]
|
||||
outputFileProducer, ok := dep.(android.OutputFileProducer)
|
||||
if !ok {
|
||||
ctx.ModuleErrorf("module %q is not an output file producer", dep.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
output, err := outputFileProducer.OutputFiles("")
|
||||
if err != nil {
|
||||
ctx.ModuleErrorf("module %q failed to produce output: %w", dep.String(), err)
|
||||
return nil
|
||||
}
|
||||
if len(output) != 1 {
|
||||
ctx.ModuleErrorf("module %q produced %d outputs; expected only one output", dep.String(), len(output))
|
||||
return nil
|
||||
}
|
||||
|
||||
return output[0]
|
||||
}
|
||||
|
||||
func (f *freezeTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
f.freezeTestTimestamp = android.PathForModuleOut(ctx, "freeze_test")
|
||||
|
||||
if f.shouldSkip(ctx) {
|
||||
// we still build a rule to prevent possible regression
|
||||
android.WriteFileRule(ctx, f.freezeTestTimestamp, ";; no freeze tests needed before system/sepolicy freezes")
|
||||
return
|
||||
}
|
||||
|
||||
// Freeze test 1: compare ToT sepolicy and prebuilt sepolicy
|
||||
currentCil := f.outputFileOfDep(ctx, currentCilTag)
|
||||
prebuiltCil := f.outputFileOfDep(ctx, prebuiltCilTag)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
rule := android.NewRuleBuilder(pctx, ctx)
|
||||
rule.Command().BuiltTool("sepolicy_freeze_test").
|
||||
FlagWithInput("-c ", currentCil).
|
||||
FlagWithInput("-p ", prebuiltCil)
|
||||
|
||||
// Freeze test 2: compare extra directories
|
||||
// We don't know the exact structure of extra directories, so just directly compare them
|
||||
extraDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraDirs()
|
||||
extraPrebuiltDirs := ctx.DeviceConfig().SepolicyFreezeTestExtraPrebuiltDirs()
|
||||
|
||||
var implicits []string
|
||||
for _, dir := range append(sourceDirs, prebuiltDirs...) {
|
||||
for _, dir := range append(extraDirs, extraPrebuiltDirs...) {
|
||||
glob, err := ctx.GlobWithDeps(dir+"/**/*", []string{"bug_map"} /* exclude */)
|
||||
if err != nil {
|
||||
ctx.ModuleErrorf("failed to glob sepolicy dir %q: %s", dir, err.Error())
|
||||
|
@ -87,15 +152,13 @@ func (f *freezeTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext
|
|||
}
|
||||
sort.Strings(implicits)
|
||||
|
||||
rule := android.NewRuleBuilder(pctx, ctx)
|
||||
|
||||
for idx, _ := range sourceDirs {
|
||||
for idx, _ := range extraDirs {
|
||||
rule.Command().Text("diff").
|
||||
Flag("-r").
|
||||
Flag("-q").
|
||||
FlagWithArg("-x ", "bug_map"). // exclude
|
||||
Text(sourceDirs[idx]).
|
||||
Text(prebuiltDirs[idx])
|
||||
Text(extraDirs[idx]).
|
||||
Text(extraPrebuiltDirs[idx])
|
||||
}
|
||||
|
||||
rule.Command().Text("touch").
|
||||
|
|
28
prebuilts/api/29.0/Android.bp
Normal file
28
prebuilts/api/29.0/Android.bp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
se_policy_conf {
|
||||
name: "29.0_plat_pub_policy.conf",
|
||||
srcs: [":se_build_files{.plat_public_29.0}", ":se_build_files{.reqd_mask}"],
|
||||
installable: false,
|
||||
build_variant: "user",
|
||||
}
|
||||
|
||||
se_policy_cil {
|
||||
name: "29.0_plat_pub_policy.cil",
|
||||
src: ":29.0_plat_pub_policy.conf",
|
||||
filter_out: [":reqd_policy_mask.cil"],
|
||||
secilc_check: false,
|
||||
installable: false,
|
||||
}
|
28
prebuilts/api/30.0/Android.bp
Normal file
28
prebuilts/api/30.0/Android.bp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
se_policy_conf {
|
||||
name: "30.0_plat_pub_policy.conf",
|
||||
srcs: [":se_build_files{.plat_public_30.0}", ":se_build_files{.reqd_mask}"],
|
||||
installable: false,
|
||||
build_variant: "user",
|
||||
}
|
||||
|
||||
se_policy_cil {
|
||||
name: "30.0_plat_pub_policy.cil",
|
||||
src: ":30.0_plat_pub_policy.conf",
|
||||
filter_out: [":reqd_policy_mask.cil"],
|
||||
secilc_check: false,
|
||||
installable: false,
|
||||
}
|
28
prebuilts/api/31.0/Android.bp
Normal file
28
prebuilts/api/31.0/Android.bp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
se_policy_conf {
|
||||
name: "31.0_plat_pub_policy.conf",
|
||||
srcs: [":se_build_files{.plat_public_31.0}", ":se_build_files{.reqd_mask}"],
|
||||
installable: false,
|
||||
build_variant: "user",
|
||||
}
|
||||
|
||||
se_policy_cil {
|
||||
name: "31.0_plat_pub_policy.cil",
|
||||
src: ":31.0_plat_pub_policy.conf",
|
||||
filter_out: [":reqd_policy_mask.cil"],
|
||||
secilc_check: false,
|
||||
installable: false,
|
||||
}
|
28
prebuilts/api/32.0/Android.bp
Normal file
28
prebuilts/api/32.0/Android.bp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
se_policy_conf {
|
||||
name: "32.0_plat_pub_policy.conf",
|
||||
srcs: [":se_build_files{.plat_public_32.0}", ":se_build_files{.reqd_mask}"],
|
||||
installable: false,
|
||||
build_variant: "user",
|
||||
}
|
||||
|
||||
se_policy_cil {
|
||||
name: "32.0_plat_pub_policy.cil",
|
||||
src: ":32.0_plat_pub_policy.conf",
|
||||
filter_out: [":reqd_policy_mask.cil"],
|
||||
secilc_check: false,
|
||||
installable: false,
|
||||
}
|
28
prebuilts/api/33.0/Android.bp
Normal file
28
prebuilts/api/33.0/Android.bp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
se_policy_conf {
|
||||
name: "33.0_plat_pub_policy.conf",
|
||||
srcs: [":se_build_files{.plat_public_33.0}", ":se_build_files{.reqd_mask}"],
|
||||
installable: false,
|
||||
build_variant: "user",
|
||||
}
|
||||
|
||||
se_policy_cil {
|
||||
name: "33.0_plat_pub_policy.cil",
|
||||
src: ":33.0_plat_pub_policy.conf",
|
||||
filter_out: [":reqd_policy_mask.cil"],
|
||||
secilc_check: false,
|
||||
installable: false,
|
||||
}
|
28
prebuilts/api/34.0/Android.bp
Normal file
28
prebuilts/api/34.0/Android.bp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2023 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
se_policy_conf {
|
||||
name: "34.0_plat_pub_policy.conf",
|
||||
srcs: [":se_build_files{.plat_public_34.0}", ":se_build_files{.reqd_mask}"],
|
||||
installable: false,
|
||||
build_variant: "user",
|
||||
}
|
||||
|
||||
se_policy_cil {
|
||||
name: "34.0_plat_pub_policy.cil",
|
||||
src: ":34.0_plat_pub_policy.conf",
|
||||
filter_out: [":reqd_policy_mask.cil"],
|
||||
secilc_check: false,
|
||||
installable: false,
|
||||
}
|
|
@ -146,3 +146,18 @@ python_binary_host {
|
|||
name: "check_prop_prefix",
|
||||
srcs: ["check_prop_prefix.py"],
|
||||
}
|
||||
|
||||
python_binary_host {
|
||||
name: "sepolicy_freeze_test",
|
||||
srcs: [
|
||||
"sepolicy_freeze_test.py",
|
||||
],
|
||||
version: {
|
||||
py3: {
|
||||
embedded_launcher: true,
|
||||
},
|
||||
},
|
||||
libs: [
|
||||
"mini_cil_parser",
|
||||
],
|
||||
}
|
||||
|
|
56
tests/sepolicy_freeze_test.py
Normal file
56
tests/sepolicy_freeze_test.py
Normal file
|
@ -0,0 +1,56 @@
|
|||
# Copyright 2023 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from optparse import OptionParser
|
||||
import mini_parser
|
||||
import os
|
||||
import sys
|
||||
|
||||
def do_main():
|
||||
usage = "sepolicy_freeze_test "
|
||||
usage += "-c current_cil -p prebuilt_cil [--help]"
|
||||
parser = OptionParser(usage=usage)
|
||||
parser.add_option("-c", "--current", dest="current", metavar="FILE")
|
||||
parser.add_option("-p", "--prebuilt", dest="prebuilt", metavar="FILE")
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if not options.current or not options.prebuilt:
|
||||
sys.exit("Must specify both current and prebuilt\n" + parser.usage)
|
||||
if not os.path.exists(options.current):
|
||||
sys.exit("Current policy " + options.current + " does not exist\n"
|
||||
+ parser.usage)
|
||||
if not os.path.exists(options.prebuilt):
|
||||
sys.exit("Prebuilt policy " + options.prebuilt + " does not exist\n"
|
||||
+ parser.usage)
|
||||
|
||||
current_policy = mini_parser.MiniCilParser(options.current)
|
||||
prebuilt_policy = mini_parser.MiniCilParser(options.prebuilt)
|
||||
|
||||
results = ""
|
||||
removed_types = prebuilt_policy.types - current_policy.types
|
||||
removed_attributes = prebuilt_policy.typeattributes - current_policy.typeattributes
|
||||
removed_attributes = set(filter(lambda x: "base_typeattr_" not in x, removed_attributes))
|
||||
|
||||
if removed_types:
|
||||
results += "The following public types were removed:\n" + ", ".join(removed_types) + "\n"
|
||||
|
||||
if removed_attributes:
|
||||
results += "The following public attributes were removed:\n" + ", ".join(removed_attributes) + "\n"
|
||||
|
||||
if len(results) > 0:
|
||||
sys.exit(results)
|
||||
|
||||
if __name__ == '__main__':
|
||||
do_main()
|
Loading…
Reference in a new issue