Merge "Give media.metrics service access to uid/pkg info" into oc-mr1-dev am: 123cf237b7
am: 91306800e7

Change-Id: Ia7bc742ded9f4d2aa196e058e31935faf9c98759
diff --git a/Android.mk b/Android.mk
index 725b731..8491d60 100644
--- a/Android.mk
+++ b/Android.mk
@@ -194,12 +194,12 @@
     plat_sepolicy.cil \
     plat_and_mapping_sepolicy.cil.sha256 \
     secilc \
-    plat_sepolicy_vers.txt
+    plat_sepolicy_vers.txt \
 
 ifneq ($(with_asan),true)
 LOCAL_REQUIRED_MODULES += \
     treble_sepolicy_tests \
-    sepolicy_tests
+
 endif
 
 # Include precompiled policy, unless told otherwise
@@ -224,8 +224,15 @@
     plat_seapp_contexts \
     plat_service_contexts \
     plat_hwservice_contexts \
+    searchpolicy.py \
     vndservice_contexts \
 
+ifneq ($(with_asan),true)
+LOCAL_REQUIRED_MODULES += \
+    sepolicy_tests \
+
+endif
+
 include $(BUILD_PHONY_PACKAGE)
 
 ##################################
@@ -1258,6 +1265,11 @@
 $(treble_sepolicy_tests): PRIVATE_SEPOLICY_OLD := $(built_26.0_plat_sepolicy)
 $(treble_sepolicy_tests): PRIVATE_COMBINED_MAPPING := $(26.0_mapping.combined.cil)
 $(treble_sepolicy_tests): PRIVATE_PLAT_SEPOLICY := $(built_plat_sepolicy)
+ifeq ($(PRODUCT_FULL_TREBLE_OVERRIDE),true)
+$(treble_sepolicy_tests): PRIVATE_FAKE_TREBLE := --fake-treble
+else
+$(treble_sepolicy_tests): PRIVATE_FAKE_TREBLE :=
+endif
 $(treble_sepolicy_tests): $(HOST_OUT_EXECUTABLES)/treble_sepolicy_tests.py \
 $(built_plat_fc) $(built_nonplat_fc) $(built_sepolicy) $(built_plat_sepolicy) \
 $(built_26.0_plat_sepolicy) $(26.0_compat) $(26.0_mapping.combined.cil)
@@ -1265,7 +1277,8 @@
 	$(hide) python $(HOST_OUT_EXECUTABLES)/treble_sepolicy_tests.py -l \
 		$(HOST_OUT)/lib64 -f $(PRIVATE_PLAT_FC) -f $(PRIVATE_NONPLAT_FC) \
 		-b $(PRIVATE_PLAT_SEPOLICY) -m $(PRIVATE_COMBINED_MAPPING) \
-		-o $(PRIVATE_SEPOLICY_OLD) -p $(PRIVATE_SEPOLICY)
+		-o $(PRIVATE_SEPOLICY_OLD) -p $(PRIVATE_SEPOLICY) \
+		$(PRIVATE_FAKE_TREBLE)
 	$(hide) touch $@
 
 26.0_PLAT_PUBLIC_POLICY :=
diff --git a/private/app_neverallows.te b/private/app_neverallows.te
index a3d7d49..dd0daeb 100644
--- a/private/app_neverallows.te
+++ b/private/app_neverallows.te
@@ -113,6 +113,9 @@
 # Avoid all access to kernel configuration
 neverallow all_untrusted_apps config_gz:file { no_rw_file_perms no_x_file_perms };
 
+# Only system_server can access proc_uid_time_in_state
+neverallow { domain -init -system_server } proc_uid_time_in_state:file *;
+
 # Do not allow untrusted apps access to preloads data files
 neverallow all_untrusted_apps preloads_data_file:file no_rw_file_perms;
 
diff --git a/private/compat/26.0/26.0.ignore.cil b/private/compat/26.0/26.0.ignore.cil
index 9a418de..9d5ce54 100644
--- a/private/compat/26.0/26.0.ignore.cil
+++ b/private/compat/26.0/26.0.ignore.cil
@@ -18,6 +18,7 @@
     mediaprovider_tmpfs
     netd_stable_secret_prop
     package_native_service
