| # Copyright 2021 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 |
| from optparse import Option, OptionValueError |
| import os |
| import mini_parser |
| import re |
| import shutil |
| import sys |
| import tempfile |
| |
| ''' |
| Verify that Treble compatibility are not broken. |
| ''' |
| |
| |
| ############################################################# |
| # Tests |
| ############################################################# |
| |
| ### |
| # Make sure that any new public type introduced in the new policy that was not |
| # present in the old policy has been recorded in the mapping file. |
| def TestNoUnmappedNewTypes(base_pub_policy, old_pub_policy, mapping): |
| newt = base_pub_policy.types - old_pub_policy.types |
| ret = "" |
| violators = [] |
| |
| for n in newt: |
| if mapping.rTypeattributesets.get(n) is None: |
| violators.append(n) |
| |
| if len(violators) > 0: |
| ret += "SELinux: The following public types were found added to the " |
| ret += "policy without an entry into the compatibility mapping file(s) " |
| ret += "found in private/compat/V.v/V.v[.ignore].cil, where V.v is the " |
| ret += "latest API level.\n" |
| ret += " ".join(str(x) for x in sorted(violators)) + "\n\n" |
| ret += "See examples of how to fix this:\n" |
| ret += "https://android-review.googlesource.com/c/platform/system/sepolicy/+/781036\n" |
| ret += "https://android-review.googlesource.com/c/platform/system/sepolicy/+/852612\n" |
| return ret |
| |
| ### |
| # Make sure that any public type removed in the current policy has its |
| # declaration added to the mapping file for use in non-platform policy |
| def TestNoUnmappedRmTypes(base_pub_policy, old_pub_policy, mapping): |
| rmt = old_pub_policy.types - base_pub_policy.types |
| ret = "" |
| violators = [] |
| |
| for o in rmt: |
| if o in mapping.pubtypes and not o in mapping.types: |
| violators.append(o) |
| |
| if len(violators) > 0: |
| ret += "SELinux: The following formerly public types were removed from " |
| ret += "policy without a declaration in the compatibility mapping " |
| ret += "found in private/compat/V.v/V.v[.ignore].cil, where V.v is the " |
| ret += "latest API level.\n" |
| ret += " ".join(str(x) for x in sorted(violators)) + "\n\n" |
| ret += "See examples of how to fix this:\n" |
| ret += "https://android-review.googlesource.com/c/platform/system/sepolicy/+/822743\n" |
| return ret |
| |
| def TestTrebleCompatMapping(base_pub_policy, old_pub_policy, mapping): |
| ret = TestNoUnmappedNewTypes(base_pub_policy, old_pub_policy, mapping) |
| ret += TestNoUnmappedRmTypes(base_pub_policy, old_pub_policy, mapping) |
| return ret |
| |
| ### |
| # extend OptionParser to allow the same option flag to be used multiple times. |
| # This is used to allow multiple file_contexts files and tests to be |
| # specified. |
| # |
| class MultipleOption(Option): |
| ACTIONS = Option.ACTIONS + ("extend",) |
| STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",) |
| TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",) |
| ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",) |
| |
| def take_action(self, action, dest, opt, value, values, parser): |
| if action == "extend": |
| values.ensure_value(dest, []).append(value) |
| else: |
| Option.take_action(self, action, dest, opt, value, values, parser) |
| |
| def do_main(): |
| usage = "treble_sepolicy_tests " |
| usage += "-b base_pub_policy -o old_pub_policy " |
| usage += "-m mapping file [--test test] [--help]" |
| parser = OptionParser(option_class=MultipleOption, usage=usage) |
| parser.add_option("-b", "--base-pub-policy", dest="base_pub_policy", |
| metavar="FILE") |
| parser.add_option("-m", "--mapping", dest="mapping", metavar="FILE") |
| parser.add_option("-o", "--old-pub-policy", dest="old_pub_policy", |
| metavar="FILE") |
| |
| (options, args) = parser.parse_args() |
| |
| # Mapping files and public platform policy are only necessary for the |
| # TrebleCompatMapping test. |
| if not options.mapping: |
| sys.exit("Must specify a compatibility mapping file\n" |
| + parser.usage) |
| if not options.old_pub_policy: |
| sys.exit("Must specify the previous public policy .cil file\n" |
| + parser.usage) |
| if not options.base_pub_policy: |
| sys.exit("Must specify the current platform-only public policy " |
| + ".cil file\n" + parser.usage) |
| mapping = mini_parser.MiniCilParser(options.mapping) |
| base_pub_policy = mini_parser.MiniCilParser(options.base_pub_policy) |
| old_pub_policy = mini_parser.MiniCilParser(options.old_pub_policy) |
| |
| results = TestTrebleCompatMapping(base_pub_policy, old_pub_policy, mapping) |
| |
| if len(results) > 0: |
| sys.exit(results) |
| |
| if __name__ == '__main__': |
| do_main() |