Merge "Relax freeze_test to check only compatibility" into main

This commit is contained in:
Treehugger Robot 2023-09-05 06:29:39 +00:00 committed by Gerrit Code Review
commit b316f8bf95
11 changed files with 334 additions and 24 deletions

View file

@ -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",
}
//////////////////////////////////

View file

@ -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"))

View file

@ -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").

View 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,
}

View 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,
}

View 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,
}

View 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,
}

View 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,
}

View 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,
}

View file

@ -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",
],
}

View 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()