Add dev_type test

Files under /dev should have dev_type attribute.

Bug: 303367345
Test: m selinux_policy
Change-Id: Iaa1e39338e2fae32086bd770c6f3ab4b33bb82aa
diff --git a/Android.bp b/Android.bp
index 038d92f..88107cc 100644
--- a/Android.bp
+++ b/Android.bp
@@ -833,3 +833,45 @@
         "-p $(location :precompiled_sepolicy) && " +
         "touch $(out)",
 }
+
+//////////////////////////////////
+// TestDevTypeViolations can't run on old devices (V or before)
+//////////////////////////////////
+
+soong_config_module_type {
+    name: "dev_type_test_genrule",
+    module_type: "genrule",
+    config_namespace: "ANDROID",
+    bool_variables: ["CHECK_DEV_TYPE_VIOLATIONS"],
+    properties: ["cmd"],
+}
+
+dev_type_test_genrule {
+    name: "sepolicy_dev_type_test",
+    srcs: [
+        ":plat_file_contexts",
+        ":vendor_file_contexts",
+        ":system_ext_file_contexts",
+        ":product_file_contexts",
+        ":odm_file_contexts",
+        ":precompiled_sepolicy",
+    ],
+    tools: ["sepolicy_tests"],
+    out: ["sepolicy_dev_type_test"],
+    soong_config_variables: {
+        CHECK_DEV_TYPE_VIOLATIONS: {
+            cmd: "$(location sepolicy_tests) " +
+                "-f $(location :plat_file_contexts) " +
+                "-f $(location :vendor_file_contexts) " +
+                "-f $(location :system_ext_file_contexts) " +
+                "-f $(location :product_file_contexts) " +
+                "-f $(location :odm_file_contexts) " +
+                "-p $(location :precompiled_sepolicy) " +
+                "-t TestDevTypeViolations && " +
+                "touch $(out)",
+            conditions_default: {
+                cmd: "touch $(out)",
+            },
+        },
+    },
+}
diff --git a/Android.mk b/Android.mk
index 384c416..63b74aa 100644
--- a/Android.mk
+++ b/Android.mk
@@ -240,6 +240,7 @@
 # genrule modules aren't installable, so LOCAL_REQUIRED_MODULES doesn't work.
 # Instead, use LOCAL_ADDITIONAL_DEPENDENCIES with intermediate output
 LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,ETC,sepolicy_test)/sepolicy_test
+LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,ETC,sepolicy_dev_type_test)/sepolicy_dev_type_test
 
 LOCAL_REQUIRED_MODULES += \
     $(addprefix treble_sepolicy_tests_,$(PLATFORM_SEPOLICY_COMPAT_VERSIONS)) \
diff --git a/tests/policy.py b/tests/policy.py
index 8fc2ef7..98133b7 100644
--- a/tests/policy.py
+++ b/tests/policy.py
@@ -146,9 +146,9 @@
     # DoNotMatchPrefix have the attribute Attr.
     # For example assert that all types in /sys, and not in /sys/kernel/debugfs
     # have the sysfs_type attribute.
-    def AssertPathTypesHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr):
+    def AssertPathTypesHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr, ExcludedTypes = []):
         # Query policy for the types associated with Attr
-        TypesPol = self.QueryTypeAttribute(Attr, True)
+        TypesPol = self.QueryTypeAttribute(Attr, True) | set(ExcludedTypes)
         # Search file_contexts to find paths/types that should be associated with
         # Attr.
         PathTypes = self.__GetTypesAndFilesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix)
diff --git a/tests/sepolicy_tests.py b/tests/sepolicy_tests.py
index 4ef161b..7a341cb 100644
--- a/tests/sepolicy_tests.py
+++ b/tests/sepolicy_tests.py
@@ -265,6 +265,22 @@
             "\"-isolated_app_all\". Violations are shown as the following: \n")  + ret
     return ret
 
+def TestDevTypeViolations(pol):
+    exceptions = [
+        "/dev/socket",
+    ]
+    exceptionTypes = [
+        "boringssl_self_test_marker",  # /dev/boringssl/selftest
+        "cgroup_rc_file",              # /dev/cgroup.rc
+        "dev_cpu_variant",             # /dev/cpu_variant:{arch}
+        "fscklogs",                    # /dev/fscklogs
+        "properties_serial",           # /dev/__properties__/properties_serial
+        "property_info",               # /dev/__properties__/property_info
+        "runtime_event_log_tags_file", # /dev/event-log-tags
+    ]
+    return pol.AssertPathTypesHaveAttr(["/dev"], exceptions,
+                                       "dev_type", exceptionTypes)
+
 ###
 # 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
@@ -298,6 +314,7 @@
     "TestCoredomainViolations",
     "TestViolatorAttributes",
     "TestIsolatedAttributeConsistency",
+    "TestDevTypeViolations",
 ]
 
 def do_main(libpath):
@@ -366,6 +383,10 @@
     if options.test is None or "TestIsolatedAttributeConsistency" in options.test:
         results += TestIsolatedAttributeConsistency(test_policy)
 
+    # dev type test won't be run as default
+    if options.test and "TestDevTypeViolations" in options.test:
+        results += TestDevTypeViolations(pol)
+
     if len(results) > 0:
         sys.exit(results)