Merge "Exempt app_data_file_type from neverallow rules."
diff --git a/public/attributes b/public/attributes
index 754dd9e..4f477f4 100644
--- a/public/attributes
+++ b/public/attributes
@@ -34,7 +34,8 @@
 attribute core_data_file_type;
 expandattribute core_data_file_type false;
 
-# All types used for app private data files under /data/data.
+# All types used for app private data files in seapp_contexts.
+# Such types should not be applied to any other files.
 attribute app_data_file_type;
 expandattribute app_data_file_type false;
 
diff --git a/public/domain.te b/public/domain.te
index 4e7347b..a36b7cb 100644
--- a/public/domain.te
+++ b/public/domain.te
@@ -783,6 +783,7 @@
     dev_type
     -coredomain_socket
     -core_data_file_type
+    -app_data_file_type
     -unlabeled
   }:sock_file ~{ append getattr ioctl read write };
 ')
@@ -807,6 +808,7 @@
   } {
     data_file_type
     -core_data_file_type
+    -app_data_file_type
   }:file_class_set ~{ append getattr ioctl read write map };
 ')
 full_treble_only(`
@@ -819,6 +821,7 @@
     } {
       data_file_type
       -core_data_file_type
+      -app_data_file_type
       # TODO(b/72998741) Remove exemption. Further restricted in a subsequent
       # neverallow. Currently only getattr and search are allowed.
       -vendor_data_file
diff --git a/tests/policy.py b/tests/policy.py
index d0ef6c4..40229b8 100644
--- a/tests/policy.py
+++ b/tests/policy.py
@@ -52,9 +52,9 @@
     __policydbP = None
     __BUFSIZE = 2048
 
-    def AssertPathTypesDoNotHaveAttr(self, MatchPrefix, DoNotMatchPrefix, Attr):
+    def AssertPathTypesDoNotHaveAttr(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 types associated with input paths.
         TypesFc, Files = self.__GetTypesAndFilesByFilePathPrefix(MatchPrefix, DoNotMatchPrefix)
         violators = TypesFc.intersection(TypesPol)
diff --git a/tests/sepolicy_tests.py b/tests/sepolicy_tests.py
index 01dda04..5597f14 100644
--- a/tests/sepolicy_tests.py
+++ b/tests/sepolicy_tests.py
@@ -61,6 +61,28 @@
 def TestPropertyTypeViolations(pol):
     return pol.AssertPropertyOwnersAreExclusive()
 
+def TestAppDataTypeViolations(pol):
+    # Types with the app_data_file_type should only be used for app data files
+    # (/data/data/package.name etc) via seapp_contexts, and never applied
+    # explicitly to other files.
+    partitions = [
+        "/data/",
+        "/vendor/",
+        "/odm/",
+        "/product/",
+    ]
+    exceptions = [
+        # These are used for app data files for the corresponding user and
+        # assorted other files.
+        # TODO(b/172812577): Use different types for the different purposes
+        "shell_data_file",
+        "bluetooth_data_file",
+        "nfc_data_file",
+        "radio_data_file",
+    ]
+    return pol.AssertPathTypesDoNotHaveAttr(partitions, [], "app_data_file_type",
+                                            exceptions)
+
 
 ###
 # extend OptionParser to allow the same option flag to be used multiple times.
@@ -87,7 +109,8 @@
     "TestDebugfsTypeViolations",
     "TestVendorTypeViolations",
     "TestCoreDataTypeViolations",
-    "TestPropertyTypeViolations"
+    "TestPropertyTypeViolations",
+    "TestAppDataTypeViolations",
 ]
 
 if __name__ == '__main__':
@@ -143,6 +166,8 @@
         results += TestCoreDataTypeViolations(pol)
     if options.test is None or "TestPropertyTypeViolations" in options.test:
         results += TestPropertyTypeViolations(pol)
+    if options.test is None or "TestAppDataTypeViolations" in options.test:
+        results += TestAppDataTypeViolations(pol)
 
     if len(results) > 0:
         sys.exit(results)