+    storaged_data_file
     sysfs_fs_ext4_features
     system_boot_reason_prop
     system_net_netd_hwservice
diff --git a/private/file.te b/private/file.te
index da5f9ad..7bd83f2 100644
--- a/private/file.te
+++ b/private/file.te
@@ -5,3 +5,6 @@
 
 # /proc/config.gz
 type config_gz, fs_type;
+
+# /data/misc/storaged
+type storaged_data_file, file_type, data_file_type, core_data_file_type;
diff --git a/private/file_contexts b/private/file_contexts
index ed51482..ffc601c 100644
--- a/private/file_contexts
+++ b/private/file_contexts
@@ -375,6 +375,7 @@
 /data/misc/recovery(/.*)?       u:object_r:recovery_data_file:s0
 /data/misc/shared_relro(/.*)?   u:object_r:shared_relro_file:s0
 /data/misc/sms(/.*)?            u:object_r:radio_data_file:s0
+/data/misc/storaged(/.*)?       u:object_r:storaged_data_file:s0
 /data/misc/systemkeys(/.*)?     u:object_r:systemkeys_data_file:s0
 /data/misc/textclassifier(/.*)?       u:object_r:textclassifier_data_file:s0
 /data/misc/user(/.*)?           u:object_r:misc_user_data_file:s0
diff --git a/private/storaged.te b/private/storaged.te
index 20377e0..8da1f26 100644
--- a/private/storaged.te
+++ b/private/storaged.te
@@ -15,6 +15,10 @@
 # Read /data/system/packages.list
 allow storaged system_data_file:file r_file_perms;
 
