From 43b9cfd3561e16225563610f1eb794eb73d0845f Mon Sep 17 00:00:00 2001
From: Stephen Smalley <sds@tycho.nsa.gov>
Date: Tue, 17 Jun 2014 14:32:46 -0400
Subject: [PATCH] Refine sepolicy-analyze -D / dup detection.

We were incorrectly reporting overlapping rules as duplicates.
Only report cases where an attribute-based rule is a superset
of type-based rule.  Also omit self rules as they are often due
to expansion of domain self rules by checkpolicy.

Change-Id: I27f33cdf9467be5fdb6ce148aa0006d407291833
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
---
 tools/sepolicy-analyze.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/tools/sepolicy-analyze.c b/tools/sepolicy-analyze.c
index 1901033a4..3cef01256 100644
--- a/tools/sepolicy-analyze.c
+++ b/tools/sepolicy-analyze.c
@@ -11,6 +11,7 @@
 #include <sepol/policydb/services.h>
 #include <sepol/policydb/expand.h>
 #include <sepol/policydb/util.h>
+#include <stdbool.h>
 
 void usage(char *arg0)
 {
@@ -343,15 +344,23 @@ static int find_dups_helper(avtab_key_t * k, avtab_datum_t * d,
     unsigned int i, j;
     avtab_key_t avkey;
     avtab_ptr_t node;
+    struct type_datum *stype, *ttype, *stype2, *ttype2;
+    bool attrib1, attrib2;
 
     if (!(k->specified & AVTAB_ALLOWED))
         return 0;
 
+    if (k->source_type == k->target_type)
+        return 0; /* self rule */
+
     avkey.target_class = k->target_class;
     avkey.specified = k->specified;
 
     sattr = &policydb->type_attr_map[k->source_type - 1];
     tattr = &policydb->type_attr_map[k->target_type - 1];
+    stype = policydb->type_val_to_struct[k->source_type - 1];
+    ttype = policydb->type_val_to_struct[k->target_type - 1];
+    attrib1 = stype->flavor || ttype->flavor;
     ebitmap_for_each_bit(sattr, snode, i) {
         if (!ebitmap_node_get_bit(snode, i))
             continue;
@@ -363,14 +372,26 @@ static int find_dups_helper(avtab_key_t * k, avtab_datum_t * d,
             if (avkey.source_type == k->source_type &&
                 avkey.target_type == k->target_type)
                 continue;
+            if (avkey.source_type == avkey.target_type)
+                continue; /* self rule */
+            stype2 = policydb->type_val_to_struct[avkey.source_type - 1];
+            ttype2 = policydb->type_val_to_struct[avkey.target_type - 1];
+            attrib2 = stype2->flavor || ttype2->flavor;
+            if (attrib1 && attrib2)
+                continue; /* overlapping attribute-based rules */
             for (node = avtab_search_node(&policydb->te_avtab, &avkey);
                  node != NULL;
                  node = avtab_search_node_next(node, avkey.specified)) {
-                if (node->datum.data & d->data) {
-                    uint32_t perms = node->datum.data & d->data;
+                uint32_t perms = node->datum.data & d->data;
+                if ((attrib1 && perms == node->datum.data) ||
+                    (attrib2 && perms == d->data)) {
+                    /*
+                     * The attribute-based rule is a superset of the
+                     * non-attribute-based rule.  This is a dup.
+                     */
                     printf("Duplicate allow rule found:\n");
-                    display_allow(policydb, k, i, perms);
-                    display_allow(policydb, &node->key, i, perms);
+                    display_allow(policydb, k, i, d->data);
+                    display_allow(policydb, &node->key, i, node->datum.data);
                     printf("\n");
                 }
             }
-- 
GitLab