From 1b8284444c088f5310879231bf3d62104bdaf324 Mon Sep 17 00:00:00 2001
From: Jeff Vander Stoep <jeffv@google.com>
Date: Wed, 21 Mar 2018 17:27:20 -0700
Subject: [PATCH] Assert types labeled in genfs_contexts have correct
 attributes

Types in sysfs should have the sysfs_type attribute, types in
debugfs and tracefs should have the debugfs_type attribute.

TODO: Test that files in procfs have the proc_type attribute.
TODO: Assert these tests in CTS.

Bug: 74182216
Test: build - these are build-time tests.
Change-Id: Icf0ff2a26c05f94da421ba23df0b92d8eef906bf
---
 tests/include/sepol_wrap.h |  3 ++
 tests/policy.py            | 51 +++++++++++++++++++++++++++++
 tests/sepol_wrap.cpp       | 67 ++++++++++++++++++++++++++++++++++++++
 tests/sepolicy_tests.py    | 10 ++++--
 4 files changed, 128 insertions(+), 3 deletions(-)

diff --git a/tests/include/sepol_wrap.h b/tests/include/sepol_wrap.h
index 2357421c7..0be2c1726 100644
--- a/tests/include/sepol_wrap.h
+++ b/tests/include/sepol_wrap.h
@@ -15,6 +15,9 @@ 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);
+void *init_genfs_iter(void *policydbp);
+int get_genfs(char *out, size_t max_size, void *policydbp, void *genfs_iterp);
+void destroy_genfs_iter(void *genfs_iterp);
 
 #ifdef __cplusplus
 }
diff --git a/tests/policy.py b/tests/policy.py
index b51ebf237..90e387fb9 100644
--- a/tests/policy.py
+++ b/tests/policy.py
@@ -47,6 +47,7 @@ class Policy:
     __Rules = set()
     __FcDict = None
     __FcSorted = None
+    __GenfsDict = None
     __libsepolwrap = None
     __policydbP = None
     __BUFSIZE = 2048
@@ -66,6 +67,21 @@ class Policy:
             ret += " ".join(str(x) for x in sorted(violators)) + "\n"
         return ret
 
+    # Check that all types for "filesystem" have "attribute" associated with them
+    # for types labeled in genfs_contexts.
+    def AssertGenfsFilesystemTypesHaveAttr(self, Filesystem, Attr):
+        TypesPol = self.QueryTypeAttribute(Attr, True)
+        TypesGenfs = self.__GenfsDict[Filesystem]
+        violators = TypesGenfs.difference(TypesPol)
+
+        ret = ""
+        if len(violators) > 0:
+            ret += "The following types in " + Filesystem
+            ret += " must be associated with the "
+            ret += "\"" + Attr + "\" attribute: "
+            ret += " ".join(str(x) for x in sorted(violators)) + "\n"
+        return ret
+
     # Check that path prefixes that match MatchPrefix, and do not Match
     # DoNotMatchPrefix have the attribute Attr.
     # For example assert that all types in /sys, and not in /sys/kernel/debugfs
@@ -337,9 +353,43 @@ class Policy:
         lib.init_type_iter.argtypes = [c_void_p, c_char_p, c_bool]
         # void destroy_type_iter(void *type_iterp);
         lib.destroy_type_iter.argtypes = [c_void_p]
+        # void *init_genfs_iter(void *policydbp)
+        lib.init_genfs_iter.restype = c_void_p
+        lib.init_genfs_iter.argtypes = [c_void_p]
+        # int get_genfs(char *out, size_t max_size, void *genfs_iterp);
+        lib.get_genfs.restype = c_int
+        lib.get_genfs.argtypes = [c_char_p, c_size_t, c_void_p, c_void_p]
+        # void destroy_genfs_iter(void *genfs_iterp)
+        lib.destroy_genfs_iter.argtypes = [c_void_p]
 
         self.__libsepolwrap = lib
 
+    def __GenfsDictAdd(self, Dict, buf):
+        fs, path, context = buf.split(" ")
+        Type = context.split(":")[2]
+        if not fs in Dict:
+            Dict[fs] = {Type}
+        else:
+            Dict[fs].add(Type)
+
+    def __InitGenfsCon(self):
+        self.__GenfsDict = {}
+        GenfsIterP = self.__libsepolwrap.init_genfs_iter(self.__policydbP)
+        if (GenfsIterP == None):
+            sys.exit("Failed to retreive genfs entries")
+        buf = create_string_buffer(self.__BUFSIZE)
+        while True:
+            ret = self.__libsepolwrap.get_genfs(buf, self.__BUFSIZE,
+                        self.__policydbP, GenfsIterP)
+            if ret == 0:
+                self.__GenfsDictAdd(self.__GenfsDict, buf.value)
+                continue
+            if ret == 1:
+                self.__GenfsDictAdd(self.__GenfsDict, buf.value)
+                break;
+            # We should never get here.
+            sys.exit("Failed to get genfs entries")
+        self.__libsepolwrap.destroy_genfs_iter(GenfsIterP)
 
     # load file_contexts
     def __InitFC(self, FcPaths):