+# Store storaged proto file
+allow storaged storaged_data_file:dir rw_dir_perms;
+allow storaged storaged_data_file:file create_file_perms;
+
 userdebug_or_eng(`
   # Read access to debugfs
   allow storaged debugfs_mmc:dir search;
diff --git a/public/su.te b/public/su.te
index 8ddd162..88065f6 100644
--- a/public/su.te
+++ b/public/su.te
@@ -50,4 +50,47 @@
   dontaudit su domain:drmservice *;
   dontaudit su unlabeled:filesystem *;
   dontaudit su postinstall_file:filesystem *;
+
+  # VTS tests run in the permissive su domain on debug builds, but the HALs
+  # being tested run in enforcing mode. Because hal_foo_server is enforcing
+  # su needs to be declared as hal_foo_client to grant hal_foo_server
+  # permission to interact with it.
+  typeattribute su halclientdomain;
+  typeattribute su hal_allocator_client;
+  typeattribute su hal_audio_client;
+  typeattribute su hal_bluetooth_client;
+  typeattribute su hal_bootctl_client;
+  typeattribute su hal_camera_client;
+  typeattribute su hal_configstore_client;
+  typeattribute su hal_contexthub_client;
+  typeattribute su hal_drm_client;
+  typeattribute su hal_cas_client;
+  typeattribute su hal_dumpstate_client;
+  typeattribute su hal_fingerprint_client;
+  typeattribute su hal_gatekeeper_client;
+  typeattribute su hal_gnss_client;
+  typeattribute su hal_graphics_allocator_client;
+  typeattribute su hal_graphics_composer_client;
+  typeattribute su hal_health_client;
+  typeattribute su hal_ir_client;
+  typeattribute su hal_keymaster_client;
+  typeattribute su hal_light_client;
+  typeattribute su hal_memtrack_client;
+  typeattribute su hal_neuralnetworks_client;
+  typeattribute su hal_nfc_client;
+  typeattribute su hal_oemlock_client;
+  typeattribute su hal_power_client;
+  typeattribute su hal_sensors_client;
+  typeattribute su hal_telephony_client;
+  typeattribute su hal_tetheroffload_client;
+  typeattribute su hal_thermal_client;
+  typeattribute su hal_tv_cec_client;
+  typeattribute su hal_tv_input_client;
+  typeattribute su hal_usb_client;
+  typeattribute su hal_vibrator_client;
+  typeattribute su hal_vr_client;
+  typeattribute su hal_weaver_client;
+  typeattribute su hal_wifi_client;
+  typeattribute su hal_wifi_offload_client;
+  typeattribute su hal_wifi_supplicant_client;
 ')
diff --git a/tests/Android.bp b/tests/Android.bp
index 19aca9c..75bc91c 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -32,3 +32,10 @@
     host_supported: true,
     required: ["policy.py"],
 }
+
+cc_prebuilt_binary {
+    name: "searchpolicy.py",
+    srcs: ["searchpolicy.py"],
+    host_supported: true,
+    required: ["policy.py"],
+}
diff --git a/tests/include/sepol_wrap.h b/tests/include/sepol_wrap.h
index 5615913..2357421 100644
--- a/tests/include/sepol_wrap.h
+++ b/tests/include/sepol_wrap.h
@@ -9,6 +9,9 @@
 void *init_avtab(void *policydbp);
 void *init_cond_avtab(void *policydbp);
 void destroy_avtab(void *avtab_iterp);
+void *init_expanded_avtab(void *policydbp);
+void *init_expanded_cond_avtab(void *policydbp);
+void destroy_expanded_avtab(void *avtab_iterp);
 int get_type(char *out, size_t max_size, void *policydbp, void *type_iterp);
 void *init_type_iter(void *policydbp, const char *type, bool is_attr);
 void destroy_type_iter(void *type_iterp);
diff --git a/tests/policy.py b/tests/policy.py
index b8a3621..a0ddb90 100644
--- a/tests/policy.py
+++ b/tests/policy.py
@@ -41,7 +41,8 @@
         self.rule = rule
 
 class Policy:
-    __Rules = None
+    __ExpandedRules = set()
+    __Rules = set()
     __FcDict = None
     __libsepolwrap = None
     __policydbP = None
@@ -97,6 +98,50 @@
         self.__libsepolwrap.destroy_type_iter(TypeIterP)
         return TypeAttr
 
+    def __TERuleMatch(self, Rule, **kwargs):
+        # Match source type
+        if ("scontext" in kwargs and
+                len(kwargs['scontext']) > 0 and
+                Rule.sctx not in kwargs['scontext']):
+            return False
+        # Match target type
+        if ("tcontext" in kwargs and
+                len(kwargs['tcontext']) > 0 and
+                Rule.tctx not in kwargs['tcontext']):
+            return False
+        # Match target class
+        if ("tclass" in kwargs and
+                len(kwargs['tclass']) > 0 and
+                not bool(set([Rule.tclass]) & kwargs['tclass'])):
+            return False
+        # Match any perms
+        if ("perms" in kwargs and
+                len(kwargs['perms']) > 0 and
+                not bool(Rule.perms & kwargs['perms'])):
+            return False
+        return True
+
+    # resolve a type to its attributes or
+    # resolve an attribute to its types and attributes
+    # For example if scontext is the domain attribute, then we need to
+    # include all types with the domain attribute such as untrusted_app and
+    # priv_app and all the attributes of those types such as appdomain.
+    def ResolveTypeAttribute(self, Type):
+        types = self.GetAllTypes(False)
+        attributes = self.GetAllTypes(True)
+
+        if Type in types:
+            return self.QueryTypeAttribute(Type, False)
+        elif Type in attributes:
+            TypesAndAttributes = set()
+            Types = self.QueryTypeAttribute(Type, True)
+            TypesAndAttributes |= Types
+            for T in Types:
+                TypesAndAttributes |= self.QueryTypeAttribute(T, False)
+            return TypesAndAttributes
+        else:
+            return set()
+
     # Return all TERules that match:
     # (any scontext) or (any tcontext) or (any tclass) or (any perms),
     # perms.
@@ -106,23 +151,32 @@
     # Will return any rule with:
     # (tcontext="foo" or tcontext="bar") and ("entrypoint" in perms)
     def QueryTERule(self, **kwargs):
-        if self.__Rules is None:
+        if len(self.__Rules) == 0:
             self.__InitTERules()
-        for Rule in self.__Rules:
-            # Match source type
-            if "scontext" in kwargs and Rule.sctx not in kwargs['scontext']:
-                continue
-            # Match target type
-            if "tcontext" in kwargs and Rule.tctx not in kwargs['tcontext']:
-                continue
-            # Match target class
-            if "tclass" in kwargs and Rule.tclass not in kwargs['tclass']:
-                continue
-            # Match any perms
-            if "perms" in kwargs and not bool(Rule.perms & set(kwargs['perms'])):
-                continue
-            yield Rule
 
+        # add any matching types and attributes for scontext and tcontext
+        if ("scontext" in kwargs and len(kwargs['scontext']) > 0):
+            scontext = set()
+            for sctx in kwargs['scontext']:
+                scontext |= self.ResolveTypeAttribute(sctx)
+            kwargs['scontext'] = scontext
+        if ("tcontext" in kwargs and len(kwargs['tcontext']) > 0):
+            tcontext = set()
+            for tctx in kwargs['tcontext']:
+                tcontext |= self.ResolveTypeAttribute(tctx)
+            kwargs['tcontext'] = tcontext
+        for Rule in self.__Rules:
+            if self.__TERuleMatch(Rule, **kwargs):
+                yield Rule
+
+    # Same as QueryTERule but only using the expanded ruleset.
+    # i.e. all attributes have been expanded to their various types.
+    def QueryExpandedTERule(self, **kwargs):
+        if len(self.__ExpandedRules) == 0:
+            self.__InitExpandedTERules()
+        for Rule in self.__ExpandedRules:
+            if self.__TERuleMatch(Rule, **kwargs):
+                yield Rule
 
     def GetAllTypes(self, isAttr):
         TypeIterP = self.__libsepolwrap.init_type_iter(self.__policydbP, None, isAttr)
@@ -155,9 +209,9 @@
         return Types
 
 
-    def __GetTERules(self, policydbP, avtabIterP):
-        if self.__Rules is None:
-            self.__Rules = set()
+    def __GetTERules(self, policydbP, avtabIterP, Rules):
+        if Rules is None:
+            Rules = set()
         buf = create_string_buffer(self.__BUFSIZE)
         ret = 0
         while True:
@@ -165,7 +219,7 @@
                         policydbP, avtabIterP)
             if ret == 0:
                 Rule = TERule(buf.value)
-                self.__Rules.add(Rule)
+                Rules.add(Rule)
                 continue
             if ret == 1:
                 break;
@@ -176,14 +230,26 @@
         avtabIterP = self.__libsepolwrap.init_avtab(self.__policydbP)
         if (avtabIterP == None):
             sys.exit("Failed to initialize avtab")
-        self.__GetTERules(self.__policydbP, avtabIterP)
+        self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
         self.__libsepolwrap.destroy_avtab(avtabIterP)
         avtabIterP = self.__libsepolwrap.init_cond_avtab(self.__policydbP)
         if (avtabIterP == None):
             sys.exit("Failed to initialize conditional avtab")
-        self.__GetTERules(self.__policydbP, avtabIterP)
+        self.__GetTERules(self.__policydbP, avtabIterP, self.__Rules)
         self.__libsepolwrap.destroy_avtab(avtabIterP)
 
+    def __InitExpandedTERules(self):
+        avtabIterP = self.__libsepolwrap.init_expanded_avtab(self.__policydbP)
+        if (avtabIterP == None):
+            sys.exit("Failed to initialize avtab")
+        self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
+        self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
+        avtabIterP = self.__libsepolwrap.init_expanded_cond_avtab(self.__policydbP)
+        if (avtabIterP == None):
+            sys.exit("Failed to initialize conditional avtab")
+        self.__GetTERules(self.__policydbP, avtabIterP, self.__ExpandedRules)
+        self.__libsepolwrap.destroy_expanded_avtab(avtabIterP)
+
     # load ctypes-ified libsepol wrapper
     def __InitLibsepolwrap(self, LibPath):
         if "linux" in sys.platform:
@@ -201,6 +267,14 @@
         lib.load_policy.argtypes = [c_char_p]
         # void destroy_policy(void *policydbp);
         lib.destroy_policy.argtypes = [c_void_p]
+        # void *init_expanded_avtab(void *policydbp);
+        lib.init_expanded_avtab.restype = c_void_p
+        lib.init_expanded_avtab.argtypes = [c_void_p]
+        # void *init_expanded_cond_avtab(void *policydbp);
+        lib.init_expanded_cond_avtab.restype = c_void_p
+        lib.init_expanded_cond_avtab.argtypes = [c_void_p]
+        # void destroy_expanded_avtab(void *avtab_iterp);
+        lib.destroy_expanded_avtab.argtypes = [c_void_p]
         # void *init_avtab(void *policydbp);
         lib.init_avtab.restype = c_void_p
         lib.init_avtab.argtypes = [c_void_p]
diff --git a/tests/searchpolicy.py b/tests/searchpolicy.py
new file mode 100644
index 0000000..ff9318b
--- /dev/null
+++ b/tests/searchpolicy.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+
+import argparse
+import policy
+
+parser = argparse.ArgumentParser(
+    description="SELinux policy rule search tool. Intended to have a similar "
+        + "API as sesearch, but simplified to use only code availabe in AOSP")
+parser.add_argument("policy", help="Path to the SELinux policy to search.", nargs="?")
+parser.add_argument("--libpath", dest="libpath", help="Path to the libsepolwrap.so", nargs="?")
+tertypes = parser.add_argument_group("TE Rule Types")
+tertypes.add_argument("--allow", action="append_const",
+                    const="allow", dest="tertypes",
+                    help="Search allow rules.")
+expr = parser.add_argument_group("Expressions")
+expr.add_argument("-s", "--source",
+                  help="Source type/role of the TE/RBAC rule.")
+expr.add_argument("-t", "--target",
+                  help="Target type/role of the TE/RBAC rule.")
+expr.add_argument("-c", "--class", dest="tclass",
+                  help="Comma separated list of object classes")
+expr.add_argument("-p", "--perms", metavar="PERMS",
+                  help="Comma separated list of permissions.")
+
+args = parser.parse_args()
+
+if not args.tertypes:
+    parser.error("Must specify \"--allow\"")
+
+if not args.policy:
+    parser.error("Must include path to policy")
+if not args.libpath:
+    parser.error("Must include path to libsepolwrap library")
+
+if not (args.source or args.target or args.tclass or args.perms):
+    parser.error("Must something to filter on, e.g. --source, --target, etc.")
+
+pol = policy.Policy(args.policy, None, args.libpath)
+
+if args.source:
+    scontext = {args.source}
+else:
+    scontext = set()
+if args.target:
+    tcontext = {args.target}
+else:
+    tcontext = set()
+if args.tclass:
+    tclass = set(args.tclass.split(","))
+else:
+    tclass = set()
+if args.perms:
+    perms = set(args.perms.split(","))
+else:
+    perms = set()
+
+TERules = pol.QueryTERule(scontext=scontext,
+                       tcontext=tcontext,
+                       tclass=tclass,
+                       perms=perms)
+
+# format rules for printing
+rules = []
+for r in TERules:
+    if len(r.perms) > 1:
+        rules.append("allow " + r.sctx + " " + r.tctx + ":" + r.tclass + " { " +
+                " ".join(r.perms) + " };")
+    else:
+        rules.append("allow " + r.sctx + " " + r.tctx + ":" + r.tclass + " " +
+                " ".join(r.perms) + ";")
+
+for r in sorted(rules):
+    print r
diff --git a/tests/sepol_wrap.cpp b/tests/sepol_wrap.cpp
index 8fea2d5..d537b7e 100644
--- a/tests/sepol_wrap.cpp
+++ b/tests/sepol_wrap.cpp
@@ -181,7 +181,7 @@
 
 /* items needed to iterate over the avtab */
 struct avtab_iter {
-    avtab_t avtab;
+    avtab_t *avtab;
     uint32_t i;
     avtab_ptr_t cur;
 };
@@ -198,9 +198,9 @@
 {
     size_t len;
 
-    for (; avtab_i->i < avtab_i->avtab.nslot; (avtab_i->i)++) {
+    for (; avtab_i->i < avtab_i->avtab->nslot; (avtab_i->i)++) {
         if (avtab_i->cur == NULL) {
-            avtab_i->cur = avtab_i->avtab.htable[avtab_i->i];
+            avtab_i->cur = avtab_i->avtab->htable[avtab_i->i];
         }
         for (; avtab_i->cur; avtab_i->cur = (avtab_i->cur)->next) {
             if (!((avtab_i->cur)->key.specified & AVTAB_ALLOWED)) continue;
@@ -233,6 +233,37 @@
     return get_avtab_allow_rule(out, len, db, avtab_i);
 }
 
+static avtab_iter *init_avtab_common(avtab_t *in)
+{
+    struct avtab_iter *out = (struct avtab_iter *)
+                            calloc(1, sizeof(struct avtab_iter));
+    if (!out) {
+        std::cerr << "Failed to allocate avtab iterator" << std::endl;
+        return NULL;
+    }
+
+    out->avtab = in;
+    return out;
+}
+
+void *init_avtab(void *policydbp)
+{
+    policydb_t *p = static_cast<policydb_t *>(policydbp);
+    return static_cast<void *>(init_avtab_common(&p->te_avtab));
+}
+
+void *init_cond_avtab(void *policydbp)
+{
+    policydb_t *p = static_cast<policydb_t *>(policydbp);
+    return static_cast<void *>(init_avtab_common(&p->te_cond_avtab));
+}
+
+void destroy_avtab(void *avtab_iterp)
+{
+    struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
+    free(avtab_i);
+}
+
 /*
  * <sepol/policydb/expand.h->conditional.h> uses 'bool' as a variable name
  * inside extern "C" { .. } construct, which clang doesn't like.
@@ -240,45 +271,57 @@
  */
 extern "C" int expand_avtab(policydb_t *p, avtab_t *a, avtab_t *expa);
 
-static avtab_iter *init_avtab_common(avtab_t *in, policydb_t *p)
+static avtab_iter *init_expanded_avtab_common(avtab_t *in, policydb_t *p)
 {
     struct avtab_iter *out = (struct avtab_iter *)
                             calloc(1, sizeof(struct avtab_iter));
     if (!out) {
-        std::cerr << "Failed to allocate avtab" << std::endl;
+        std::cerr << "Failed to allocate avtab iterator" << std::endl;
         return NULL;
     }
 
-    if (avtab_init(&out->avtab)) {
-        std::cerr << "Failed to initialize avtab" << std::endl;
+    avtab_t *avtab = (avtab_t *) calloc(1, sizeof(avtab_t));
+
+    if (!avtab) {
+        std::cerr << "Failed to allocate avtab" << std::endl;
         free(out);
         return NULL;
     }
 
-    if (expand_avtab(p, in, &out->avtab)) {
+    out->avtab = avtab;
+    if (avtab_init(out->avtab)) {
+        std::cerr << "Failed to initialize avtab" << std::endl;
+        free(avtab);
+        free(out);
+        return NULL;
+    }
+
+    if (expand_avtab(p, in, out->avtab)) {
         std::cerr << "Failed to expand avtab" << std::endl;
+        free(avtab);
         free(out);
         return NULL;
     }
     return out;
 }
 
-void *init_avtab(void *policydbp)
+void *init_expanded_avtab(void *policydbp)
 {
     policydb_t *p = static_cast<policydb_t *>(policydbp);
-    return static_cast<void *>(init_avtab_common(&p->te_avtab, p));
+    return static_cast<void *>(init_expanded_avtab_common(&p->te_avtab, p));
 }
 
-void *init_cond_avtab(void *policydbp)
+void *init_expanded_cond_avtab(void *policydbp)
 {
     policydb_t *p = static_cast<policydb_t *>(policydbp);
-    return static_cast<void *>(init_avtab_common(&p->te_cond_avtab, p));
+    return static_cast<void *>(init_expanded_avtab_common(&p->te_cond_avtab, p));
 }
 
-void destroy_avtab(void *avtab_iterp)
+void destroy_expanded_avtab(void *avtab_iterp)
 {
     struct avtab_iter *avtab_i = static_cast<struct avtab_iter *>(avtab_iterp);
-    avtab_destroy(&avtab_i->avtab);
+    avtab_destroy(avtab_i->avtab);
+    free(avtab_i->avtab);
     free(avtab_i);
 }
 
diff --git a/tests/treble_sepolicy_tests.py b/tests/treble_sepolicy_tests.py
index 58fd85b..2c0cef3 100644
--- a/tests/treble_sepolicy_tests.py
+++ b/tests/treble_sepolicy_tests.py
@@ -76,6 +76,9 @@
 oldalltypes = set()
 compatMapping = None
 
+# Distinguish between PRODUCT_FULL_TREBLE and PRODUCT_FULL_TREBLE_OVERRIDE
+FakeTreble = False
+
 def GetAllDomains(pol):
     global alldomains
     for result in pol.QueryTypeAttribute("domain", True):
@@ -129,7 +132,7 @@
 #
 def GetDomainEntrypoints(pol):
     global alldomains
-    for x in pol.QueryTERule(tclass="file", perms=["entrypoint"]):
+    for x in pol.QueryExpandedTERule(tclass=set(["file"]), perms=set(["entrypoint"])):
         if not x.sctx in alldomains:
             continue
         alldomains[x.sctx].entrypoints.append(str(x.tctx))
@@ -172,6 +175,14 @@
     GetAllTypes(pol, oldpol)
     compatMapping = mapping
 
+def DomainsWithAttribute(attr):
+    global alldomains
+    domains = []
+    for domain in alldomains:
+        if attr in alldomains[domain].attributes:
+            domains.append(domain)
+    return domains
+
 #############################################################
 # Tests
 #############################################################
@@ -255,6 +266,26 @@
     ret = TestNoUnmappedNewTypes()
     ret += TestNoUnmappedRmTypes()
     return ret
+
+def TestViolatorAttribute(attribute):
+    global FakeTreble
+    ret = ""
+    if FakeTreble:
+        return ret
+
+    violators = DomainsWithAttribute(attribute)
+    if len(violators) > 0:
+        ret += "SELinux: The following domains violate the Treble ban "
+        ret += "against use of the " + attribute + " attribute: "
+        ret += " ".join(str(x) for x in sorted(violators)) + "\n"
+    return ret
+
+def TestViolatorAttributes():
+    ret = TestViolatorAttribute("binder_in_vendor_violators")
+    ret += TestViolatorAttribute("socket_between_core_and_vendor_violators")
+    ret += TestViolatorAttribute("vendor_executes_system_violators")
+    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
@@ -273,11 +304,13 @@
             Option.take_action(self, action, dest, opt, value, values, parser)
 
 Tests = {"CoredomainViolations": TestCoredomainViolations,
-         "TrebleCompatMapping": TestTrebleCompatMapping }
+         "TrebleCompatMapping": TestTrebleCompatMapping,
+         "ViolatorAttributes": TestViolatorAttributes}
 
 if __name__ == '__main__':
-    usage = "treble_sepolicy_tests.py -f nonplat_file_contexts -f "
-    usage +="plat_file_contexts -p curr_policy -b base_policy -o old_policy "
+    usage = "treble_sepolicy_tests.py -l out/host/linux-x86/lib64 "
+    usage += "-f nonplat_file_contexts -f plat_file_contexts "
+    usage += "-p curr_policy -b base_policy -o old_policy "
     usage +="-m mapping file [--test test] [--help]"
     parser = OptionParser(option_class=MultipleOption, usage=usage)
     parser.add_option("-b", "--basepolicy", dest="basepolicy", metavar="FILE")
@@ -288,8 +321,9 @@
     parser.add_option("-o", "--oldpolicy", dest="oldpolicy", metavar="FILE")
     parser.add_option("-p", "--policy", dest="policy", metavar="FILE")
     parser.add_option("-t", "--test", dest="tests", action="extend",
-
             help="Test options include "+str(Tests))
+    parser.add_option("--fake-treble", action="store_true", dest="faketreble",
+            default=False)
 
     (options, args) = parser.parse_args()
 
@@ -317,6 +351,9 @@
             sys.exit("Error: File_contexts file " + f + " does not exist\n" +
                     parser.usage)
 
+    if options.faketreble:
+        FakeTreble = True
+
     pol = policy.Policy(options.policy, options.file_contexts, options.libpath)
     setup(pol)
     basepol = policy.Policy(options.basepolicy, None, options.libpath)