C++程序  |  1719行  |  41.36 KB

/*
 * Copyright 2011 Tresys Technology, LLC. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 * 
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are those
 * of the authors and should not be interpreted as representing official policies,
 * either expressed or implied, of Tresys Technology, LLC.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>

#include <sepol/policydb/conditional.h>
#include <sepol/errcodes.h>

#include "cil_internal.h"
#include "cil_flavor.h"
#include "cil_log.h"
#include "cil_mem.h"
#include "cil_tree.h"
#include "cil_list.h"
#include "cil_post.h"
#include "cil_policy.h"
#include "cil_verify.h"
#include "cil_symtab.h"

static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db);
static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db);

static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor)
{
	struct cil_list_item *curr;

	cil_list_for_each(curr, list) {
		switch (curr->flavor) {
		case CIL_LIST:
			return CIL_FALSE;
			break;
		case CIL_OP:
			return CIL_FALSE;
			break;
		default:
			if (flavor == CIL_CAT) {
				struct cil_symtab_datum *d = curr->data;
				struct cil_tree_node *n = d->nodes->head->data;
				if (n->flavor == CIL_CATSET) {
					return CIL_FALSE;
				}
			}
			break;
		}	
	}
	return CIL_TRUE;
}

void cil_post_fc_fill_data(struct fc_data *fc, char *path)
{
	int c = 0;
	fc->meta = 0;
	fc->stem_len = 0;
	fc->str_len = 0;
	
	while (path[c] != '\0') {
		switch (path[c]) {
		case '.':
		case '^':
		case '$':
		case '?':
		case '*':
		case '+':
		case '|':
		case '[':
		case '(':
		case '{':
			fc->meta = 1;
			break;
		case '\\':
			c++;
		default:
			if (!fc->meta) {
				fc->stem_len++;
			}
			break;
		}
		fc->str_len++;
		c++;
	}
}

int cil_post_filecon_compare(const void *a, const void *b)
{
	int rc = 0;
	struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
	struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
	struct fc_data *a_data = cil_malloc(sizeof(*a_data));
	struct fc_data *b_data = cil_malloc(sizeof(*b_data));
	char *a_path = cil_malloc(strlen(a_filecon->path_str) + 1);
	a_path[0] = '\0';
	char *b_path = cil_malloc(strlen(b_filecon->path_str) + 1);
	b_path[0] = '\0';
	strcat(a_path, a_filecon->path_str);
	strcat(b_path, b_filecon->path_str);
	cil_post_fc_fill_data(a_data, a_path);
	cil_post_fc_fill_data(b_data, b_path);
	if (a_data->meta && !b_data->meta) {
		rc = -1;
	} else if (b_data->meta && !a_data->meta) {
		rc = 1;
	} else if (a_data->stem_len < b_data->stem_len) {
		rc = -1;
	} else if (b_data->stem_len < a_data->stem_len) {
		rc = 1;
	} else if (a_data->str_len < b_data->str_len) {
		rc = -1;
	} else if (b_data->str_len < a_data->str_len) {
		rc = 1;
	} else if (a_filecon->type < b_filecon->type) {
		rc = -1;
	} else if (b_filecon->type < a_filecon->type) {
		rc = 1;
	}

	free(a_path);
	free(b_path);
	free(a_data);
	free(b_data);

	return rc;
}

int cil_post_portcon_compare(const void *a, const void *b)
{
	int rc = SEPOL_ERR;
	struct cil_portcon *aportcon = *(struct cil_portcon**)a;
	struct cil_portcon *bportcon = *(struct cil_portcon**)b;

	rc = (aportcon->port_high - aportcon->port_low) 
		- (bportcon->port_high - bportcon->port_low);
	if (rc == 0) {
		if (aportcon->port_low < bportcon->port_low) {
			rc = -1;
		} else if (bportcon->port_low < aportcon->port_low) {
			rc = 1;
		}
	}

	return rc;
}

int cil_post_genfscon_compare(const void *a, const void *b)
{
	int rc = SEPOL_ERR;
	struct cil_genfscon *agenfscon = *(struct cil_genfscon**)a;
	struct cil_genfscon *bgenfscon = *(struct cil_genfscon**)b;

	rc = strcmp(agenfscon->fs_str, bgenfscon->fs_str);
	if (rc == 0) {
		rc = strcmp(agenfscon->path_str, bgenfscon->path_str);
	}

	return rc;
}

int cil_post_netifcon_compare(const void *a, const void *b)
{
	struct cil_netifcon *anetifcon = *(struct cil_netifcon**)a;
	struct cil_netifcon *bnetifcon = *(struct cil_netifcon**)b;

	return  strcmp(anetifcon->interface_str, bnetifcon->interface_str);
}

int cil_post_nodecon_compare(const void *a, const void *b)
{
	struct cil_nodecon *anodecon;
	struct cil_nodecon *bnodecon;
	anodecon = *(struct cil_nodecon**)a;
	bnodecon = *(struct cil_nodecon**)b;

	/* sort ipv4 before ipv6 */
	if (anodecon->addr->family != bnodecon->addr->family) {
		if (anodecon->addr->family == AF_INET) {
			return -1;
		} else {
			return 1;
		}
	}

	/* most specific netmask goes first, then order by ip addr */
	if (anodecon->addr->family == AF_INET) {
		int rc = memcmp(&anodecon->mask->ip.v4, &bnodecon->mask->ip.v4, sizeof(anodecon->mask->ip.v4));
		if (rc != 0) {
			return -1 * rc;
		}
		return memcmp(&anodecon->addr->ip.v4, &bnodecon->addr->ip.v4, sizeof(anodecon->addr->ip.v4));
	} else {
		int rc = memcmp(&anodecon->mask->ip.v6, &bnodecon->mask->ip.v6, sizeof(anodecon->mask->ip.v6));
		if (rc != 0) {
			return -1 * rc;
		}
		return memcmp(&anodecon->addr->ip.v6, &bnodecon->addr->ip.v6, sizeof(anodecon->addr->ip.v6));
	}
}