@@ -376,6 +426,7 @@ class Policy:
         self.__InitLibsepolwrap(LibPath)
         self.__InitFC(FcPaths)
         self.__InitPolicy(PolicyPath)
+        self.__InitGenfsCon()
 
     def __del__(self):
         if self.__policydbP is not None:
diff --git a/tests/sepol_wrap.cpp b/tests/sepol_wrap.cpp
index d537b7e00..39b618b90 100644
--- a/tests/sepol_wrap.cpp
+++ b/tests/sepol_wrap.cpp
@@ -17,6 +17,73 @@
 #include <android-base/strings.h>
 #include <sepol_wrap.h>
 
+struct genfs_iter {
+    genfs_t *genfs;
+    ocontext_t *ocon;
+};
+
+void *init_genfs_iter(void *policydbp)
+{
+    struct genfs_iter *out = (struct genfs_iter *)
+                            calloc(1, sizeof(struct genfs_iter));
+
+    if (!out) {
+        std::cerr << "Failed to allocate genfs iterator" << std::endl;
+        return NULL;
+    }
+
+    policydb_t *db = static_cast<policydb_t *>(policydbp);
+
+    out->genfs = db->genfs;
+    out->ocon = db->genfs->head;
+
+    return static_cast<void *>(out);
+}
+
+/*
+ * print genfs path into *out buffer.
+ *
+ * Returns -1 on error.
+ * Returns 0 on successfully retrieving a genfs entry.
+ * Returns 1 on successfully retrieving the final genfs entry.
+ */
+int get_genfs(char *out, size_t max_size, void *policydbp, void *genfs_iterp)
+{
+    size_t len;
+    struct genfs_iter *i = static_cast<struct genfs_iter *>(genfs_iterp);
+    policydb_t *db = static_cast<policydb_t *>(policydbp);
+
+    len = snprintf(out, max_size, "%s %s %s:%s:%s:s0",
+            i->genfs->fstype,
+            i->ocon->u.name,
+            db->p_user_val_to_name[i->ocon->context->user-1],
+            db->p_role_val_to_name[i->ocon->context->role-1],
+            db->p_type_val_to_name[i->ocon->context->type-1]);
+
+    if (len >= max_size) {
+        std::cerr << "genfs path exceeds buffer size." << std::endl;
+        return -1;
+    }
+
+    i->ocon = i->ocon->next;
+    if (i->ocon == NULL) {
+        if (i->genfs->next != NULL) {
+            i->genfs = i->genfs->next;
+            i->ocon = i->genfs->head;
+        } else {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+void destroy_genfs_iter(void *genfs_iterp)
+{
+    struct genfs_iter *genfs_i = static_cast<struct genfs_iter *>(genfs_iterp);
+    free(genfs_i);
+}
+
 #define TYPE_ITER_LOOKUP   0
 #define TYPE_ITER_ALLTYPES 1
 #define TYPE_ITER_ALLATTRS 2
diff --git a/tests/sepolicy_tests.py b/tests/sepolicy_tests.py
index 2cf4ae814..b09c60bc3 100644
--- a/tests/sepolicy_tests.py
+++ b/tests/sepolicy_tests.py
@@ -12,13 +12,17 @@ def TestDataTypeViolations(pol):
     return pol.AssertPathTypesHaveAttr(["/data/"], [], "data_file_type")
 
 def TestSysfsTypeViolations(pol):
-    return pol.AssertPathTypesHaveAttr(["/sys/"], ["/sys/kernel/debug/",
+    ret = pol.AssertGenfsFilesystemTypesHaveAttr("sysfs", "sysfs_type")
+    ret += pol.AssertPathTypesHaveAttr(["/sys/"], ["/sys/kernel/debug/",
                                     "/sys/kernel/tracing"], "sysfs_type")
+    return ret
 
 def TestDebugfsTypeViolations(pol):
-    # TODO: this should apply to genfs_context entries as well
-    return pol.AssertPathTypesHaveAttr(["/sys/kernel/debug/",
+    ret = pol.AssertGenfsFilesystemTypesHaveAttr("debugfs", "debugfs_type")
+    ret += pol.AssertGenfsFilesystemTypesHaveAttr("tracefs", "debugfs_type")
+    ret += pol.AssertPathTypesHaveAttr(["/sys/kernel/debug/",
                                     "/sys/kernel/tracing"], [], "debugfs_type")
+    return ret
 
 def TestVendorTypeViolations(pol):
     return pol.AssertPathTypesHaveAttr(["/vendor/"], [], "vendor_file_type")
-- 
GitLab