summaryrefslogtreecommitdiffstats
path: root/libpoldiff/src/type_map.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpoldiff/src/type_map.c')
-rw-r--r--libpoldiff/src/type_map.c985
1 files changed, 985 insertions, 0 deletions
diff --git a/libpoldiff/src/type_map.c b/libpoldiff/src/type_map.c
new file mode 100644
index 0000000..ff97c43
--- /dev/null
+++ b/libpoldiff/src/type_map.c
@@ -0,0 +1,985 @@
+/**
+ * @file
+ * Implementation of type equivalence mapping for semantic
+ * difference calculations.
+ * The mapping of types is handled by creating a list of pseudo type
+ * values to represent the set of all semantically unique types in
+ * both the original and modified policies. This mapping takes into
+ * account both inferred and user specified mappings of types and may
+ * contain holes where a type does not exist in one of the policies.
+ *
+ * @author Jeremy A. Mowery jmowery@tresys.com
+ * @author Jason Tang jtang@tresys.com
+ *
+ * Copyright (C) 2006-2007 Tresys Technology, LLC
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "poldiff_internal.h"
+
+#include <apol/policy-query.h>
+#include <apol/util.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * A poldiff's type map consists of maps between policies' types to a
+ * unified pseudo-type value.
+ */
+struct type_map
+{
+ /** array of size num_orig_types mapping types by (value - 1)
+ to pseudo value */
+ uint32_t *orig_to_pseudo;
+ /** array of size num_mod_types mapping types by (value - 1)
+ to pseudo value */
+ uint32_t *mod_to_pseudo;
+ /** vector of vector of qpol_type_t that reverse map pseudo
+ value to orig_pol value(s) */
+ apol_vector_t *pseudo_to_orig;
+ /** vector of vector of qpol_type_t that reverse map pseudo
+ value to mod_pol value(s) */
+ apol_vector_t *pseudo_to_mod;
+ size_t num_orig_types;
+ size_t num_mod_types;
+ /** vector of poldiff_type_remap_entry_t */
+ apol_vector_t *remap;
+};
+
+/**
+ * Each map entry consists of 2 vectors, each vector being a list of
+ * qpol_type_t.
+ */
+struct poldiff_type_remap_entry
+{
+ /** vector of names of qpol_type_t in original qpolicy */
+ apol_vector_t *orig_types;
+ /** vector of names of qpol_type_t in the modified qpolicy */
+ apol_vector_t *mod_types;
+ int inferred;
+ int enabled;
+};
+
+/**
+ * Free the space associated with a singly type remap entry.
+ *
+ * @param elem Pointer to a type remap entry to free. If NULL then do
+ * nothing.
+ */
+static void type_remap_entry_free(void *elem)
+{
+ poldiff_type_remap_entry_t *entry = (poldiff_type_remap_entry_t *) elem;
+ if (entry != NULL) {
+ apol_vector_destroy(&entry->orig_types);
+ apol_vector_destroy(&entry->mod_types);
+ free(entry);
+ }
+}
+
+/**
+ * Allocate a new poldiff type remap entry, append it to the current
+ * type remap vector, enable it, and return the entry.
+ *
+ * @param diff Policy diff structure containing remap vector.
+ *
+ * @return a new entry, or NULL on error.
+ */
+static poldiff_type_remap_entry_t *poldiff_type_remap_entry_create(poldiff_t * diff)
+{
+ poldiff_type_remap_entry_t *e = NULL;
+ if ((e = calloc(1, sizeof(*e))) == NULL ||
+ (e->orig_types = apol_vector_create_with_capacity(1, free)) == NULL ||
+ (e->mod_types = apol_vector_create_with_capacity(1, free)) == NULL || apol_vector_append(diff->type_map->remap, e) < 0)
+ {
+ type_remap_entry_free(e);
+ return NULL;
+ }
+ diff->remapped = 1;
+ e->enabled = 1;
+ return e;
+}
+
+int poldiff_type_remap_create(poldiff_t * diff, const apol_vector_t * orig_names, const apol_vector_t * mod_names)
+{
+ poldiff_type_remap_entry_t *entry = NULL;
+ size_t i;
+ char *name;
+ const qpol_type_t *type;
+ unsigned char isalias, isattr;
+ int retval = -1, error = 0;
+ if (diff == NULL || orig_names == NULL || mod_names == NULL) {
+ error = EINVAL;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ if (apol_vector_get_size(orig_names) == 0 ||
+ apol_vector_get_size(mod_names) == 0 || (apol_vector_get_size(orig_names) > 1 && apol_vector_get_size(mod_names) > 1)) {
+ error = EINVAL;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ if ((entry = calloc(1, sizeof(*entry))) == NULL ||
+ (entry->orig_types = apol_vector_create_with_capacity(1, free)) == NULL ||
+ (entry->mod_types = apol_vector_create_with_capacity(1, free)) == NULL) {
+ error = ENOMEM;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ for (i = 0; i < apol_vector_get_size(orig_names); i++) {
+ name = (char *)apol_vector_get_element(orig_names, i);
+ if (qpol_policy_get_type_by_name(diff->orig_qpol, name, &type) < 0 ||
+ qpol_type_get_isalias(diff->orig_qpol, type, &isalias) < 0 ||
+ qpol_type_get_isattr(diff->orig_qpol, type, &isattr) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (isalias || isattr) {
+ error = EINVAL;
+ ERR(diff, "%s is not a primary type.", name);
+ goto cleanup;
+ }
+ if ((name = strdup(name)) == NULL || apol_vector_append(entry->orig_types, (void *)name) < 0) {
+ error = ENOMEM;
+ free(name);
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ }
+ apol_vector_sort_uniquify(entry->orig_types, apol_str_strcmp, NULL);
+ for (i = 0; i < apol_vector_get_size(mod_names); i++) {
+ name = (char *)apol_vector_get_element(mod_names, i);
+ if (qpol_policy_get_type_by_name(diff->mod_qpol, name, &type) < 0 ||
+ qpol_type_get_isalias(diff->mod_qpol, type, &isalias) < 0 ||
+ qpol_type_get_isattr(diff->mod_qpol, type, &isattr) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (isalias || isattr) {
+ error = EINVAL;
+ ERR(diff, "%s is not a primary type.", name);
+ goto cleanup;
+ }
+ if ((name = strdup(name)) == NULL || apol_vector_append(entry->mod_types, (void *)name) < 0) {
+ error = ENOMEM;
+ free(name);
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ }
+ apol_vector_sort_uniquify(entry->mod_types, apol_str_strcmp, NULL);
+ entry->enabled = 1;
+ if (apol_vector_append(diff->type_map->remap, entry) < 0) {
+ error = ENOMEM;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ retval = 0;
+ diff->remapped = 1;
+ cleanup:
+ if (retval < 0) {
+ type_remap_entry_free(entry);
+ }
+ errno = error;
+ return retval;
+}
+
+apol_vector_t *poldiff_type_remap_get_entries(const poldiff_t * diff)
+{
+ if (diff == NULL || diff->type_map == NULL) {
+ ERR(diff, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return NULL;
+ }
+ return diff->type_map->remap;
+}
+
+void poldiff_type_remap_entry_remove(poldiff_t * diff, poldiff_type_remap_entry_t * entry)
+{
+ size_t idx;
+ if (diff == NULL || entry == NULL) {
+ ERR(diff, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return;
+ }
+ if (apol_vector_get_index(diff->type_map->remap, entry, NULL, NULL, &idx) < 0) {
+ ERR(diff, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return;
+ }
+ apol_vector_remove(diff->type_map->remap, idx);
+ diff->remapped = 1;
+}
+
+apol_vector_t *poldiff_type_remap_entry_get_original_types(const poldiff_t * diff, const poldiff_type_remap_entry_t * entry)
+{
+ if (diff == NULL || entry == NULL) {
+ ERR(diff, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_vector_create_from_vector(entry->orig_types, NULL, NULL, NULL);
+}
+
+apol_vector_t *poldiff_type_remap_entry_get_modified_types(const poldiff_t * diff, const poldiff_type_remap_entry_t * entry)
+{
+ if (diff == NULL || entry == NULL) {
+ ERR(diff, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return NULL;
+ }
+ return apol_vector_create_from_vector(entry->mod_types, NULL, NULL, NULL);
+}
+
+int poldiff_type_remap_entry_get_is_inferred(const poldiff_type_remap_entry_t * entry)
+{
+ if (entry == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return entry->inferred;
+}
+
+int poldiff_type_remap_entry_get_is_enabled(const poldiff_type_remap_entry_t * entry)
+{
+ if (entry == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ return entry->enabled;
+}
+
+void poldiff_type_remap_entry_set_enabled(poldiff_type_remap_entry_t * entry, int enabled)
+{
+ if (entry == NULL) {
+ errno = EINVAL;
+ return;
+ }
+ if (enabled) {
+ entry->enabled = 1;
+ } else {
+ entry->enabled = 0;
+ }
+}
+
+type_map_t *type_map_create(void)
+{
+ type_map_t *map = calloc(1, sizeof(*map));
+ if (map == NULL) {
+ return NULL;
+ }
+ if ((map->remap = apol_vector_create(type_remap_entry_free)) == NULL) {
+ type_map_destroy(&map);
+ return NULL;
+ }
+ return map;
+}
+
+void type_map_destroy(type_map_t ** map)
+{
+ if (map != NULL && *map != NULL) {
+ free((*map)->orig_to_pseudo);
+ free((*map)->mod_to_pseudo);
+ apol_vector_destroy(&(*map)->pseudo_to_orig);
+ apol_vector_destroy(&(*map)->pseudo_to_mod);
+ apol_vector_destroy(&(*map)->remap);
+ free(*map);
+ *map = NULL;
+ }
+}
+
+/**
+ * If --enable-debug is given, then dump to stdout the type map from
+ * policy's types -> pseudo-types.
+ */
+static void type_map_dump(poldiff_t * diff)
+{
+#ifdef SETOOLS_DEBUG
+ size_t i, j;
+ apol_vector_t *v;
+ const qpol_type_t *t;
+ const char *name;
+ printf("# type map debug dump (qpol_type_t -> pseudo-type):\norig:\n");
+ for (i = 0; i < diff->type_map->num_orig_types; i++) {
+ printf("%3zd:%5d", i, diff->type_map->orig_to_pseudo[i]);
+ if ((i + 1) % 5 == 0) {
+ printf("\n");
+ } else {
+ printf("\t");
+ }
+ }
+ for (i = 0; i < apol_vector_get_size(diff->type_map->pseudo_to_orig); i++) {
+ v = apol_vector_get_element(diff->type_map->pseudo_to_orig, i);
+ printf("\n%3zd->", i);
+ for (j = 0; j < apol_vector_get_size(v); j++) {
+ t = apol_vector_get_element(v, j);
+ qpol_type_get_name(diff->orig_qpol, t, &name);
+ printf(" %s", name);
+ }
+ }
+ printf("\nmod:\n");
+ for (i = 0; i < diff->type_map->num_mod_types; i++) {
+ printf("%3zd:%5d", i, diff->type_map->mod_to_pseudo[i]);
+ if ((i + 1) % 5 == 0) {
+ printf("\n");
+ } else {
+ printf("\t");
+ }
+ }
+ for (i = 0; i < apol_vector_get_size(diff->type_map->pseudo_to_mod); i++) {
+ v = apol_vector_get_element(diff->type_map->pseudo_to_mod, i);
+ printf("\n%3zd->", i);
+ for (j = 0; j < apol_vector_get_size(v); j++) {
+ t = apol_vector_get_element(v, j);
+ qpol_type_get_name(diff->mod_qpol, t, &name);
+ printf(" %s", name);
+ }
+ }
+ printf("\n");
+#endif
+}
+
+/**
+ * Free a vector of qpol_type_t pointers.
+ */
+static void type_map_vector_free(void *elem)
+{
+ apol_vector_t *v = (apol_vector_t *) elem;
+ if (v != NULL) {
+ apol_vector_destroy(&v);
+ }
+}
+
+int type_map_build(poldiff_t * diff)
+{
+ type_map_t *map;
+ apol_vector_t *ov = NULL, *mv = NULL;
+ int retval = -1, error = 0;
+ size_t i, j;
+ const qpol_type_t *t;
+ uint32_t val, max_val, next_val;
+ apol_vector_t *reverse_v = NULL;
+
+ map = diff->type_map;
+ free(map->orig_to_pseudo);
+ map->orig_to_pseudo = NULL;
+ map->num_orig_types = 0;
+ free(map->mod_to_pseudo);
+ map->mod_to_pseudo = NULL;
+ map->num_mod_types = 0;
+ apol_vector_destroy(&map->pseudo_to_orig);
+ apol_vector_destroy(&map->pseudo_to_mod);
+
+ if (apol_type_get_by_query(diff->orig_pol, NULL, &ov) < 0 || apol_type_get_by_query(diff->mod_pol, NULL, &mv) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+
+ /* there is no guarantee that the number of types is equal to
+ * the highest type value (because a policy could have
+ * attributes), so calculate them here */
+ max_val = 0;
+ for (i = 0; i < apol_vector_get_size(ov); i++) {
+ t = (qpol_type_t *) apol_vector_get_element(ov, i);
+ if (qpol_type_get_value(diff->orig_qpol, t, &val) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (val > max_val) {
+ max_val = val;
+ }
+ }
+ if ((map->orig_to_pseudo = calloc(max_val, sizeof(*(map->orig_to_pseudo)))) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ map->num_orig_types = max_val;
+ max_val = 0;
+ for (i = 0; i < apol_vector_get_size(mv); i++) {
+ t = (qpol_type_t *) apol_vector_get_element(mv, i);
+ if (qpol_type_get_value(diff->mod_qpol, t, &val) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (val > max_val) {
+ max_val = val;
+ }
+ }
+ if ((map->mod_to_pseudo = calloc(max_val, sizeof(*(map->mod_to_pseudo)))) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ map->num_mod_types = max_val;
+
+ if ((map->pseudo_to_orig = apol_vector_create(type_map_vector_free)) == NULL
+ || (map->pseudo_to_mod = apol_vector_create(type_map_vector_free)) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+
+ next_val = 1;
+ for (i = 0; i < apol_vector_get_size(map->remap); i++) {
+ poldiff_type_remap_entry_t *e;
+ const char *name;
+ e = (poldiff_type_remap_entry_t *) apol_vector_get_element(map->remap, i);
+ if (!e->enabled) {
+ continue;
+ }
+
+ if ((reverse_v = apol_vector_create_with_capacity(1, NULL)) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ for (j = 0; j < apol_vector_get_size(e->orig_types); j++) {
+ name = (const char *)apol_vector_get_element(e->orig_types, j);
+ if (qpol_policy_get_type_by_name(diff->orig_qpol, name, &t) < 0 ||
+ qpol_type_get_value(diff->orig_qpol, t, &val) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (map->orig_to_pseudo[val - 1] != 0) {
+ error = EINVAL;
+ ERR(diff, "Type %s is already remapped.", name);
+ goto cleanup;
+ }
+ map->orig_to_pseudo[val - 1] = next_val;
+ if (apol_vector_append(reverse_v, (void *)t) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ }
+ if (apol_vector_append(map->pseudo_to_orig, reverse_v) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ reverse_v = NULL;
+
+ if ((reverse_v = apol_vector_create_with_capacity(1, NULL)) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ for (j = 0; j < apol_vector_get_size(e->mod_types); j++) {
+ name = (const char *)apol_vector_get_element(e->mod_types, j);
+ if (qpol_policy_get_type_by_name(diff->mod_qpol, name, &t) < 0 ||
+ qpol_type_get_value(diff->mod_qpol, t, &val) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (map->mod_to_pseudo[val - 1] != 0) {
+ error = EINVAL;
+ ERR(diff, "Type %s is already remapped.", name);
+ goto cleanup;
+ }
+ map->mod_to_pseudo[val - 1] = next_val;
+ if (apol_vector_append(reverse_v, (void *)t) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ }
+ if (apol_vector_append(map->pseudo_to_mod, reverse_v) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ reverse_v = NULL;
+
+ next_val++;
+ }
+
+ /* all remaining types (both from orig and mod) get their own
+ * values */
+ for (i = 0; i < apol_vector_get_size(ov); i++) {
+ t = apol_vector_get_element(ov, i);
+ if (qpol_type_get_value(diff->orig_qpol, t, &val) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (map->orig_to_pseudo[val - 1] == 0) {
+ map->orig_to_pseudo[val - 1] = next_val;
+ if ((reverse_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
+ apol_vector_append(reverse_v, (void *)t) < 0 ||
+ apol_vector_append(map->pseudo_to_orig, reverse_v) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ reverse_v = NULL;
+ if ((reverse_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
+ apol_vector_append(map->pseudo_to_mod, reverse_v) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ reverse_v = NULL;
+ next_val++;
+ }
+ }
+ for (i = 0; i < apol_vector_get_size(mv); i++) {
+ t = apol_vector_get_element(mv, i);
+ if (qpol_type_get_value(diff->mod_qpol, t, &val) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if (map->mod_to_pseudo[val - 1] == 0) {
+ map->mod_to_pseudo[val - 1] = next_val;
+ if ((reverse_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
+ apol_vector_append(reverse_v, (void *)t) < 0 || apol_vector_append(map->pseudo_to_mod, reverse_v) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ reverse_v = NULL;
+ if ((reverse_v = apol_vector_create_with_capacity(1, NULL)) == NULL ||
+ apol_vector_append(map->pseudo_to_orig, reverse_v) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ reverse_v = NULL;
+ next_val++;
+ }
+ }
+
+ type_map_dump(diff);
+
+ retval = 0;
+ cleanup:
+ apol_vector_destroy(&ov);
+ apol_vector_destroy(&mv);
+ apol_vector_destroy(&reverse_v);
+ error = errno;
+ return retval;
+}
+
+void poldiff_type_remap_flush(poldiff_t * diff)
+{
+ if (diff == NULL || diff->type_map == NULL) {
+ ERR(diff, "%s", strerror(EINVAL));
+ errno = EINVAL;
+ return;
+ }
+ apol_vector_destroy(&(diff->type_map->remap));
+ /* no error checking below */
+ diff->type_map->remap = apol_vector_create(type_remap_entry_free);
+ diff->remapped = 1;
+}
+
+/**
+ * Convenience struct for comparing elements within arrays of primary types.
+ */
+struct type_map_comp
+{
+ poldiff_t *diff;
+ /** from which policy the first element came, either
+ * POLDIFF_POLICY_ORIG or POLDIFF_POLICY_MOD */
+ int dir;
+};
+
+/**
+ * Given two qpol_type_t pointers, both of which are primary types,
+ * compare their names for equivalence.
+ *
+ * @param a Pointer to a qpol_type_t from a policy.
+ * @param b Pointer to a qpol_type_t from a policy.
+ * @param data Pointer to a type_map_comp struct.
+ *
+ * @return 0 if the names match, non-zero if not.
+ */
+static int type_map_primary_comp(const void *a, const void *b, void *data)
+{
+ const qpol_type_t *ta = a;
+ const qpol_type_t *tb = b;
+ struct type_map_comp *c = (struct type_map_comp *)data;
+ poldiff_t *diff = c->diff;
+ int dir = c->dir;
+ const char *na, *nb;
+ if (dir == POLDIFF_POLICY_ORIG) {
+ if (qpol_type_get_name(diff->orig_qpol, ta, &na) < 0 || qpol_type_get_name(diff->mod_qpol, tb, &nb) < 0) {
+ return -1;
+ }
+ } else {
+ if (qpol_type_get_name(diff->mod_qpol, ta, &na) < 0 || qpol_type_get_name(diff->orig_qpol, tb, &nb) < 0) {
+ return -1;
+ }
+ }
+ return strcmp(na, nb);
+}
+
+/**
+ * Given two qpol_type_t pointers, both of which are primary types,
+ * see if the first type matches any of the other type's aliases.
+ *
+ * @param a Pointer to a qpol_type_t from a policy.
+ * @param b Pointer to a qpol_type_t from a policy.
+ * @param data Pointer to a type_map_comp struct.
+ *
+ * @return 0 if b is a member of a's aliases, non-zero if not.
+ */
+static int type_map_prim_alias_comp(const void *a, const void *b, void *data)
+{
+ const qpol_type_t *ta = a;
+ const qpol_type_t *tb = b;
+ struct type_map_comp *c = (struct type_map_comp *)data;
+ poldiff_t *diff = c->diff;
+ int dir = c->dir;
+ const char *prim, *alias;
+ qpol_iterator_t *iter = NULL;
+ if (dir == POLDIFF_POLICY_ORIG) {
+ if (qpol_type_get_alias_iter(diff->orig_qpol, ta, &iter) < 0 || qpol_type_get_name(diff->mod_qpol, tb, &prim) < 0) {
+ qpol_iterator_destroy(&iter);
+ return -1;
+ }
+ } else {
+ if (qpol_type_get_alias_iter(diff->mod_qpol, ta, &iter) < 0 || qpol_type_get_name(diff->orig_qpol, tb, &prim) < 0) {
+ qpol_iterator_destroy(&iter);
+ return -1;
+ }
+ }
+ for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
+ if (qpol_iterator_get_item(iter, (void **)&alias) < 0) {
+ qpol_iterator_destroy(&iter);
+ return -1;
+ }
+ if (strcmp(prim, alias) == 0) {
+ qpol_iterator_destroy(&iter);
+ return 0;
+ }
+ }
+ qpol_iterator_destroy(&iter);
+ return -1;
+}
+
+/**
+ * Given two qpol_type_t pointers, both of which are primary types,
+ * see if the first type's aliases matches the second type's aliases.
+ *
+ * @param a Pointer to a qpol_type_t from a policy.
+ * @param b Pointer to a qpol_type_t from a policy.
+ * @param data Pointer to a type_map_comp struct.
+ *
+ * @return 0 if b is a member of a's aliases, non-zero if not.
+ */
+static int type_map_prim_aliases_comp(const void *a, const void *b, void *data)
+{
+ qpol_type_t *ta = (qpol_type_t *) a;
+ qpol_type_t *tb = (qpol_type_t *) b;
+ struct type_map_comp *c = (struct type_map_comp *)data;
+ poldiff_t *diff = c->diff;
+ int dir = c->dir;
+ qpol_policy_t *p1, *p2;
+ qpol_iterator_t *iter1 = NULL, *iter2 = NULL;
+ apol_vector_t *v1 = NULL, *v2 = NULL;
+ size_t i;
+ int retval = -1, error = 0;
+ if (dir == POLDIFF_POLICY_ORIG) {
+ p1 = diff->orig_qpol;
+ p2 = diff->mod_qpol;
+ } else {
+ p1 = diff->mod_qpol;
+ p2 = diff->orig_qpol;
+ }
+ if (qpol_type_get_alias_iter(p1, ta, &iter1) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((v1 = apol_vector_create_from_iter(iter1, NULL)) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ if (qpol_type_get_alias_iter(p2, tb, &iter2) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ if ((v2 = apol_vector_create_from_iter(iter2, NULL)) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ if (apol_vector_get_size(v1) == 0 || apol_vector_get_size(v2) == 0) {
+ retval = 1;
+ goto cleanup;
+ } else {
+ apol_vector_sort_uniquify(v1, apol_str_strcmp, NULL);
+ apol_vector_sort_uniquify(v2, apol_str_strcmp, NULL);
+ retval = apol_vector_compare(v1, v2, apol_str_strcmp, NULL, &i);
+ }
+ cleanup:
+ qpol_iterator_destroy(&iter1);
+ qpol_iterator_destroy(&iter2);
+ apol_vector_destroy(&v1);
+ apol_vector_destroy(&v2);
+ errno = error;
+ return retval;
+}
+
+/**
+ * If --enable-debug is given, then dump to stdout the type-map from
+ * pseudo-types to the policy's type(s).
+ */
+static void type_remap_vector_dump(poldiff_t * diff)
+{
+#ifdef SETOOLS_DEBUG
+ apol_vector_t *v, *w;
+ size_t i, j;
+ poldiff_type_remap_entry_t *e;
+ char *name;
+ printf("# type remap vector debug dump (pseudo-type -> qpol_type_t(s):\n");
+ v = poldiff_type_remap_get_entries(diff);
+ for (i = 0; i < apol_vector_get_size(v); i++) {
+ e = apol_vector_get_element(v, i);
+ printf("%zd\t%s\t", i, poldiff_type_remap_entry_get_is_enabled(e) ? "en" : "dis");
+ w = poldiff_type_remap_entry_get_original_types(diff, e);
+ for (j = 0; j < apol_vector_get_size(w); j++) {
+ name = apol_vector_get_element(w, j);
+ printf("%s ", name);
+ }
+ apol_vector_destroy(&w);
+ printf("-> ");
+ w = poldiff_type_remap_entry_get_modified_types(diff, e);
+ for (j = 0; j < apol_vector_get_size(w); j++) {
+ name = apol_vector_get_element(w, j);
+ printf("%s ", name);
+ }
+ apol_vector_destroy(&w);
+ printf("\n");
+ }
+#endif
+}
+
+static int type_map_entry_append_qtypes(poldiff_t * diff, poldiff_type_remap_entry_t * entry, const qpol_type_t * t,
+ const qpol_type_t * u)
+{
+ const char *name;
+ char *dup_name;
+ if (qpol_type_get_name(diff->orig_qpol, t, &name) < 0) {
+ return -1;
+ }
+ if ((dup_name = strdup(name)) == NULL || apol_vector_append(entry->orig_types, (void *)dup_name) < 0) {
+ free(dup_name);
+ return -1;
+ }
+
+ if (qpol_type_get_name(diff->mod_qpol, u, &name) < 0) {
+ return -1;
+ }
+ if ((dup_name = strdup(name)) == NULL || apol_vector_append(entry->mod_types, (void *)dup_name) < 0) {
+ free(dup_name);
+ return -1;
+ }
+ return 0;
+}
+
+int type_map_infer(poldiff_t * diff)
+{
+ apol_vector_t *ov = NULL, *mv = NULL;
+ char *orig_done = NULL, *mod_done = NULL;
+ size_t num_orig, num_mod, i, j;
+ qpol_type_t *t, *u;
+ struct type_map_comp c = { diff, 0 };
+ poldiff_type_remap_entry_t *entry = NULL;
+ int retval = -1, error = 0;
+
+ INFO(diff, "%s", "Inferring type remap.");
+ if (apol_type_get_by_query(diff->orig_pol, NULL, &ov) < 0 || apol_type_get_by_query(diff->mod_pol, NULL, &mv) < 0) {
+ error = errno;
+ goto cleanup;
+ }
+ num_orig = apol_vector_get_size(ov);
+ num_mod = apol_vector_get_size(mv);
+ if ((orig_done = calloc(1, num_orig)) == NULL || (mod_done = calloc(1, num_mod)) == NULL) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+
+ /* first map primary <--> primary */
+ c.dir = POLDIFF_POLICY_MOD;
+ for (i = 0; i < num_orig; i++) {
+ t = (qpol_type_t *) apol_vector_get_element(ov, i);
+ if (apol_vector_get_index(mv, t, type_map_primary_comp, &c, &j) < 0) {
+ continue;
+ }
+ assert(!mod_done[j]);
+ u = (qpol_type_t *) apol_vector_get_element(mv, j);
+ if ((entry = poldiff_type_remap_entry_create(diff)) == NULL || type_map_entry_append_qtypes(diff, entry, t, u) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ entry->inferred = 1;
+ orig_done[i] = 1;
+ mod_done[j] = 1;
+ }
+
+ /* now map primary -> primary's alias */
+ c.dir = POLDIFF_POLICY_MOD;
+ for (i = 0; i < num_orig; i++) {
+ if (orig_done[i]) {
+ continue;
+ }
+ t = (qpol_type_t *) apol_vector_get_element(ov, i);
+ u = NULL;
+ for (j = 0; j < num_mod; j++) {
+ if (mod_done[j]) {
+ continue;
+ }
+ u = (qpol_type_t *) apol_vector_get_element(mv, j);
+ if (type_map_prim_alias_comp(u, t, &c) == 0) {
+ break;
+ }
+ }
+ if (j >= num_mod) {
+ continue;
+ }
+ if ((entry = poldiff_type_remap_entry_create(diff)) == NULL || type_map_entry_append_qtypes(diff, entry, t, u) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ entry->inferred = 1;
+ orig_done[i] = 1;
+ mod_done[j] = 1;
+ }
+
+ /* then map primary's alias <- primary */
+ c.dir = POLDIFF_POLICY_ORIG;
+ for (j = 0; j < num_mod; j++) {
+ if (mod_done[j]) {
+ continue;
+ }
+ u = (qpol_type_t *) apol_vector_get_element(mv, j);
+ t = NULL;
+ for (i = 0; i < num_orig; i++) {
+ if (orig_done[i]) {
+ continue;
+ }
+ t = (qpol_type_t *) apol_vector_get_element(ov, i);
+ if (type_map_prim_alias_comp(t, u, &c) == 0) {
+ break;
+ }
+ }
+ if (i >= num_orig) {
+ continue;
+ }
+ if ((entry = poldiff_type_remap_entry_create(diff)) == NULL || type_map_entry_append_qtypes(diff, entry, t, u) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ entry->inferred = 1;
+ orig_done[i] = 1;
+ mod_done[j] = 1;
+ }
+
+ /* map alias <-> alias */
+ c.dir = POLDIFF_POLICY_MOD;
+ for (i = 0; i < num_orig; i++) {
+ if (orig_done[i]) {
+ continue;
+ }
+ t = (qpol_type_t *) apol_vector_get_element(ov, i);
+ u = NULL;
+ for (j = 0; j < num_mod; j++) {
+ if (mod_done[j]) {
+ continue;
+ }
+ u = (qpol_type_t *) apol_vector_get_element(mv, j);
+ if (type_map_prim_aliases_comp(u, t, &c) == 0) {
+ break;
+ }
+ }
+ if (j >= num_mod) {
+ continue;
+ }
+ if ((entry = poldiff_type_remap_entry_create(diff)) == NULL || type_map_entry_append_qtypes(diff, entry, t, u) < 0) {
+ error = errno;
+ ERR(diff, "%s", strerror(error));
+ goto cleanup;
+ }
+ entry->inferred = 1;
+ orig_done[i] = 1;
+ mod_done[j] = 1;
+ }
+
+ type_remap_vector_dump(diff);
+
+ retval = 0;
+ diff->remapped = 1;
+ cleanup:
+ apol_vector_destroy(&ov);
+ apol_vector_destroy(&mv);
+ free(orig_done);
+ free(mod_done);
+ errno = error;
+ return retval;
+}
+
+uint32_t type_map_lookup(const poldiff_t * diff, const qpol_type_t * type, int which_pol)
+{
+ uint32_t val;
+ if (which_pol == POLDIFF_POLICY_ORIG) {
+ if (qpol_type_get_value(diff->orig_qpol, type, &val) < 0) {
+ return 0;
+ }
+ assert(val <= diff->type_map->num_orig_types);
+ assert(diff->type_map->orig_to_pseudo[val - 1] != 0);
+ return diff->type_map->orig_to_pseudo[val - 1];
+ } else {
+ if (qpol_type_get_value(diff->mod_qpol, type, &val) < 0) {
+ return 0;
+ }
+ assert(val <= diff->type_map->num_mod_types);
+ assert(diff->type_map->mod_to_pseudo[val - 1] != 0);
+ return diff->type_map->mod_to_pseudo[val - 1];
+ }
+}
+
+const apol_vector_t *type_map_lookup_reverse(const poldiff_t * diff, uint32_t val, int which_pol)
+{
+ if (which_pol == POLDIFF_POLICY_ORIG) {
+ return apol_vector_get_element(diff->type_map->pseudo_to_orig, val - 1);
+ } else {
+ return apol_vector_get_element(diff->type_map->pseudo_to_mod, val - 1);
+ }
+}
+
+const char *type_map_get_name(const poldiff_t * diff, const uint32_t pseudo_val, int pol)
+{
+ const apol_vector_t *v = NULL;
+ const char *name = NULL;
+ const qpol_type_t *t;
+
+ v = type_map_lookup_reverse(diff, pseudo_val, pol);
+ if (apol_vector_get_size(v) == 0) {
+ return NULL;
+ }
+ t = apol_vector_get_element(v, 0);
+ if (pol == POLDIFF_POLICY_ORIG)
+ qpol_type_get_name(diff->orig_qpol, t, &name);
+ else
+ qpol_type_get_name(diff->mod_qpol, t, &name);
+ return name;
+}