aboutsummaryrefslogtreecommitdiffstats
path: root/tools/sepolicy-analyze/typecmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/sepolicy-analyze/typecmp.c')
-rw-r--r--tools/sepolicy-analyze/typecmp.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/tools/sepolicy-analyze/typecmp.c b/tools/sepolicy-analyze/typecmp.c
new file mode 100644
index 0000000..5fffd63
--- /dev/null
+++ b/tools/sepolicy-analyze/typecmp.c
@@ -0,0 +1,295 @@
+#include <getopt.h>
+#include <sepol/policydb/expand.h>
+
+#include "typecmp.h"
+
+void typecmp_usage() {
+ fprintf(stderr, "\ttypecmp [-d|--diff] [-e|--equiv]\n");
+}
+
+static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
+ struct avtab_node *type_rules)
+{
+ struct avtab_node *p, *c, *n;
+
+ for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
+ /*
+ * Find the insertion point, keeping the list
+ * ordered by source type, then target type, then
+ * target class.
+ */
+ if (k->source_type < c->key.source_type)
+ break;
+ if (k->source_type == c->key.source_type &&
+ k->target_type < c->key.target_type)
+ break;
+ if (k->source_type == c->key.source_type &&
+ k->target_type == c->key.target_type &&
+ k->target_class <= c->key.target_class)
+ break;
+ }
+
+ if (c &&
+ k->source_type == c->key.source_type &&
+ k->target_type == c->key.target_type &&
+ k->target_class == c->key.target_class) {
+ c->datum.data |= d->data;
+ return 0;
+ }
+
+ /* Insert the rule */
+ n = malloc(sizeof(struct avtab_node));
+ if (!n) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ n->key = *k;
+ n->datum = *d;
+ n->next = p->next;
+ p->next = n;
+ return 0;
+}
+
+static int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d,
+ void *args)
+{
+ struct avtab_node *type_rules = args;
+ avtab_key_t key;
+
+ /*
+ * Insert the rule into the list for
+ * the source type. The source type value
+ * is cleared as we want to compare against other type
+ * rules with different source types.
+ */
+ key = *k;
+ key.source_type = 0;
+ if (k->source_type == k->target_type) {
+ /* Clear target type as well; this is a self rule. */
+ key.target_type = 0;
+ }
+ if (insert_type_rule(&key, d, &type_rules[k->source_type - 1]))
+ return -1;
+
+ if (k->source_type == k->target_type)
+ return 0;
+
+ /*
+ * If the target type differs, then we also
+ * insert the rule into the list for the target
+ * type. We clear the target type value so that
+ * we can compare against other type rules with
+ * different target types.
+ */
+ key = *k;
+ key.target_type = 0;
+ if (insert_type_rule(&key, d, &type_rules[k->target_type - 1]))
+ return -1;
+
+ return 0;
+}
+
+static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
+{
+ if (k->specified & AVTAB_ALLOWED)
+ return create_type_rules_helper(k, d, args);
+ return 0;
+}
+
+static int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d,
+ void *args)
+{
+ if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) ==
+ (AVTAB_ALLOWED|AVTAB_ENABLED))
+ return create_type_rules_helper(k, d, args);
+ return 0;
+}
+
+static void free_type_rules(struct avtab_node *l)
+{
+ struct avtab_node *tmp;
+
+ while (l) {
+ tmp = l;
+ l = l->next;
+ free(tmp);
+ }
+}
+
+static int find_match(policydb_t *policydb, struct avtab_node *l1,
+ int idx1, struct avtab_node *l2, int idx2)
+{
+ struct avtab_node *c;
+ uint32_t perms1, perms2;
+
+ for (c = l2; c; c = c->next) {
+ if (l1->key.source_type < c->key.source_type)
+ break;
+ if (l1->key.source_type == c->key.source_type &&
+ l1->key.target_type < c->key.target_type)
+ break;
+ if (l1->key.source_type == c->key.source_type &&
+ l1->key.target_type == c->key.target_type &&
+ l1->key.target_class <= c->key.target_class)
+ break;
+ }
+
+ if (c &&
+ l1->key.source_type == c->key.source_type &&
+ l1->key.target_type == c->key.target_type &&
+ l1->key.target_class == c->key.target_class) {
+ perms1 = l1->datum.data & ~c->datum.data;
+ perms2 = c->datum.data & ~l1->datum.data;
+ if (perms1 || perms2) {
+ if (perms1)
+ display_allow(policydb, &l1->key, idx1, perms1);
+ if (perms2)
+ display_allow(policydb, &c->key, idx2, perms2);
+ printf("\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int analyze_types(policydb_t * policydb, char diff, char equiv)
+{
+ avtab_t exp_avtab, exp_cond_avtab;
+ struct avtab_node *type_rules, *l1, *l2;
+ struct type_datum *type;
+ size_t i, j;
+
+ /*
+ * Create a list of access vector rules for each type
+ * from the access vector table.
+ */
+ type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim);
+ if (!type_rules) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim);
+
+ if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) {
+ fputs("out of memory\n", stderr);
+ return -1;
+ }
+
+ if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) {
+ fputs("out of memory\n", stderr);
+ avtab_destroy(&exp_avtab);
+ return -1;
+ }
+
+ if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) {
+ fputs("out of memory\n", stderr);
+ avtab_destroy(&exp_avtab); /* */
+ return -1;
+ }
+
+ if (avtab_map(&exp_avtab, create_type_rules, type_rules))
+ exit(1);
+
+ if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules))
+ exit(1);
+
+ avtab_destroy(&exp_avtab);
+ avtab_destroy(&exp_cond_avtab);
+
+ /*
+ * Compare the type lists and identify similar types.
+ */
+ for (i = 0; i < policydb->p_types.nprim - 1; i++) {
+ if (!type_rules[i].next)
+ continue;
+ type = policydb->type_val_to_struct[i];
+ if (type->flavor) {
+ free_type_rules(type_rules[i].next);
+ type_rules[i].next = NULL;
+ continue;
+ }
+ for (j = i + 1; j < policydb->p_types.nprim; j++) {
+ type = policydb->type_val_to_struct[j];
+ if (type->flavor) {
+ free_type_rules(type_rules[j].next);
+ type_rules[j].next = NULL;
+ continue;
+ }
+ for (l1 = type_rules[i].next, l2 = type_rules[j].next;
+ l1 && l2; l1 = l1->next, l2 = l2->next) {
+ if (l1->key.source_type != l2->key.source_type)
+ break;
+ if (l1->key.target_type != l2->key.target_type)
+ break;
+ if (l1->key.target_class != l2->key.target_class
+ || l1->datum.data != l2->datum.data)
+ break;
+ }
+ if (l1 || l2) {
+ if (diff) {
+ printf
+ ("Types %s and %s differ, starting with:\n",
+ policydb->p_type_val_to_name[i],
+ policydb->p_type_val_to_name[j]);
+
+ if (l1 && l2) {
+ if (find_match(policydb, l1, i, l2, j))
+ continue;
+ if (find_match(policydb, l2, j, l1, i))
+ continue;
+ }
+ if (l1)
+ display_allow(policydb, &l1->key, i, l1->datum.data);
+ if (l2)
+ display_allow(policydb, &l2->key, j, l2->datum.data);
+ printf("\n");
+ }
+ continue;
+ }
+ free_type_rules(type_rules[j].next);
+ type_rules[j].next = NULL;
+ if (equiv) {
+ printf("Types %s and %s are equivalent.\n",
+ policydb->p_type_val_to_name[i],
+ policydb->p_type_val_to_name[j]);
+ }
+ }
+ free_type_rules(type_rules[i].next);
+ type_rules[i].next = NULL;
+ }
+
+ free(type_rules);
+ return 0;
+}
+
+int typecmp_func (int argc, char **argv, policydb_t *policydb) {
+ char ch, diff = 0, equiv = 0;
+
+ struct option typecmp_options[] = {
+ {"diff", no_argument, NULL, 'd'},
+ {"equiv", no_argument, NULL, 'e'},
+ {NULL, 0, NULL, 0}
+ };
+
+ while ((ch = getopt_long(argc, argv, "de", typecmp_options, NULL)) != -1) {
+ switch (ch) {
+ case 'd':
+ diff = 1;
+ break;
+ case 'e':
+ equiv = 1;
+ break;
+ default:
+ USAGE_ERROR = true;
+ return -1;
+ }
+ }
+
+ if (!(diff || equiv)) {
+ USAGE_ERROR = true;
+ return -1;
+ }
+ return analyze_types(policydb, diff, equiv);
+}