int cil_post_pirqcon_compare(const void *a, const void *b)
{
	int rc = SEPOL_ERR;
	struct cil_pirqcon *apirqcon = *(struct cil_pirqcon**)a;
	struct cil_pirqcon *bpirqcon = *(struct cil_pirqcon**)b;

	if (apirqcon->pirq < bpirqcon->pirq) {
		rc = -1;
	} else if (bpirqcon->pirq < apirqcon->pirq) {
		rc = 1;
	} else {
		rc = 0;
	}

	return rc;
}

int cil_post_iomemcon_compare(const void *a, const void *b)
{
	int rc = SEPOL_ERR;
	struct cil_iomemcon *aiomemcon = *(struct cil_iomemcon**)a;
	struct cil_iomemcon *biomemcon = *(struct cil_iomemcon**)b;

	rc = (aiomemcon->iomem_high - aiomemcon->iomem_low) 
		- (biomemcon->iomem_high - biomemcon->iomem_low);
	if (rc == 0) {
		if (aiomemcon->iomem_low < biomemcon->iomem_low) {
			rc = -1;
		} else if (biomemcon->iomem_low < aiomemcon->iomem_low) {
			rc = 1;
		}
	}

	return rc;
}

int cil_post_ioportcon_compare(const void *a, const void *b)
{
	int rc = SEPOL_ERR;
	struct cil_ioportcon *aioportcon = *(struct cil_ioportcon**)a;
	struct cil_ioportcon *bioportcon = *(struct cil_ioportcon**)b;

	rc = (aioportcon->ioport_high - aioportcon->ioport_low) 
		- (bioportcon->ioport_high - bioportcon->ioport_low);
	if (rc == 0) {
		if (aioportcon->ioport_low < bioportcon->ioport_low) {
			rc = -1;
		} else if (bioportcon->ioport_low < aioportcon->ioport_low) {
			rc = 1;
		}
	}

	return rc;
}

int cil_post_pcidevicecon_compare(const void *a, const void *b)
{
	int rc = SEPOL_ERR;
	struct cil_pcidevicecon *apcidevicecon = *(struct cil_pcidevicecon**)a;
	struct cil_pcidevicecon *bpcidevicecon = *(struct cil_pcidevicecon**)b;

	if (apcidevicecon->dev < bpcidevicecon->dev) {
		rc = -1;
	} else if (bpcidevicecon->dev < apcidevicecon->dev) {
		rc = 1;
	} else {
		rc = 0;
	}

	return rc;
}

int cil_post_devicetreecon_compare(const void *a, const void *b)
{
	int rc = SEPOL_ERR;
	struct cil_devicetreecon *adevicetreecon = *(struct cil_devicetreecon**)a;
	struct cil_devicetreecon *bdevicetreecon = *(struct cil_devicetreecon**)b;

	rc = strcmp(adevicetreecon->path, bdevicetreecon->path);

	return rc;
}

int cil_post_fsuse_compare(const void *a, const void *b)
{
	int rc;
	struct cil_fsuse *afsuse;
	struct cil_fsuse *bfsuse;
	afsuse = *(struct cil_fsuse**)a;
	bfsuse = *(struct cil_fsuse**)b;
	if (afsuse->type < bfsuse->type) {
		rc = -1;
	} else if (bfsuse->type < afsuse->type) {
		rc = 1;
	} else {
		rc = strcmp(afsuse->fs_str, bfsuse->fs_str);
	}
	return rc;
}

static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
{
	struct cil_db *db = extra_args;

	switch(node->flavor) {
	case CIL_BLOCK: {
		struct cil_block *blk = node->data;
		if (blk->is_abstract == CIL_TRUE) {
			*finished = CIL_TREE_SKIP_HEAD;
		}
		break;
	}
	case CIL_MACRO:
		*finished = CIL_TREE_SKIP_HEAD;
		break;
	case CIL_TYPE: {
		struct cil_type *type = node->data;
		if (type->datum.nodes->head->data == node) {
			// multiple AST nodes can point to the same cil_type data (like if
			// copied from a macro). This check ensures we only count the
			// duplicates once
			type->value = db->num_types;
			db->num_types++;
		}
		break;
	}
	case CIL_ROLE: {
		struct cil_role *role = node->data;
		if (role->datum.nodes->head->data == node) {
			// multiple AST nodes can point to the same cil_role data (like if
			// copied from a macro). This check ensures we only count the
			// duplicates once
			role->value = db->num_roles;
			db->num_roles++;
		}
		break;
	}
	case CIL_NETIFCON:
		db->netifcon->count++;
		break;
	case CIL_GENFSCON:
		db->genfscon->count++;
		break;
	case CIL_FILECON:
		db->filecon->count++;
		break;
	case CIL_NODECON:
		db->nodecon->count++;
		break;
	case CIL_PORTCON:
		db->portcon->count++;
		break;
	case CIL_PIRQCON:
		db->pirqcon->count++;
		break;
	case CIL_IOMEMCON:
		db->iomemcon->count++;
		break;
	case CIL_IOPORTCON:
		db->ioportcon->count++;
		break;
	case CIL_PCIDEVICECON:
		db->pcidevicecon->count++;
		break;	
	case CIL_DEVICETREECON:
		db->devicetreecon->count++;
		break;
	case CIL_FSUSE:
		db->fsuse->count++;
		break;
	default:
		break;
	}

	return SEPOL_OK;
}

