APEX file_context should have valid labels

A new test mode (--all) tests if every file context label used in APEX
is "known". It should fail if unknown label is used in APEX.

Bug: 299391194
Test: atest apex_sepolicy_tests_test
Change-Id: Ie467019a6dc74bba9901ba8d705b31e6de24cd62
diff --git a/tests/apex_sepolicy_tests.py b/tests/apex_sepolicy_tests.py
index 518ebbc..3c51b67 100644
--- a/tests/apex_sepolicy_tests.py
+++ b/tests/apex_sepolicy_tests.py
@@ -65,7 +65,13 @@
     scontext: set[str]
 
 
-Rule = AllowRead
+@dataclass
+class ResolveType:
+    """Rule checking if type can be resolved"""
+    pass
+
+
+Rule = AllowRead | ResolveType
 
 
 def match_path(path: str, matcher: Matcher) -> bool:
@@ -94,10 +100,18 @@
                     continue  # no errors
 
                 errors.append(f"Error: {path}: {s} can't read. (tcontext={tcontext})")
+        case ResolveType():
+            if tcontext not in pol.GetAllTypes(False):
+                errors.append(f"Error: {path}: tcontext({tcontext}) is unknown")
     return errors
 
 
-rules = [
+target_specific_rules = [
+    (Glob('*'), ResolveType()),
+]
+
+
+generic_rules = [
     # permissions
     (Is('./etc/permissions/'), AllowRead('dir', {'system_server'})),
     (Glob('./etc/permissions/*.xml'), AllowRead('file', {'system_server'})),
@@ -114,7 +128,10 @@
 ]
 
 
-def check_line(pol: policy.Policy, line: str) -> List[str]:
+all_rules = target_specific_rules + generic_rules
+
+
+def check_line(pol: policy.Policy, line: str, rules) -> List[str]:
     """Parses a file_contexts line and runs checks"""
     # skip empty/comment line
     line = line.strip()
@@ -151,6 +168,7 @@
 def do_main(work_dir):
     """Do testing"""
     parser = argparse.ArgumentParser()
+    parser.add_argument('--all', action='store_true', help='tests ALL aspects')
     parser.add_argument('-f', '--file_contexts', help='output of "deapexer list -Z"')
     args = parser.parse_args()
 
@@ -158,10 +176,15 @@
     policy_path = extract_data('precompiled_sepolicy', work_dir)
     pol = policy.Policy(policy_path, None, lib_path)
 
+    if args.all:
+        rules = all_rules
+    else:
+        rules = generic_rules
+
     errors = []
     with open(args.file_contexts, 'rt', encoding='utf-8') as file_contexts:
         for line in file_contexts:
-            errors.extend(check_line(pol, line))
+            errors.extend(check_line(pol, line, rules))
     if len(errors) > 0:
         sys.exit('\n'.join(errors))
 
diff --git a/tests/apex_sepolicy_tests_test.py b/tests/apex_sepolicy_tests_test.py
index 9c87a00..6e719ed 100644
--- a/tests/apex_sepolicy_tests_test.py
+++ b/tests/apex_sepolicy_tests_test.py
@@ -43,12 +43,12 @@
         return self.__class__.pol
 
     def assert_ok(self, line: str):
-        errors = apex.check_line(self.pol, line)
+        errors = apex.check_line(self.pol, line, apex.all_rules)
         self.assertEqual(errors, [], "Should be no errors")
 
     def assert_error(self, line: str, expected_error: str):
         pattern = re.compile(expected_error)
-        errors = apex.check_line(self.pol, line)
+        errors = apex.check_line(self.pol, line, apex.all_rules)
         for err in errors:
             if re.search(pattern, err):
                 return
@@ -76,17 +76,19 @@
                           r'Error: \./etc/permissions/permisssion.xml: .* can\'t read')
 
     def test_initscripts(self):
+        # here, netd_service is chosen randomly for invalid label for a file
+
         # init reads .rc file
         self.assert_ok('./etc/init.rc u:object_r:vendor_file:s0')
-        self.assert_error('./etc/init.rc u:object_r:unknown:s0',
+        self.assert_error('./etc/init.rc u:object_r:netd_service:s0',
                           r'Error: .* can\'t read')
         # init reads .#rc file
         self.assert_ok('./etc/init.32rc u:object_r:vendor_file:s0')
-        self.assert_error('./etc/init.32rc u:object_r:unknown:s0',
+        self.assert_error('./etc/init.32rc u:object_r:netd_service:s0',
                           r'Error: .* can\'t read')
         # init skips file with unknown extension => no errors
         self.assert_ok('./etc/init.x32rc u:object_r:vendor_file:s0')
-        self.assert_ok('./etc/init.x32rc u:object_r:unknown:s0')
+        self.assert_ok('./etc/init.x32rc u:object_r:netd_service:s0')
 
     def test_linkerconfig(self):
         self.assert_ok('./etc/linker.config.pb u:object_r:system_file:s0')
@@ -96,5 +98,9 @@
         self.assert_error('./ u:object_r:apex_data_file:s0',
                         r'Error: .*linkerconfig.* can\'t read')
 
+    def test_unknown_label(self):
+        self.assert_error('./bin/hw/foo u:object_r:foo_exec:s0',
+                        r'Error: \./bin/hw/foo: tcontext\(foo_exec\) is unknown')
+
 if __name__ == '__main__':
     unittest.main(verbosity=2)