static int __cil_post_db_array_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
{
	struct cil_db *db = extra_args;

	switch(node->flavor) {
	case CIL_BLOCK: {
		struct cil_block *blk = node->data;
		if (blk->is_abstract == CIL_TRUE) {
			*finished = CIL_TREE_SKIP_HEAD;
		}
		break;
	}
	case CIL_MACRO:
		*finished = CIL_TREE_SKIP_HEAD;
		break;
	case CIL_TYPE: {
		struct cil_type *type = node->data;
		if (db->val_to_type == NULL) {
			db->val_to_type = cil_malloc(sizeof(*db->val_to_type) * db->num_types);
		}
		db->val_to_type[type->value] = type;
		break;
	}
	case CIL_ROLE: {
		struct cil_role *role = node->data;
		if (db->val_to_role == NULL) {
			db->val_to_role = cil_malloc(sizeof(*db->val_to_role) * db->num_roles);
		}
		db->val_to_role[role->value] = role;
		break;
	}
	case CIL_USERPREFIX: {
		cil_list_append(db->userprefixes, CIL_USERPREFIX, node->data);
		break;
	}
	case CIL_SELINUXUSER: {
		cil_list_prepend(db->selinuxusers, CIL_SELINUXUSER, node->data);
		break;
	}
	case CIL_SELINUXUSERDEFAULT: {
		cil_list_append(db->selinuxusers, CIL_SELINUXUSERDEFAULT, node->data);
		break;
	}
	case CIL_NETIFCON: {
		struct cil_sort *sort = db->netifcon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_FSUSE: {
		struct cil_sort *sort = db->fsuse;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_GENFSCON: {
		struct cil_sort *sort = db->genfscon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_FILECON: {
		struct cil_sort *sort = db->filecon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
		sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_NODECON: {
		struct cil_sort *sort = db->nodecon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_PORTCON: {
		struct cil_sort *sort = db->portcon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_PIRQCON: {
		struct cil_sort *sort = db->pirqcon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_IOMEMCON: {
		struct cil_sort *sort = db->iomemcon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_IOPORTCON: {
		struct cil_sort *sort = db->ioportcon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_PCIDEVICECON: {
		struct cil_sort *sort = db->pcidevicecon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	case CIL_DEVICETREECON: {
		struct cil_sort *sort = db->devicetreecon;
		uint32_t count = sort->count;
		uint32_t i = sort->index;
		if (sort->array == NULL) {
			sort->array = cil_malloc(sizeof(*sort->array)*count);
		}
		sort->array[i] = node->data;
		sort->index++;
		break;
	}
	default:
		break;
	}

	return SEPOL_OK;
}

static int __evaluate_type_expression(struct cil_typeattribute *attr, struct cil_db *db)
{
	int rc;

	attr->types = cil_malloc(sizeof(*attr->types));
	rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->types, db->num_types, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_ERR, "Failed to expand type attribute to bitmap\n");
		ebitmap_destroy(attr->types);
		free(attr->types);
		attr->types = NULL;
	}
	return rc;
}

static int __cil_type_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct cil_tree_node *node = datum->nodes->head->data;

	ebitmap_init(bitmap);

	if (node->flavor == CIL_TYPEATTRIBUTE) {
		struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
		if (attr->types == NULL) {
			rc = __evaluate_type_expression(attr, db);
			if (rc != SEPOL_OK) goto exit;
		}
		ebitmap_union(bitmap, attr->types);
	} else if (node->flavor == CIL_TYPEALIAS) {
		struct cil_alias *alias = (struct cil_alias *)datum;
		struct cil_type *type = alias->actual;
		if (ebitmap_set_bit(bitmap, type->value, 1)) {
			cil_log(CIL_ERR, "Failed to set type bit\n");
			ebitmap_destroy(bitmap);
			goto exit;
		}
	} else {
		struct cil_type *type = (struct cil_type *)datum;
		if (ebitmap_set_bit(bitmap, type->value, 1)) {
			cil_log(CIL_ERR, "Failed to set type bit\n");
			ebitmap_destroy(bitmap);
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}

static int __evaluate_role_expression(struct cil_roleattribute *attr, struct cil_db *db)
{
	int rc;

	attr->roles = cil_malloc(sizeof(*attr->roles));
	rc = __cil_expr_list_to_bitmap(attr->expr_list, attr->roles, db->num_roles, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_ERR, "Failed to expand role attribute to bitmap\n");
		ebitmap_destroy(attr->roles);
		free(attr->roles);
		attr->roles = NULL;
	}
	return rc;
}

static int __cil_role_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct cil_tree_node *node = datum->nodes->head->data;

	ebitmap_init(bitmap);

	if (node->flavor == CIL_ROLEATTRIBUTE) {
		struct cil_roleattribute *attr = (struct cil_roleattribute *)datum;
		if (attr->roles == NULL) {
			rc = __evaluate_role_expression(attr, db);
			if (rc != SEPOL_OK) goto exit;
		}
		ebitmap_union(bitmap, attr->roles);
	} else {
		struct cil_role *role = (struct cil_role *)datum;
		if (ebitmap_set_bit(bitmap, role->value, 1)) {
			cil_log(CIL_ERR, "Failed to set role bit\n");
			ebitmap_destroy(bitmap);
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}

static int __cil_perm_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, __attribute__((unused)) struct cil_db *db)
{
	struct cil_perm *perm = (struct cil_perm *)datum;
	unsigned int value = perm->value;

	ebitmap_init(bitmap);
	if (ebitmap_set_bit(bitmap, value, 1)) {
		cil_log(CIL_INFO, "Failed to set perm bit\n");
		ebitmap_destroy(bitmap);
		return SEPOL_ERR;
	}

	return SEPOL_OK;
}

static int __evaluate_cat_expression(struct cil_cats *cats, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	ebitmap_t bitmap;
	struct cil_list *new;
	struct cil_list_item *curr;

	if (cats->evaluated == CIL_TRUE) {
		return SEPOL_OK;
	}

	if (cil_verify_is_list(cats->datum_expr, CIL_CAT)) {
		return SEPOL_OK;
	}

	ebitmap_init(&bitmap);
	rc = __cil_expr_to_bitmap(cats->datum_expr, &bitmap, db->num_cats, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_ERR, "Failed to expand category expression to bitmap\n");
		ebitmap_destroy(&bitmap);
		goto exit;
	}

	cil_list_init(&new, CIL_CAT);

	cil_list_for_each(curr, db->catorder) {
		struct cil_cat *cat = curr->data;
		if (ebitmap_get_bit(&bitmap, cat->value)) {
			cil_list_append(new, CIL_DATUM, cat);
		}
	}

	ebitmap_destroy(&bitmap);
	cil_list_destroy(&cats->datum_expr, CIL_FALSE);
	if (new->head != NULL) { 
		cats->datum_expr = new;
	} else {
		/* empty list */
		cil_list_destroy(&new, CIL_FALSE);
		cats->datum_expr = NULL;
	}

	cats->evaluated = CIL_TRUE;

	return SEPOL_OK;

exit:
	return rc;
}

static int __cil_cat_to_bitmap(struct cil_symtab_datum *datum, ebitmap_t *bitmap, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct cil_tree_node *node = datum->nodes->head->data;

	ebitmap_init(bitmap);

	if (node->flavor == CIL_CATSET) {
		struct cil_catset *catset = (struct cil_catset *)datum;
		struct cil_list_item *curr;
		if (catset->cats->evaluated == CIL_FALSE) {
			rc = __evaluate_cat_expression(catset->cats, db);
			if (rc != SEPOL_OK) goto exit;
		}
		for (curr = catset->cats->datum_expr->head; curr; curr = curr->next) {
			struct cil_cat *cat = (struct cil_cat *)curr->data;
			if (ebitmap_set_bit(bitmap, cat->value, 1)) {
				cil_log(CIL_ERR, "Failed to set cat bit\n");
				ebitmap_destroy(bitmap);
				goto exit;
			}
		}
	} else if (node->flavor == CIL_CATALIAS) {
		struct cil_alias *alias = (struct cil_alias *)datum;
		struct cil_cat *cat = alias->actual;
		if (ebitmap_set_bit(bitmap, cat->value, 1)) {
			cil_log(CIL_ERR, "Failed to set cat bit\n");
			ebitmap_destroy(bitmap);
			goto exit;
		}
	} else {
		struct cil_cat *cat = (struct cil_cat *)datum;
		if (ebitmap_set_bit(bitmap, cat->value, 1)) {
			cil_log(CIL_ERR, "Failed to set cat bit\n");
			ebitmap_destroy(bitmap);
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}

static int __cil_expr_range_to_bitmap_helper(struct cil_list_item *i1, struct cil_list_item *i2, ebitmap_t *bitmap)
{
	int rc = SEPOL_ERR;
	struct cil_symtab_datum *d1 = i1->data;
	struct cil_symtab_datum *d2 = i2->data;
	struct cil_tree_node *n1 = d1->nodes->head->data;
	struct cil_tree_node *n2 = d2->nodes->head->data;
	struct cil_cat *c1 = (struct cil_cat *)d1;
	struct cil_cat *c2 = (struct cil_cat *)d2;
	int i;

	if (n1->flavor == CIL_CATSET || n2->flavor == CIL_CATSET) {
		cil_log(CIL_ERR, "Category sets cannont be used in a category range\n");
		goto exit;
	}

	if (n1->flavor == CIL_CATALIAS) {
		struct cil_alias *alias = (struct cil_alias *)d1;
		c1 = alias->actual;
	}

	if (n2->flavor == CIL_CATALIAS) {
		struct cil_alias *alias = (struct cil_alias *)d2;
		c2 = alias->actual;
	}

	for (i = c1->value; i <= c2->value; i++) {
		if (ebitmap_set_bit(bitmap, i, 1)) {
			cil_log(CIL_ERR, "Failed to set cat bit\n");
			ebitmap_destroy(bitmap);
			goto exit;
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}

static int __cil_expr_to_bitmap_helper(struct cil_list_item *curr, enum cil_flavor flavor, ebitmap_t *bitmap, int max, struct cil_db *db)
{
	int rc = SEPOL_ERR;

	if (curr->flavor == CIL_DATUM) {
		switch (flavor) {
		case CIL_TYPE:
			rc = __cil_type_to_bitmap(curr->data, bitmap, db);
			break;
		case CIL_ROLE:
			rc = __cil_role_to_bitmap(curr->data, bitmap, db);
			break;
		case CIL_PERM:
			rc = __cil_perm_to_bitmap(curr->data, bitmap, db);
			break;
		case CIL_CAT:
			rc = __cil_cat_to_bitmap(curr->data, bitmap, db);
			break;
		default:
			rc = SEPOL_ERR;
		}
	} else if (curr->flavor == CIL_LIST) {
		struct cil_list *l = curr->data;
		ebitmap_init(bitmap);
		rc = __cil_expr_to_bitmap(l, bitmap, max, db);
		if (rc != SEPOL_OK) {
			ebitmap_destroy(bitmap);
		}	
	}

	return rc;
}

static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct cil_list_item *curr;
	enum cil_flavor flavor;
	ebitmap_t tmp, b1, b2;

	if (expr == NULL || expr->head == NULL) {
		return SEPOL_OK;
	}

	curr = expr->head;
	flavor = expr->flavor;

	if (curr->flavor == CIL_OP) {
		enum cil_flavor op = (enum cil_flavor)curr->data;

		if (op == CIL_ALL) {
			ebitmap_init(&b1); /* all zeros */
			rc = ebitmap_not(&tmp, &b1, max);
			ebitmap_destroy(&b1);
			if (rc != SEPOL_OK) {
				cil_log(CIL_INFO, "Failed to expand 'all' operator\n");
				ebitmap_destroy(&tmp);
				goto exit;
			}
		} else if (op == CIL_RANGE) {
			if (flavor != CIL_CAT) {
				cil_log(CIL_INFO, "Range operation only supported for categories\n");
				rc = SEPOL_ERR;
				goto exit;
			}
			ebitmap_init(&tmp);
			rc = __cil_expr_range_to_bitmap_helper(curr->next, curr->next->next, &tmp);
			if (rc != SEPOL_OK) {
				cil_log(CIL_INFO, "Failed to expand category range\n");
				ebitmap_destroy(&tmp);
				goto exit;
			}
		} else {
			rc = __cil_expr_to_bitmap_helper(curr->next, flavor, &b1, max, db);
			if (rc != SEPOL_OK) {
				cil_log(CIL_INFO, "Failed to get first operand bitmap\n");
				goto exit;
			}

			if (op == CIL_NOT) {
				rc = ebitmap_not(&tmp, &b1, max);
				ebitmap_destroy(&b1);
				if (rc != SEPOL_OK) {
					cil_log(CIL_INFO, "Failed to NOT bitmap\n");
					ebitmap_destroy(&tmp);
					goto exit;
				}
			} else {
				rc = __cil_expr_to_bitmap_helper(curr->next->next, flavor, &b2, max, db);
				if (rc != SEPOL_OK) {
					cil_log(CIL_INFO, "Failed to get second operand bitmap\n");
					goto exit;
				}

				if (op == CIL_OR) {
					rc = ebitmap_or(&tmp, &b1, &b2);
				} else if (op == CIL_AND) {
					rc = ebitmap_and(&tmp, &b1, &b2);
				} else if (op == CIL_XOR) {
					rc = ebitmap_xor(&tmp, &b1, &b2);
				} else {
					rc = SEPOL_ERR;
				}
				ebitmap_destroy(&b1);
				ebitmap_destroy(&b2);
				if (rc != SEPOL_OK) {
					cil_log(CIL_INFO, "Failed to apply operator to bitmaps\n");
					ebitmap_destroy(&tmp);
					goto exit;
				}
			}
		}
	} else {
		ebitmap_init(&tmp);
		for (;curr; curr = curr->next) {
			rc = __cil_expr_to_bitmap_helper(curr, flavor, &b2, max, db);
			if (rc != SEPOL_OK) {
				cil_log(CIL_INFO, "Failed to get operand in list\n");
				ebitmap_destroy(&tmp);
				goto exit;
			}
			b1 = tmp;
			rc = ebitmap_or(&tmp, &b1, &b2);
			ebitmap_destroy(&b1);
			ebitmap_destroy(&b2);
			if (rc != SEPOL_OK) {
				cil_log(CIL_INFO, "Failed to OR operands in list\n");
				ebitmap_destroy(&tmp);
				goto exit;
			}

		}
	}

	ebitmap_union(out, &tmp);
	ebitmap_destroy(&tmp);

	return SEPOL_OK;

exit:
	return rc;
}

static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct cil_list_item *expr;

	ebitmap_init(out);

	if (expr_list == NULL) {
		return SEPOL_OK;
	}

	cil_list_for_each(expr, expr_list) {
		ebitmap_t bitmap;
		struct cil_list *l = (struct cil_list *)expr->data;
		ebitmap_init(&bitmap);
		rc = __cil_expr_to_bitmap(l, &bitmap, max, db);
		if (rc != SEPOL_OK) {
			cil_log(CIL_INFO, "Failed to expand expression list to bitmap\n");
			ebitmap_destroy(&bitmap);
			goto exit;
		}
		ebitmap_union(out, &bitmap);
		ebitmap_destroy(&bitmap);
	}

	return SEPOL_OK;

exit:
	return SEPOL_ERR;
}

static int __cil_post_db_attr_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
{
	int rc = SEPOL_ERR;
	struct cil_db *db = extra_args;

	switch (node->flavor) {
	case CIL_BLOCK: {
		struct cil_block *blk = node->data;
		if (blk->is_abstract == CIL_TRUE) {
			*finished = CIL_TREE_SKIP_HEAD;
		}
		break;
	}
	case CIL_MACRO: {
		*finished = CIL_TREE_SKIP_HEAD;
		break;
	}
	case CIL_TYPEATTRIBUTE: {
		struct cil_typeattribute *attr = node->data;
		if (attr->types == NULL) {
			rc = __evaluate_type_expression(attr, db);
			if (rc != SEPOL_OK) goto exit;
		}
		break;
	}
	case CIL_ROLEATTRIBUTE: {
		struct cil_roleattribute *attr = node->data;
		if (attr->roles == NULL) {
			rc = __evaluate_role_expression(attr, db);
			if (rc != SEPOL_OK) goto exit;
		}
		break;
	}
	default:
		break;
	}

	return SEPOL_OK;

exit:
	return rc;
}

static int __cil_role_assign_types(struct cil_role *role, struct cil_symtab_datum *datum)
{
	struct cil_tree_node *node = datum->nodes->head->data;

	if (role->types == NULL) {
		role->types = cil_malloc(sizeof(*role->types));
		ebitmap_init(role->types);
	}

	if (node->flavor == CIL_TYPE) {
		struct cil_type *type = (struct cil_type *)datum;
		if (ebitmap_set_bit(role->types, type->value, 1)) {
			cil_log(CIL_INFO, "Failed to set bit in role types bitmap\n");
			goto exit;
		}
	} else if (node->flavor == CIL_TYPEALIAS) {
		struct cil_alias *alias = (struct cil_alias *)datum;
		struct cil_type *type = alias->actual;
		if (ebitmap_set_bit(role->types, type->value, 1)) {
			cil_log(CIL_INFO, "Failed to set bit in role types bitmap\n");
			goto exit;
		}
	} else if (node->flavor == CIL_TYPEATTRIBUTE) {
		struct cil_typeattribute *attr = (struct cil_typeattribute *)datum;
		ebitmap_union(role->types, attr->types);
	}

	return SEPOL_OK;

exit:
	return SEPOL_ERR;
}

static int __cil_post_db_roletype_helper(struct cil_tree_node *node, __attribute__((unused)) uint32_t *finished, void *extra_args)
{
	int rc = SEPOL_ERR;
	struct cil_db *db = extra_args;

	switch (node->flavor) {
	case CIL_BLOCK: {
		struct cil_block *blk = node->data;
		if (blk->is_abstract == CIL_TRUE) {
			*finished = CIL_TREE_SKIP_HEAD;
		}
		break;
	}
	case CIL_MACRO: {
		*finished = CIL_TREE_SKIP_HEAD;
		break;
	}
	case CIL_ROLETYPE: {
		struct cil_roletype *roletype = node->data;
		struct cil_symtab_datum *role_datum = roletype->role;
		struct cil_symtab_datum *type_datum = roletype->type;
		struct cil_tree_node *role_node = role_datum->nodes->head->data;

		if (role_node->flavor == CIL_ROLEATTRIBUTE) {
			struct cil_roleattribute *attr = roletype->role;
			ebitmap_node_t *rnode;
			unsigned int i;
	
			ebitmap_for_each_bit(attr->roles, rnode, i) {
				struct cil_role *role = NULL;

				if (!ebitmap_get_bit(attr->roles, i)) {
					continue;
				}

				role = db->val_to_role[i];

				rc = __cil_role_assign_types(role, type_datum);
				if (rc != SEPOL_OK) {
					goto exit;
				}
			}
		} else {
			struct cil_role *role = roletype->role;

			rc = __cil_role_assign_types(role, type_datum);
			if (rc != SEPOL_OK) {
				goto exit;
			}
		}
		break;
	}
	default:
		break;
	}

	return SEPOL_OK;
exit:
	cil_log(CIL_INFO, "cil_post_db_roletype_helper failed\n");
	return rc;
}

static int __evaluate_level_expression(struct cil_level *level, struct cil_db *db)
{
	if (level->cats != NULL) {
		return __evaluate_cat_expression(level->cats, db);
	}

	return SEPOL_OK;
}

static int __evaluate_levelrange_expression(struct cil_levelrange *levelrange, struct cil_db *db)
{
	int rc = SEPOL_OK;

	if (levelrange->low != NULL && levelrange->low->cats != NULL) {
		rc =  __evaluate_cat_expression(levelrange->low->cats, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}
	if (levelrange->high != NULL && levelrange->high->cats != NULL) {
		rc = __evaluate_cat_expression(levelrange->high->cats, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
	}

exit:
	return rc;
}

static int __cil_post_db_cat_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
{
	int rc = SEPOL_ERR;
	struct cil_db *db = extra_args;

	switch (node->flavor) {
	case CIL_BLOCK: {
		struct cil_block *blk = node->data;
		if (blk->is_abstract == CIL_TRUE) {
			*finished = CIL_TREE_SKIP_HEAD;
		}
		break;
	}
	case CIL_MACRO: {
		*finished = CIL_TREE_SKIP_HEAD;
		break;
	}
	case CIL_CATSET: {
		struct cil_catset *catset = node->data;
		rc = __evaluate_cat_expression(catset->cats, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_SENSCAT: {
		struct cil_senscat *senscat = node->data;
		rc = __evaluate_cat_expression(senscat->cats, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_LEVEL: {
		rc = __evaluate_level_expression(node->data, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_LEVELRANGE: {
		rc = __evaluate_levelrange_expression(node->data, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_USER: {
		struct cil_user *user = node->data;
		rc = __evaluate_level_expression(user->dftlevel, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		rc = __evaluate_levelrange_expression(user->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_SELINUXUSERDEFAULT:
	case CIL_SELINUXUSER: {
		struct cil_selinuxuser *selinuxuser = node->data;
		rc = __evaluate_levelrange_expression(selinuxuser->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_RANGETRANSITION: {
		struct cil_rangetransition *rangetrans = node->data;
		rc = __evaluate_levelrange_expression(rangetrans->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_CONTEXT: {
		struct cil_context *context = node->data;
		rc = __evaluate_levelrange_expression(context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_SIDCONTEXT: {
		struct cil_sidcontext *sidcontext = node->data;
		rc = __evaluate_levelrange_expression(sidcontext->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_FILECON: {
		struct cil_filecon *filecon = node->data;
		if (filecon->context) {
			rc = __evaluate_levelrange_expression(filecon->context->range, db);
			if (rc != SEPOL_OK) {
				goto exit;
			}
		}
		break;
	}
	case CIL_PORTCON: {
		struct cil_portcon *portcon = node->data;
		rc = __evaluate_levelrange_expression(portcon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_NODECON: {
		struct cil_nodecon *nodecon = node->data;
		rc = __evaluate_levelrange_expression(nodecon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_GENFSCON: {
		struct cil_genfscon *genfscon = node->data;
		rc = __evaluate_levelrange_expression(genfscon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_NETIFCON: {
		struct cil_netifcon *netifcon = node->data;
		rc = __evaluate_levelrange_expression(netifcon->if_context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		rc = __evaluate_levelrange_expression(netifcon->packet_context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_PIRQCON: {
		struct cil_pirqcon *pirqcon = node->data;
		rc = __evaluate_levelrange_expression(pirqcon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_IOMEMCON: {
		struct cil_iomemcon *iomemcon = node->data;
		rc = __evaluate_levelrange_expression(iomemcon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_IOPORTCON: {
		struct cil_ioportcon *ioportcon = node->data;
		rc = __evaluate_levelrange_expression(ioportcon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_PCIDEVICECON: {
		struct cil_pcidevicecon *pcidevicecon = node->data;
		rc = __evaluate_levelrange_expression(pcidevicecon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_DEVICETREECON: {
		struct cil_devicetreecon *devicetreecon = node->data;
		rc = __evaluate_levelrange_expression(devicetreecon->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_FSUSE: {
		struct cil_fsuse *fsuse = node->data;
		rc = __evaluate_levelrange_expression(fsuse->context->range, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	default:
		break;
	}

	return SEPOL_OK;

exit:
	return rc;
}

struct perm_to_list {
	enum cil_flavor flavor;
	ebitmap_t *perms;
	struct cil_list *new_list;
};

static int __perm_bits_to_list(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
{
	struct perm_to_list *perm_args = (struct perm_to_list *)args;
	ebitmap_t *perms = perm_args->perms;
	struct cil_list *new_list = perm_args->new_list;
	struct cil_perm *perm = (struct cil_perm *)d;
	unsigned int value = perm->value;

	if (!ebitmap_get_bit(perms, value)) {
		return SEPOL_OK;
	}

	cil_list_append(new_list, CIL_DATUM, d);

	return SEPOL_OK;
}

static int __evaluate_perm_expression(struct cil_list *perms, enum cil_flavor flavor, symtab_t *class_symtab, symtab_t *common_symtab, unsigned int num_perms, struct cil_list **new_list, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct perm_to_list args;
	ebitmap_t bitmap;

	if (cil_verify_is_list(perms, CIL_PERM)) {
		return SEPOL_OK;
	}

	ebitmap_init(&bitmap);
	rc = __cil_expr_to_bitmap(perms, &bitmap, num_perms, db);
	if (rc != SEPOL_OK) {
		ebitmap_destroy(&bitmap);
		goto exit;
	}

	cil_list_init(new_list, flavor);

	args.flavor = flavor;
	args.perms = &bitmap;
	args.new_list = *new_list;

	cil_symtab_map(class_symtab, __perm_bits_to_list, &args);

	if (common_symtab != NULL) {
		cil_symtab_map(common_symtab, __perm_bits_to_list, &args);
	}

	ebitmap_destroy(&bitmap);
	return SEPOL_OK;

exit:
	return rc;
}

static int __evaluate_classperms(struct cil_classperms *cp, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct cil_class *class = cp->class;
	struct cil_class *common = class->common;
	symtab_t *common_symtab = NULL;
	struct cil_list *new_list = NULL;

	if (common) {
		common_symtab = &common->perms;
	}

	rc = __evaluate_perm_expression(cp->perms, CIL_PERM, &class->perms, common_symtab, class->num_perms, &new_list, db);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	if (new_list == NULL) {
		return SEPOL_OK;
	}

	cil_list_destroy(&cp->perms, CIL_FALSE);

	cp->perms = new_list;

	return SEPOL_OK;

exit:
	return rc;
}

static int __evaluate_classperms_list(struct cil_list *classperms, struct cil_db *db)
{
	int rc = SEPOL_ERR;
	struct cil_list_item *curr;

	cil_list_for_each(curr, classperms) {
		if (curr->flavor == CIL_CLASSPERMS) {
			struct cil_classperms *cp = curr->data;
			if (FLAVOR(cp->class) == CIL_CLASS) {
				rc = __evaluate_classperms(cp, db);
				if (rc != SEPOL_OK) {
					goto exit;
				}
			} else { /* MAP */
				struct cil_list_item *i = NULL;
				cil_list_for_each(i, cp->perms) {
					struct cil_perm *cmp = i->data;
					rc = __evaluate_classperms_list(cmp->classperms, db);
					if (rc != SEPOL_OK) {
						goto exit;
					}
				}
			}	
		} else { /* SET */
			struct cil_classperms_set *cp_set = curr->data;
			struct cil_classpermission *cp = cp_set->set;
			rc = __evaluate_classperms_list(cp->classperms, db);
			if (rc != SEPOL_OK) {
				goto exit;
			}
		}
	}

	return SEPOL_OK;

exit:
	return rc;
}

struct class_map_args {
	struct cil_db *db;
	int rc;
};

static int __evaluate_map_perm_classperms(__attribute__((unused)) hashtab_key_t k, hashtab_datum_t d, void *args)
{
	struct class_map_args *map_args = args;
	struct cil_perm *cmp = (struct cil_perm *)d;

	int rc = __evaluate_classperms_list(cmp->classperms, map_args->db);

	if (rc != SEPOL_OK) {
		map_args->rc = rc;
	}

	return SEPOL_OK;
}

static int __evaluate_map_class(struct cil_class *mc, struct cil_db *db)
{
	struct class_map_args map_args;

	map_args.db = db;
	map_args.rc = SEPOL_OK;
	cil_symtab_map(&mc->perms, __evaluate_map_perm_classperms, &map_args);

	return map_args.rc;
}

static int __cil_post_db_classperms_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
{
	int rc = SEPOL_ERR;
	struct cil_db *db = extra_args;

	switch (node->flavor) {
	case CIL_BLOCK: {
		struct cil_block *blk = node->data;
		if (blk->is_abstract == CIL_TRUE) {
			*finished = CIL_TREE_SKIP_HEAD;
		}
		break;
	}
	case CIL_MACRO:
		*finished = CIL_TREE_SKIP_HEAD;
		break;
	case CIL_MAP_CLASS: {
		rc = __evaluate_map_class(node->data, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_CLASSPERMISSION: {
		struct cil_classpermission *cp = node->data;
		rc = __evaluate_classperms_list(cp->classperms, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_AVRULE: {
		struct cil_avrule *avrule = node->data;
		rc = __evaluate_classperms_list(avrule->classperms, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	case CIL_CONSTRAIN:
	case CIL_MLSCONSTRAIN: {
		struct cil_constrain *constrain = node->data;
		rc = __evaluate_classperms_list(constrain->classperms, db);
		if (rc != SEPOL_OK) {
			goto exit;
		}
		break;
	}
	default:
		break;
	}

	return SEPOL_OK;

exit:
	return rc;
}

static int cil_post_db(struct cil_db *db)
{
	int rc = SEPOL_ERR;

	rc = cil_tree_walk(db->ast->root, __cil_post_db_count_helper, NULL, NULL, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_INFO, "Failure during cil databse count helper\n");
		goto exit;
	}

	rc = cil_tree_walk(db->ast->root, __cil_post_db_array_helper, NULL, NULL, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_INFO, "Failure during cil database array helper\n");
		goto exit;
	}

	rc = cil_tree_walk(db->ast->root, __cil_post_db_attr_helper, NULL, NULL, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_INFO, "Failed to create attribute bitmaps\n");
		goto exit;
	}

	rc = cil_tree_walk(db->ast->root, __cil_post_db_roletype_helper, NULL, NULL, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_INFO, "Failed during roletype association\n");
		goto exit;
	}

	rc = cil_tree_walk(db->ast->root, __cil_post_db_classperms_helper, NULL, NULL, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_INFO, "Failed to evaluate class mapping permissions expressions\n");
		goto exit;
	}

	rc = cil_tree_walk(db->ast->root, __cil_post_db_cat_helper, NULL, NULL, db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_INFO, "Failed to evaluate category expressions\n");
		goto exit;
	}

	qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
	qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
	qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
	qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
	qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
	qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare);
	qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
	qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
	qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
	qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
	qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);

exit:
	return rc;
}

static int cil_post_verify(struct cil_db *db)
{
	int rc = SEPOL_ERR;
	int avrule_cnt = 0;
	int handleunknown = -1;
	int mls = -1;
	int nseuserdflt = 0;
	int pass = 0;
	struct cil_args_verify extra_args;
	struct cil_complex_symtab csymtab;

	cil_complex_symtab_init(&csymtab, CIL_CLASS_SYM_SIZE);

	extra_args.db = db;
	extra_args.csymtab = &csymtab;
	extra_args.avrule_cnt = &avrule_cnt;
	extra_args.handleunknown = &handleunknown;
	extra_args.mls = &mls;
	extra_args.nseuserdflt = &nseuserdflt;
	extra_args.pass = &pass;

	for (pass = 0; pass < 2; pass++) {
		rc = cil_tree_walk(db->ast->root, __cil_verify_helper, NULL, NULL, &extra_args);
		if (rc != SEPOL_OK) {
			cil_log(CIL_ERR, "Failed to verify cil database\n");
			goto exit;
		}
	}

	if (db->handle_unknown == -1) {
		if (handleunknown == -1) {
			db->handle_unknown = SEPOL_DENY_UNKNOWN;
		} else {
			db->handle_unknown = handleunknown;
		}
	}

	if (db->mls == -1) {
		if (mls == -1) {
			db->mls = CIL_FALSE;
		} else {
			db->mls = mls;
		}
	}

	if (avrule_cnt == 0) {
		cil_log(CIL_ERR, "Policy must include at least one avrule\n");
		rc = SEPOL_ERR;
		goto exit;
	}

	if (nseuserdflt > 1) {
		cil_log(CIL_ERR, "Policy cannot contain more than one selinuxuserdefault, found: %d\n", nseuserdflt);
		rc = SEPOL_ERR;
		goto exit;
	}

exit:
	cil_complex_symtab_destroy(&csymtab);
	return rc;
}

int cil_post_process(struct cil_db *db)
{
	int rc = SEPOL_ERR;

	rc = cil_verify_no_classperms_loop(db);
	if (rc != SEPOL_OK) {
		goto exit;
	}

	rc = cil_post_db(db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_ERR, "Failed post db handling\n");
		goto exit;
	}

	rc = cil_post_verify(db);
	if (rc != SEPOL_OK) {
		cil_log(CIL_ERR, "Failed to verify cil database\n");
		goto exit;
	}

exit:
	return rc;
		
}