16cd6a6acSopenharmony_ci/* Authors: Karl MacMillan <kmacmillan@tresys.com>
26cd6a6acSopenharmony_ci *          Frank Mayer <mayerf@tresys.com>
36cd6a6acSopenharmony_ci *          David Caplan <dac@tresys.com>
46cd6a6acSopenharmony_ci *
56cd6a6acSopenharmony_ci * Copyright (C) 2003 - 2005 Tresys Technology, LLC
66cd6a6acSopenharmony_ci *
76cd6a6acSopenharmony_ci *  This library is free software; you can redistribute it and/or
86cd6a6acSopenharmony_ci *  modify it under the terms of the GNU Lesser General Public
96cd6a6acSopenharmony_ci *  License as published by the Free Software Foundation; either
106cd6a6acSopenharmony_ci *  version 2.1 of the License, or (at your option) any later version.
116cd6a6acSopenharmony_ci *
126cd6a6acSopenharmony_ci *  This library is distributed in the hope that it will be useful,
136cd6a6acSopenharmony_ci *  but WITHOUT ANY WARRANTY; without even the implied warranty of
146cd6a6acSopenharmony_ci *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
156cd6a6acSopenharmony_ci *  Lesser General Public License for more details.
166cd6a6acSopenharmony_ci *
176cd6a6acSopenharmony_ci *  You should have received a copy of the GNU Lesser General Public
186cd6a6acSopenharmony_ci *  License along with this library; if not, write to the Free Software
196cd6a6acSopenharmony_ci *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
206cd6a6acSopenharmony_ci */
216cd6a6acSopenharmony_ci
226cd6a6acSopenharmony_ci#include <stdlib.h>
236cd6a6acSopenharmony_ci
246cd6a6acSopenharmony_ci#include <sepol/policydb/flask_types.h>
256cd6a6acSopenharmony_ci#include <sepol/policydb/conditional.h>
266cd6a6acSopenharmony_ci
276cd6a6acSopenharmony_ci#include "private.h"
286cd6a6acSopenharmony_ci#include "debug.h"
296cd6a6acSopenharmony_ci
306cd6a6acSopenharmony_ci/* move all type rules to top of t/f lists to help kernel on evaluation */
316cd6a6acSopenharmony_cistatic void cond_optimize(cond_av_list_t ** l)
326cd6a6acSopenharmony_ci{
336cd6a6acSopenharmony_ci	cond_av_list_t *top, *p, *cur;
346cd6a6acSopenharmony_ci
356cd6a6acSopenharmony_ci	top = p = cur = *l;
366cd6a6acSopenharmony_ci
376cd6a6acSopenharmony_ci	while (cur) {
386cd6a6acSopenharmony_ci		if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) {
396cd6a6acSopenharmony_ci			p->next = cur->next;
406cd6a6acSopenharmony_ci			cur->next = top;
416cd6a6acSopenharmony_ci			top = cur;
426cd6a6acSopenharmony_ci			cur = p->next;
436cd6a6acSopenharmony_ci		} else {
446cd6a6acSopenharmony_ci			p = cur;
456cd6a6acSopenharmony_ci			cur = cur->next;
466cd6a6acSopenharmony_ci		}
476cd6a6acSopenharmony_ci	}
486cd6a6acSopenharmony_ci	*l = top;
496cd6a6acSopenharmony_ci}
506cd6a6acSopenharmony_ci
516cd6a6acSopenharmony_ci/* reorder t/f lists for kernel */
526cd6a6acSopenharmony_civoid cond_optimize_lists(cond_list_t * cl)
536cd6a6acSopenharmony_ci{
546cd6a6acSopenharmony_ci	cond_list_t *n;
556cd6a6acSopenharmony_ci
566cd6a6acSopenharmony_ci	for (n = cl; n != NULL; n = n->next) {
576cd6a6acSopenharmony_ci		cond_optimize(&n->true_list);
586cd6a6acSopenharmony_ci		cond_optimize(&n->false_list);
596cd6a6acSopenharmony_ci	}
606cd6a6acSopenharmony_ci}
616cd6a6acSopenharmony_ci
626cd6a6acSopenharmony_cistatic int bool_present(unsigned int target, unsigned int bools[],
636cd6a6acSopenharmony_ci			unsigned int num_bools)
646cd6a6acSopenharmony_ci{
656cd6a6acSopenharmony_ci	unsigned int i = 0;
666cd6a6acSopenharmony_ci	int ret = 1;
676cd6a6acSopenharmony_ci
686cd6a6acSopenharmony_ci	if (num_bools > COND_MAX_BOOLS) {
696cd6a6acSopenharmony_ci		return 0;
706cd6a6acSopenharmony_ci	}
716cd6a6acSopenharmony_ci	while (i < num_bools && target != bools[i])
726cd6a6acSopenharmony_ci		i++;
736cd6a6acSopenharmony_ci	if (i == num_bools)
746cd6a6acSopenharmony_ci		ret = 0;	/* got to end w/o match */
756cd6a6acSopenharmony_ci	return ret;
766cd6a6acSopenharmony_ci}
776cd6a6acSopenharmony_ci
786cd6a6acSopenharmony_cistatic int same_bools(cond_node_t * a, cond_node_t * b)
796cd6a6acSopenharmony_ci{
806cd6a6acSopenharmony_ci	unsigned int i, x;
816cd6a6acSopenharmony_ci
826cd6a6acSopenharmony_ci	x = a->nbools;
836cd6a6acSopenharmony_ci
846cd6a6acSopenharmony_ci	/* same number of bools? */
856cd6a6acSopenharmony_ci	if (x != b->nbools)
866cd6a6acSopenharmony_ci		return 0;
876cd6a6acSopenharmony_ci
886cd6a6acSopenharmony_ci	/* make sure all the bools in a are also in b */
896cd6a6acSopenharmony_ci	for (i = 0; i < x; i++)
906cd6a6acSopenharmony_ci		if (!bool_present(a->bool_ids[i], b->bool_ids, x))
916cd6a6acSopenharmony_ci			return 0;
926cd6a6acSopenharmony_ci	return 1;
936cd6a6acSopenharmony_ci}
946cd6a6acSopenharmony_ci
956cd6a6acSopenharmony_ci/*
966cd6a6acSopenharmony_ci * Determine if two conditional expressions are equal.
976cd6a6acSopenharmony_ci */
986cd6a6acSopenharmony_ciint cond_expr_equal(cond_node_t * a, cond_node_t * b)
996cd6a6acSopenharmony_ci{
1006cd6a6acSopenharmony_ci	cond_expr_t *cur_a, *cur_b;
1016cd6a6acSopenharmony_ci
1026cd6a6acSopenharmony_ci	if (a == NULL || b == NULL)
1036cd6a6acSopenharmony_ci		return 0;
1046cd6a6acSopenharmony_ci
1056cd6a6acSopenharmony_ci	if (a->nbools != b->nbools)
1066cd6a6acSopenharmony_ci		return 0;
1076cd6a6acSopenharmony_ci
1086cd6a6acSopenharmony_ci	/* if exprs have <= COND_MAX_BOOLS we can check the precompute values
1096cd6a6acSopenharmony_ci	 * for the expressions.
1106cd6a6acSopenharmony_ci	 */
1116cd6a6acSopenharmony_ci	if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) {
1126cd6a6acSopenharmony_ci		if (!same_bools(a, b))
1136cd6a6acSopenharmony_ci			return 0;
1146cd6a6acSopenharmony_ci		return (a->expr_pre_comp == b->expr_pre_comp);
1156cd6a6acSopenharmony_ci	}
1166cd6a6acSopenharmony_ci
1176cd6a6acSopenharmony_ci	/* for long expressions we check for exactly the same expression */
1186cd6a6acSopenharmony_ci	cur_a = a->expr;
1196cd6a6acSopenharmony_ci	cur_b = b->expr;
1206cd6a6acSopenharmony_ci	while (1) {
1216cd6a6acSopenharmony_ci		if (cur_a == NULL && cur_b == NULL)
1226cd6a6acSopenharmony_ci			return 1;
1236cd6a6acSopenharmony_ci		else if (cur_a == NULL || cur_b == NULL)
1246cd6a6acSopenharmony_ci			return 0;
1256cd6a6acSopenharmony_ci		if (cur_a->expr_type != cur_b->expr_type)
1266cd6a6acSopenharmony_ci			return 0;
1276cd6a6acSopenharmony_ci		if (cur_a->expr_type == COND_BOOL) {
1286cd6a6acSopenharmony_ci			if (cur_a->bool != cur_b->bool)
1296cd6a6acSopenharmony_ci				return 0;
1306cd6a6acSopenharmony_ci		}
1316cd6a6acSopenharmony_ci		cur_a = cur_a->next;
1326cd6a6acSopenharmony_ci		cur_b = cur_b->next;
1336cd6a6acSopenharmony_ci	}
1346cd6a6acSopenharmony_ci	return 1;
1356cd6a6acSopenharmony_ci}
1366cd6a6acSopenharmony_ci
1376cd6a6acSopenharmony_ci/* Create a new conditional node, optionally copying
1386cd6a6acSopenharmony_ci * the conditional expression from an existing node.
1396cd6a6acSopenharmony_ci * If node is NULL then a new node will be created
1406cd6a6acSopenharmony_ci * with no conditional expression.
1416cd6a6acSopenharmony_ci */
1426cd6a6acSopenharmony_cicond_node_t *cond_node_create(policydb_t * p, cond_node_t * node)
1436cd6a6acSopenharmony_ci{
1446cd6a6acSopenharmony_ci	cond_node_t *new_node;
1456cd6a6acSopenharmony_ci	unsigned int i;
1466cd6a6acSopenharmony_ci
1476cd6a6acSopenharmony_ci	new_node = (cond_node_t *)malloc(sizeof(cond_node_t));
1486cd6a6acSopenharmony_ci	if (!new_node) {
1496cd6a6acSopenharmony_ci		return NULL;
1506cd6a6acSopenharmony_ci	}
1516cd6a6acSopenharmony_ci	memset(new_node, 0, sizeof(cond_node_t));
1526cd6a6acSopenharmony_ci
1536cd6a6acSopenharmony_ci	if (node) {
1546cd6a6acSopenharmony_ci		new_node->expr = cond_copy_expr(node->expr);
1556cd6a6acSopenharmony_ci		if (!new_node->expr) {
1566cd6a6acSopenharmony_ci			free(new_node);
1576cd6a6acSopenharmony_ci			return NULL;
1586cd6a6acSopenharmony_ci		}
1596cd6a6acSopenharmony_ci		new_node->cur_state = cond_evaluate_expr(p, new_node->expr);
1606cd6a6acSopenharmony_ci		new_node->nbools = node->nbools;
1616cd6a6acSopenharmony_ci		for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++)
1626cd6a6acSopenharmony_ci			new_node->bool_ids[i] = node->bool_ids[i];
1636cd6a6acSopenharmony_ci		new_node->expr_pre_comp = node->expr_pre_comp;
1646cd6a6acSopenharmony_ci		new_node->flags = node->flags;
1656cd6a6acSopenharmony_ci	}
1666cd6a6acSopenharmony_ci
1676cd6a6acSopenharmony_ci	return new_node;
1686cd6a6acSopenharmony_ci}
1696cd6a6acSopenharmony_ci
1706cd6a6acSopenharmony_ci/* Find a conditional (the needle) within a list of existing ones (the
1716cd6a6acSopenharmony_ci * haystack) that has a matching expression.  If found, return a
1726cd6a6acSopenharmony_ci * pointer to the existing node, setting 'was_created' to 0.
1736cd6a6acSopenharmony_ci * Otherwise create a new one and return it, setting 'was_created' to
1746cd6a6acSopenharmony_ci * 1. */
1756cd6a6acSopenharmony_cicond_node_t *cond_node_find(policydb_t * p,
1766cd6a6acSopenharmony_ci			    cond_node_t * needle, cond_node_t * haystack,
1776cd6a6acSopenharmony_ci			    int *was_created)
1786cd6a6acSopenharmony_ci{
1796cd6a6acSopenharmony_ci	while (haystack) {
1806cd6a6acSopenharmony_ci		if (cond_expr_equal(needle, haystack)) {
1816cd6a6acSopenharmony_ci			*was_created = 0;
1826cd6a6acSopenharmony_ci			return haystack;
1836cd6a6acSopenharmony_ci		}
1846cd6a6acSopenharmony_ci		haystack = haystack->next;
1856cd6a6acSopenharmony_ci	}
1866cd6a6acSopenharmony_ci	*was_created = 1;
1876cd6a6acSopenharmony_ci
1886cd6a6acSopenharmony_ci	return cond_node_create(p, needle);
1896cd6a6acSopenharmony_ci}
1906cd6a6acSopenharmony_ci
1916cd6a6acSopenharmony_ci/* return either a pre-existing matching node or create a new node */
1926cd6a6acSopenharmony_cicond_node_t *cond_node_search(policydb_t * p, cond_node_t * list,
1936cd6a6acSopenharmony_ci			      cond_node_t * cn)
1946cd6a6acSopenharmony_ci{
1956cd6a6acSopenharmony_ci	int was_created;
1966cd6a6acSopenharmony_ci	cond_node_t *result = cond_node_find(p, cn, list, &was_created);
1976cd6a6acSopenharmony_ci	if (result != NULL && was_created) {
1986cd6a6acSopenharmony_ci		/* add conditional node to policy list */
1996cd6a6acSopenharmony_ci		result->next = p->cond_list;
2006cd6a6acSopenharmony_ci		p->cond_list = result;
2016cd6a6acSopenharmony_ci	}
2026cd6a6acSopenharmony_ci	return result;
2036cd6a6acSopenharmony_ci}
2046cd6a6acSopenharmony_ci
2056cd6a6acSopenharmony_ci/*
2066cd6a6acSopenharmony_ci * cond_evaluate_expr evaluates a conditional expr
2076cd6a6acSopenharmony_ci * in reverse polish notation. It returns true (1), false (0),
2086cd6a6acSopenharmony_ci * or undefined (-1). Undefined occurs when the expression
2096cd6a6acSopenharmony_ci * exceeds the stack depth of COND_EXPR_MAXDEPTH.
2106cd6a6acSopenharmony_ci */
2116cd6a6acSopenharmony_ciint cond_evaluate_expr(policydb_t * p, cond_expr_t * expr)
2126cd6a6acSopenharmony_ci{
2136cd6a6acSopenharmony_ci
2146cd6a6acSopenharmony_ci	cond_expr_t *cur;
2156cd6a6acSopenharmony_ci	int s[COND_EXPR_MAXDEPTH];
2166cd6a6acSopenharmony_ci	int sp = -1;
2176cd6a6acSopenharmony_ci
2186cd6a6acSopenharmony_ci	s[0] = -1;
2196cd6a6acSopenharmony_ci
2206cd6a6acSopenharmony_ci	for (cur = expr; cur != NULL; cur = cur->next) {
2216cd6a6acSopenharmony_ci		switch (cur->expr_type) {
2226cd6a6acSopenharmony_ci		case COND_BOOL:
2236cd6a6acSopenharmony_ci			if (sp == (COND_EXPR_MAXDEPTH - 1))
2246cd6a6acSopenharmony_ci				return -1;
2256cd6a6acSopenharmony_ci			sp++;
2266cd6a6acSopenharmony_ci			s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
2276cd6a6acSopenharmony_ci			break;
2286cd6a6acSopenharmony_ci		case COND_NOT:
2296cd6a6acSopenharmony_ci			if (sp < 0)
2306cd6a6acSopenharmony_ci				return -1;
2316cd6a6acSopenharmony_ci			s[sp] = !s[sp];
2326cd6a6acSopenharmony_ci			break;
2336cd6a6acSopenharmony_ci		case COND_OR:
2346cd6a6acSopenharmony_ci			if (sp < 1)
2356cd6a6acSopenharmony_ci				return -1;
2366cd6a6acSopenharmony_ci			sp--;
2376cd6a6acSopenharmony_ci			s[sp] |= s[sp + 1];
2386cd6a6acSopenharmony_ci			break;
2396cd6a6acSopenharmony_ci		case COND_AND:
2406cd6a6acSopenharmony_ci			if (sp < 1)
2416cd6a6acSopenharmony_ci				return -1;
2426cd6a6acSopenharmony_ci			sp--;
2436cd6a6acSopenharmony_ci			s[sp] &= s[sp + 1];
2446cd6a6acSopenharmony_ci			break;
2456cd6a6acSopenharmony_ci		case COND_XOR:
2466cd6a6acSopenharmony_ci			if (sp < 1)
2476cd6a6acSopenharmony_ci				return -1;
2486cd6a6acSopenharmony_ci			sp--;
2496cd6a6acSopenharmony_ci			s[sp] ^= s[sp + 1];
2506cd6a6acSopenharmony_ci			break;
2516cd6a6acSopenharmony_ci		case COND_EQ:
2526cd6a6acSopenharmony_ci			if (sp < 1)
2536cd6a6acSopenharmony_ci				return -1;
2546cd6a6acSopenharmony_ci			sp--;
2556cd6a6acSopenharmony_ci			s[sp] = (s[sp] == s[sp + 1]);
2566cd6a6acSopenharmony_ci			break;
2576cd6a6acSopenharmony_ci		case COND_NEQ:
2586cd6a6acSopenharmony_ci			if (sp < 1)
2596cd6a6acSopenharmony_ci				return -1;
2606cd6a6acSopenharmony_ci			sp--;
2616cd6a6acSopenharmony_ci			s[sp] = (s[sp] != s[sp + 1]);
2626cd6a6acSopenharmony_ci			break;
2636cd6a6acSopenharmony_ci		default:
2646cd6a6acSopenharmony_ci			return -1;
2656cd6a6acSopenharmony_ci		}
2666cd6a6acSopenharmony_ci	}
2676cd6a6acSopenharmony_ci	return s[0];
2686cd6a6acSopenharmony_ci}
2696cd6a6acSopenharmony_ci
2706cd6a6acSopenharmony_cicond_expr_t *cond_copy_expr(cond_expr_t * expr)
2716cd6a6acSopenharmony_ci{
2726cd6a6acSopenharmony_ci	cond_expr_t *cur, *head, *tail, *new_expr;
2736cd6a6acSopenharmony_ci	tail = head = NULL;
2746cd6a6acSopenharmony_ci	cur = expr;
2756cd6a6acSopenharmony_ci	while (cur) {
2766cd6a6acSopenharmony_ci		new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t));
2776cd6a6acSopenharmony_ci		if (!new_expr)
2786cd6a6acSopenharmony_ci			goto free_head;
2796cd6a6acSopenharmony_ci		memset(new_expr, 0, sizeof(cond_expr_t));
2806cd6a6acSopenharmony_ci
2816cd6a6acSopenharmony_ci		new_expr->expr_type = cur->expr_type;
2826cd6a6acSopenharmony_ci		new_expr->bool = cur->bool;
2836cd6a6acSopenharmony_ci
2846cd6a6acSopenharmony_ci		if (!head)
2856cd6a6acSopenharmony_ci			head = new_expr;
2866cd6a6acSopenharmony_ci		if (tail)
2876cd6a6acSopenharmony_ci			tail->next = new_expr;
2886cd6a6acSopenharmony_ci		tail = new_expr;
2896cd6a6acSopenharmony_ci		cur = cur->next;
2906cd6a6acSopenharmony_ci	}
2916cd6a6acSopenharmony_ci	return head;
2926cd6a6acSopenharmony_ci
2936cd6a6acSopenharmony_ci      free_head:
2946cd6a6acSopenharmony_ci	while (head) {
2956cd6a6acSopenharmony_ci		tail = head->next;
2966cd6a6acSopenharmony_ci		free(head);
2976cd6a6acSopenharmony_ci		head = tail;
2986cd6a6acSopenharmony_ci	}
2996cd6a6acSopenharmony_ci	return NULL;
3006cd6a6acSopenharmony_ci}
3016cd6a6acSopenharmony_ci
3026cd6a6acSopenharmony_ci/*
3036cd6a6acSopenharmony_ci * evaluate_cond_node evaluates the conditional stored in
3046cd6a6acSopenharmony_ci * a cond_node_t and if the result is different than the
3056cd6a6acSopenharmony_ci * current state of the node it sets the rules in the true/false
3066cd6a6acSopenharmony_ci * list appropriately. If the result of the expression is undefined
3076cd6a6acSopenharmony_ci * all of the rules are disabled for safety.
3086cd6a6acSopenharmony_ci */
3096cd6a6acSopenharmony_cistatic int evaluate_cond_node(policydb_t * p, cond_node_t * node)
3106cd6a6acSopenharmony_ci{
3116cd6a6acSopenharmony_ci	int new_state;
3126cd6a6acSopenharmony_ci	cond_av_list_t *cur;
3136cd6a6acSopenharmony_ci
3146cd6a6acSopenharmony_ci	new_state = cond_evaluate_expr(p, node->expr);
3156cd6a6acSopenharmony_ci	if (new_state != node->cur_state) {
3166cd6a6acSopenharmony_ci		node->cur_state = new_state;
3176cd6a6acSopenharmony_ci		if (new_state == -1)
3186cd6a6acSopenharmony_ci			WARN(NULL, "expression result was undefined - disabling all rules.");
3196cd6a6acSopenharmony_ci		/* turn the rules on or off */
3206cd6a6acSopenharmony_ci		for (cur = node->true_list; cur != NULL; cur = cur->next) {
3216cd6a6acSopenharmony_ci			if (new_state <= 0) {
3226cd6a6acSopenharmony_ci				cur->node->key.specified &= ~AVTAB_ENABLED;
3236cd6a6acSopenharmony_ci			} else {
3246cd6a6acSopenharmony_ci				cur->node->key.specified |= AVTAB_ENABLED;
3256cd6a6acSopenharmony_ci			}
3266cd6a6acSopenharmony_ci		}
3276cd6a6acSopenharmony_ci
3286cd6a6acSopenharmony_ci		for (cur = node->false_list; cur != NULL; cur = cur->next) {
3296cd6a6acSopenharmony_ci			/* -1 or 1 */
3306cd6a6acSopenharmony_ci			if (new_state) {
3316cd6a6acSopenharmony_ci				cur->node->key.specified &= ~AVTAB_ENABLED;
3326cd6a6acSopenharmony_ci			} else {
3336cd6a6acSopenharmony_ci				cur->node->key.specified |= AVTAB_ENABLED;
3346cd6a6acSopenharmony_ci			}
3356cd6a6acSopenharmony_ci		}
3366cd6a6acSopenharmony_ci	}
3376cd6a6acSopenharmony_ci	return 0;
3386cd6a6acSopenharmony_ci}
3396cd6a6acSopenharmony_ci
3406cd6a6acSopenharmony_ci/* precompute and simplify an expression if possible.  If left with !expression, change
3416cd6a6acSopenharmony_ci * to expression and switch t and f. precompute expression for expressions with limited
3426cd6a6acSopenharmony_ci * number of bools.
3436cd6a6acSopenharmony_ci */
3446cd6a6acSopenharmony_ciint cond_normalize_expr(policydb_t * p, cond_node_t * cn)
3456cd6a6acSopenharmony_ci{
3466cd6a6acSopenharmony_ci	cond_expr_t *ne, *e;
3476cd6a6acSopenharmony_ci	cond_av_list_t *tmp;
3486cd6a6acSopenharmony_ci	unsigned int i, j, orig_value[COND_MAX_BOOLS];
3496cd6a6acSopenharmony_ci	int k;
3506cd6a6acSopenharmony_ci	uint32_t test = 0x0;
3516cd6a6acSopenharmony_ci	avrule_t *tmp2;
3526cd6a6acSopenharmony_ci
3536cd6a6acSopenharmony_ci	cn->nbools = 0;
3546cd6a6acSopenharmony_ci
3556cd6a6acSopenharmony_ci	memset(cn->bool_ids, 0, sizeof(cn->bool_ids));
3566cd6a6acSopenharmony_ci	cn->expr_pre_comp = 0x0;
3576cd6a6acSopenharmony_ci
3586cd6a6acSopenharmony_ci	/* take care of !expr case */
3596cd6a6acSopenharmony_ci	ne = NULL;
3606cd6a6acSopenharmony_ci	e = cn->expr;
3616cd6a6acSopenharmony_ci
3626cd6a6acSopenharmony_ci	/* because it's RPN look at last element */
3636cd6a6acSopenharmony_ci	while (e->next != NULL) {
3646cd6a6acSopenharmony_ci		ne = e;
3656cd6a6acSopenharmony_ci		e = e->next;
3666cd6a6acSopenharmony_ci	}
3676cd6a6acSopenharmony_ci	if (e->expr_type == COND_NOT) {
3686cd6a6acSopenharmony_ci		if (ne) {
3696cd6a6acSopenharmony_ci			ne->next = NULL;
3706cd6a6acSopenharmony_ci		} else {	/* ne should never be NULL */
3716cd6a6acSopenharmony_ci			ERR(NULL, "Found expr with no bools and only a ! - this should never happen.");
3726cd6a6acSopenharmony_ci			return -1;
3736cd6a6acSopenharmony_ci		}
3746cd6a6acSopenharmony_ci		/* swap the true and false lists */
3756cd6a6acSopenharmony_ci		tmp = cn->true_list;
3766cd6a6acSopenharmony_ci		cn->true_list = cn->false_list;
3776cd6a6acSopenharmony_ci		cn->false_list = tmp;
3786cd6a6acSopenharmony_ci		tmp2 = cn->avtrue_list;
3796cd6a6acSopenharmony_ci		cn->avtrue_list = cn->avfalse_list;
3806cd6a6acSopenharmony_ci		cn->avfalse_list = tmp2;
3816cd6a6acSopenharmony_ci
3826cd6a6acSopenharmony_ci		/* free the "not" node in the list */
3836cd6a6acSopenharmony_ci		free(e);
3846cd6a6acSopenharmony_ci	}
3856cd6a6acSopenharmony_ci
3866cd6a6acSopenharmony_ci	/* find all the bools in the expression */
3876cd6a6acSopenharmony_ci	for (e = cn->expr; e != NULL; e = e->next) {
3886cd6a6acSopenharmony_ci		switch (e->expr_type) {
3896cd6a6acSopenharmony_ci		case COND_BOOL:
3906cd6a6acSopenharmony_ci			/* see if we've already seen this bool */
3916cd6a6acSopenharmony_ci			if (!bool_present(e->bool, cn->bool_ids, cn->nbools)) {
3926cd6a6acSopenharmony_ci				/* count em all but only record up to COND_MAX_BOOLS */
3936cd6a6acSopenharmony_ci				if (cn->nbools < COND_MAX_BOOLS)
3946cd6a6acSopenharmony_ci					cn->bool_ids[cn->nbools++] = e->bool;
3956cd6a6acSopenharmony_ci				else
3966cd6a6acSopenharmony_ci					cn->nbools++;
3976cd6a6acSopenharmony_ci			}
3986cd6a6acSopenharmony_ci			break;
3996cd6a6acSopenharmony_ci		default:
4006cd6a6acSopenharmony_ci			break;
4016cd6a6acSopenharmony_ci		}
4026cd6a6acSopenharmony_ci	}
4036cd6a6acSopenharmony_ci
4046cd6a6acSopenharmony_ci	/* only precompute for exprs with <= COND_AX_BOOLS */
4056cd6a6acSopenharmony_ci	if (cn->nbools <= COND_MAX_BOOLS) {
4066cd6a6acSopenharmony_ci		/* save the default values for the bools so we can play with them */
4076cd6a6acSopenharmony_ci		for (i = 0; i < cn->nbools; i++) {
4086cd6a6acSopenharmony_ci			orig_value[i] =
4096cd6a6acSopenharmony_ci			    p->bool_val_to_struct[cn->bool_ids[i] - 1]->state;
4106cd6a6acSopenharmony_ci		}
4116cd6a6acSopenharmony_ci
4126cd6a6acSopenharmony_ci		/* loop through all possible combinations of values for bools in expression */
4136cd6a6acSopenharmony_ci		for (test = 0x0; test < (UINT32_C(1) << cn->nbools); test++) {
4146cd6a6acSopenharmony_ci			/* temporarily set the value for all the bools in the
4156cd6a6acSopenharmony_ci			 * expression using the corr.  bit in test */
4166cd6a6acSopenharmony_ci			for (j = 0; j < cn->nbools; j++) {
4176cd6a6acSopenharmony_ci				p->bool_val_to_struct[cn->bool_ids[j] -
4186cd6a6acSopenharmony_ci						      1]->state =
4196cd6a6acSopenharmony_ci				    (test & (UINT32_C(1) << j)) ? 1 : 0;
4206cd6a6acSopenharmony_ci			}
4216cd6a6acSopenharmony_ci			k = cond_evaluate_expr(p, cn->expr);
4226cd6a6acSopenharmony_ci			if (k == -1) {
4236cd6a6acSopenharmony_ci				ERR(NULL, "While testing expression, expression result "
4246cd6a6acSopenharmony_ci				     "was undefined - this should never happen.");
4256cd6a6acSopenharmony_ci				return -1;
4266cd6a6acSopenharmony_ci			}
4276cd6a6acSopenharmony_ci			/* set the bit if expression evaluates true */
4286cd6a6acSopenharmony_ci			if (k)
4296cd6a6acSopenharmony_ci				cn->expr_pre_comp |= UINT32_C(1) << test;
4306cd6a6acSopenharmony_ci		}
4316cd6a6acSopenharmony_ci
4326cd6a6acSopenharmony_ci		/* restore bool default values */
4336cd6a6acSopenharmony_ci		for (i = 0; i < cn->nbools; i++)
4346cd6a6acSopenharmony_ci			p->bool_val_to_struct[cn->bool_ids[i] - 1]->state =
4356cd6a6acSopenharmony_ci			    orig_value[i];
4366cd6a6acSopenharmony_ci	}
4376cd6a6acSopenharmony_ci	return 0;
4386cd6a6acSopenharmony_ci}
4396cd6a6acSopenharmony_ci
4406cd6a6acSopenharmony_ciint evaluate_conds(policydb_t * p)
4416cd6a6acSopenharmony_ci{
4426cd6a6acSopenharmony_ci	int ret;
4436cd6a6acSopenharmony_ci	cond_node_t *cur;
4446cd6a6acSopenharmony_ci
4456cd6a6acSopenharmony_ci	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
4466cd6a6acSopenharmony_ci		ret = evaluate_cond_node(p, cur);
4476cd6a6acSopenharmony_ci		if (ret)
4486cd6a6acSopenharmony_ci			return ret;
4496cd6a6acSopenharmony_ci	}
4506cd6a6acSopenharmony_ci	return 0;
4516cd6a6acSopenharmony_ci}
4526cd6a6acSopenharmony_ci
4536cd6a6acSopenharmony_ciint cond_policydb_init(policydb_t * p)
4546cd6a6acSopenharmony_ci{
4556cd6a6acSopenharmony_ci	p->bool_val_to_struct = NULL;
4566cd6a6acSopenharmony_ci	p->cond_list = NULL;
4576cd6a6acSopenharmony_ci	if (avtab_init(&p->te_cond_avtab))
4586cd6a6acSopenharmony_ci		return -1;
4596cd6a6acSopenharmony_ci
4606cd6a6acSopenharmony_ci	return 0;
4616cd6a6acSopenharmony_ci}
4626cd6a6acSopenharmony_ci
4636cd6a6acSopenharmony_civoid cond_av_list_destroy(cond_av_list_t * list)
4646cd6a6acSopenharmony_ci{
4656cd6a6acSopenharmony_ci	cond_av_list_t *cur, *next;
4666cd6a6acSopenharmony_ci	for (cur = list; cur != NULL; cur = next) {
4676cd6a6acSopenharmony_ci		next = cur->next;
4686cd6a6acSopenharmony_ci		/* the avtab_ptr_t node is destroy by the avtab */
4696cd6a6acSopenharmony_ci		free(cur);
4706cd6a6acSopenharmony_ci	}
4716cd6a6acSopenharmony_ci}
4726cd6a6acSopenharmony_ci
4736cd6a6acSopenharmony_civoid cond_expr_destroy(cond_expr_t * expr)
4746cd6a6acSopenharmony_ci{
4756cd6a6acSopenharmony_ci	cond_expr_t *cur_expr, *next_expr;
4766cd6a6acSopenharmony_ci
4776cd6a6acSopenharmony_ci	if (!expr)
4786cd6a6acSopenharmony_ci		return;
4796cd6a6acSopenharmony_ci
4806cd6a6acSopenharmony_ci	for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) {
4816cd6a6acSopenharmony_ci		next_expr = cur_expr->next;
4826cd6a6acSopenharmony_ci		free(cur_expr);
4836cd6a6acSopenharmony_ci	}
4846cd6a6acSopenharmony_ci}
4856cd6a6acSopenharmony_ci
4866cd6a6acSopenharmony_civoid cond_node_destroy(cond_node_t * node)
4876cd6a6acSopenharmony_ci{
4886cd6a6acSopenharmony_ci	if (!node)
4896cd6a6acSopenharmony_ci		return;
4906cd6a6acSopenharmony_ci
4916cd6a6acSopenharmony_ci	cond_expr_destroy(node->expr);
4926cd6a6acSopenharmony_ci	avrule_list_destroy(node->avtrue_list);
4936cd6a6acSopenharmony_ci	avrule_list_destroy(node->avfalse_list);
4946cd6a6acSopenharmony_ci	cond_av_list_destroy(node->true_list);
4956cd6a6acSopenharmony_ci	cond_av_list_destroy(node->false_list);
4966cd6a6acSopenharmony_ci}
4976cd6a6acSopenharmony_ci
4986cd6a6acSopenharmony_civoid cond_list_destroy(cond_list_t * list)
4996cd6a6acSopenharmony_ci{
5006cd6a6acSopenharmony_ci	cond_node_t *next, *cur;
5016cd6a6acSopenharmony_ci
5026cd6a6acSopenharmony_ci	if (list == NULL)
5036cd6a6acSopenharmony_ci		return;
5046cd6a6acSopenharmony_ci
5056cd6a6acSopenharmony_ci	for (cur = list; cur != NULL; cur = next) {
5066cd6a6acSopenharmony_ci		next = cur->next;
5076cd6a6acSopenharmony_ci		cond_node_destroy(cur);
5086cd6a6acSopenharmony_ci		free(cur);
5096cd6a6acSopenharmony_ci	}
5106cd6a6acSopenharmony_ci}
5116cd6a6acSopenharmony_ci
5126cd6a6acSopenharmony_civoid cond_policydb_destroy(policydb_t * p)
5136cd6a6acSopenharmony_ci{
5146cd6a6acSopenharmony_ci	if (p->bool_val_to_struct != NULL)
5156cd6a6acSopenharmony_ci		free(p->bool_val_to_struct);
5166cd6a6acSopenharmony_ci	avtab_destroy(&p->te_cond_avtab);
5176cd6a6acSopenharmony_ci	cond_list_destroy(p->cond_list);
5186cd6a6acSopenharmony_ci}
5196cd6a6acSopenharmony_ci
5206cd6a6acSopenharmony_ciint cond_init_bool_indexes(policydb_t * p)
5216cd6a6acSopenharmony_ci{
5226cd6a6acSopenharmony_ci	if (p->bool_val_to_struct)
5236cd6a6acSopenharmony_ci		free(p->bool_val_to_struct);
5246cd6a6acSopenharmony_ci	p->bool_val_to_struct = (cond_bool_datum_t **)
5256cd6a6acSopenharmony_ci	    calloc(p->p_bools.nprim, sizeof(cond_bool_datum_t *));
5266cd6a6acSopenharmony_ci	if (!p->bool_val_to_struct)
5276cd6a6acSopenharmony_ci		return -1;
5286cd6a6acSopenharmony_ci	return 0;
5296cd6a6acSopenharmony_ci}
5306cd6a6acSopenharmony_ci
5316cd6a6acSopenharmony_ciint cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p
5326cd6a6acSopenharmony_ci		      __attribute__ ((unused)))
5336cd6a6acSopenharmony_ci{
5346cd6a6acSopenharmony_ci	if (key)
5356cd6a6acSopenharmony_ci		free(key);
5366cd6a6acSopenharmony_ci	free(datum);
5376cd6a6acSopenharmony_ci	return 0;
5386cd6a6acSopenharmony_ci}
5396cd6a6acSopenharmony_ci
5406cd6a6acSopenharmony_ciint cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap)
5416cd6a6acSopenharmony_ci{
5426cd6a6acSopenharmony_ci	policydb_t *p;
5436cd6a6acSopenharmony_ci	cond_bool_datum_t *booldatum;
5446cd6a6acSopenharmony_ci
5456cd6a6acSopenharmony_ci	booldatum = datum;
5466cd6a6acSopenharmony_ci	p = datap;
5476cd6a6acSopenharmony_ci
5486cd6a6acSopenharmony_ci	if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim)
5496cd6a6acSopenharmony_ci		return -EINVAL;
5506cd6a6acSopenharmony_ci
5516cd6a6acSopenharmony_ci	if (p->p_bool_val_to_name[booldatum->s.value - 1] != NULL)
5526cd6a6acSopenharmony_ci		return -EINVAL;
5536cd6a6acSopenharmony_ci
5546cd6a6acSopenharmony_ci	p->p_bool_val_to_name[booldatum->s.value - 1] = key;
5556cd6a6acSopenharmony_ci	p->bool_val_to_struct[booldatum->s.value - 1] = booldatum;
5566cd6a6acSopenharmony_ci
5576cd6a6acSopenharmony_ci	return 0;
5586cd6a6acSopenharmony_ci}
5596cd6a6acSopenharmony_ci
5606cd6a6acSopenharmony_cistatic int bool_isvalid(cond_bool_datum_t * b)
5616cd6a6acSopenharmony_ci{
5626cd6a6acSopenharmony_ci	if (!(b->state == 0 || b->state == 1))
5636cd6a6acSopenharmony_ci		return 0;
5646cd6a6acSopenharmony_ci	return 1;
5656cd6a6acSopenharmony_ci}
5666cd6a6acSopenharmony_ci
5676cd6a6acSopenharmony_ciint cond_read_bool(policydb_t * p,
5686cd6a6acSopenharmony_ci		   hashtab_t h,
5696cd6a6acSopenharmony_ci		   struct policy_file *fp)
5706cd6a6acSopenharmony_ci{
5716cd6a6acSopenharmony_ci	char *key = 0;
5726cd6a6acSopenharmony_ci	cond_bool_datum_t *booldatum;
5736cd6a6acSopenharmony_ci	uint32_t buf[3], len;
5746cd6a6acSopenharmony_ci	int rc;
5756cd6a6acSopenharmony_ci
5766cd6a6acSopenharmony_ci	booldatum = malloc(sizeof(cond_bool_datum_t));
5776cd6a6acSopenharmony_ci	if (!booldatum)
5786cd6a6acSopenharmony_ci		return -1;
5796cd6a6acSopenharmony_ci	memset(booldatum, 0, sizeof(cond_bool_datum_t));
5806cd6a6acSopenharmony_ci
5816cd6a6acSopenharmony_ci	rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
5826cd6a6acSopenharmony_ci	if (rc < 0)
5836cd6a6acSopenharmony_ci		goto err;
5846cd6a6acSopenharmony_ci
5856cd6a6acSopenharmony_ci	booldatum->s.value = le32_to_cpu(buf[0]);
5866cd6a6acSopenharmony_ci	booldatum->state = le32_to_cpu(buf[1]);
5876cd6a6acSopenharmony_ci
5886cd6a6acSopenharmony_ci	if (!bool_isvalid(booldatum))
5896cd6a6acSopenharmony_ci		goto err;
5906cd6a6acSopenharmony_ci
5916cd6a6acSopenharmony_ci	len = le32_to_cpu(buf[2]);
5926cd6a6acSopenharmony_ci	if (str_read(&key, fp, len))
5936cd6a6acSopenharmony_ci		goto err;
5946cd6a6acSopenharmony_ci
5956cd6a6acSopenharmony_ci	if (p->policy_type != POLICY_KERN &&
5966cd6a6acSopenharmony_ci	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
5976cd6a6acSopenharmony_ci		rc = next_entry(buf, fp, sizeof(uint32_t));
5986cd6a6acSopenharmony_ci		if (rc < 0)
5996cd6a6acSopenharmony_ci			goto err;
6006cd6a6acSopenharmony_ci		booldatum->flags = le32_to_cpu(buf[0]);
6016cd6a6acSopenharmony_ci	}
6026cd6a6acSopenharmony_ci
6036cd6a6acSopenharmony_ci	if (hashtab_insert(h, key, booldatum))
6046cd6a6acSopenharmony_ci		goto err;
6056cd6a6acSopenharmony_ci
6066cd6a6acSopenharmony_ci	return 0;
6076cd6a6acSopenharmony_ci      err:
6086cd6a6acSopenharmony_ci	cond_destroy_bool(key, booldatum, 0);
6096cd6a6acSopenharmony_ci	return -1;
6106cd6a6acSopenharmony_ci}
6116cd6a6acSopenharmony_ci
6126cd6a6acSopenharmony_cistruct cond_insertf_data {
6136cd6a6acSopenharmony_ci	struct policydb *p;
6146cd6a6acSopenharmony_ci	cond_av_list_t *other;
6156cd6a6acSopenharmony_ci	cond_av_list_t *head;
6166cd6a6acSopenharmony_ci	cond_av_list_t *tail;
6176cd6a6acSopenharmony_ci};
6186cd6a6acSopenharmony_ci
6196cd6a6acSopenharmony_cistatic int cond_insertf(avtab_t * a
6206cd6a6acSopenharmony_ci			__attribute__ ((unused)), avtab_key_t * k,
6216cd6a6acSopenharmony_ci			avtab_datum_t * d, void *ptr)
6226cd6a6acSopenharmony_ci{
6236cd6a6acSopenharmony_ci	struct cond_insertf_data *data = ptr;
6246cd6a6acSopenharmony_ci	struct policydb *p = data->p;
6256cd6a6acSopenharmony_ci	cond_av_list_t *other = data->other, *list, *cur;
6266cd6a6acSopenharmony_ci	avtab_ptr_t node_ptr;
6276cd6a6acSopenharmony_ci	uint8_t found;
6286cd6a6acSopenharmony_ci
6296cd6a6acSopenharmony_ci	/*
6306cd6a6acSopenharmony_ci	 * For type rules we have to make certain there aren't any
6316cd6a6acSopenharmony_ci	 * conflicting rules by searching the te_avtab and the
6326cd6a6acSopenharmony_ci	 * cond_te_avtab.
6336cd6a6acSopenharmony_ci	 */
6346cd6a6acSopenharmony_ci	if (k->specified & AVTAB_TYPE) {
6356cd6a6acSopenharmony_ci		if (avtab_search(&p->te_avtab, k)) {
6366cd6a6acSopenharmony_ci			WARN(NULL, "security: type rule already exists outside of a conditional.");
6376cd6a6acSopenharmony_ci			return -1;
6386cd6a6acSopenharmony_ci		}
6396cd6a6acSopenharmony_ci		/*
6406cd6a6acSopenharmony_ci		 * If we are reading the false list other will be a pointer to
6416cd6a6acSopenharmony_ci		 * the true list. We can have duplicate entries if there is only
6426cd6a6acSopenharmony_ci		 * 1 other entry and it is in our true list.
6436cd6a6acSopenharmony_ci		 *
6446cd6a6acSopenharmony_ci		 * If we are reading the true list (other == NULL) there shouldn't
6456cd6a6acSopenharmony_ci		 * be any other entries.
6466cd6a6acSopenharmony_ci		 */
6476cd6a6acSopenharmony_ci		if (other) {
6486cd6a6acSopenharmony_ci			node_ptr = avtab_search_node(&p->te_cond_avtab, k);
6496cd6a6acSopenharmony_ci			if (node_ptr) {
6506cd6a6acSopenharmony_ci				if (avtab_search_node_next
6516cd6a6acSopenharmony_ci				    (node_ptr, k->specified)) {
6526cd6a6acSopenharmony_ci					ERR(NULL, "security: too many conflicting type rules.");
6536cd6a6acSopenharmony_ci					return -1;
6546cd6a6acSopenharmony_ci				}
6556cd6a6acSopenharmony_ci				found = 0;
6566cd6a6acSopenharmony_ci				for (cur = other; cur != NULL; cur = cur->next) {
6576cd6a6acSopenharmony_ci					if (cur->node == node_ptr) {
6586cd6a6acSopenharmony_ci						found = 1;
6596cd6a6acSopenharmony_ci						break;
6606cd6a6acSopenharmony_ci					}
6616cd6a6acSopenharmony_ci				}
6626cd6a6acSopenharmony_ci				if (!found) {
6636cd6a6acSopenharmony_ci					ERR(NULL, "security: conflicting type rules.");
6646cd6a6acSopenharmony_ci					return -1;
6656cd6a6acSopenharmony_ci				}
6666cd6a6acSopenharmony_ci			}
6676cd6a6acSopenharmony_ci		} else {
6686cd6a6acSopenharmony_ci			if (avtab_search(&p->te_cond_avtab, k)) {
6696cd6a6acSopenharmony_ci				ERR(NULL, "security: conflicting type rules when adding type rule for true.");
6706cd6a6acSopenharmony_ci				return -1;
6716cd6a6acSopenharmony_ci			}
6726cd6a6acSopenharmony_ci		}
6736cd6a6acSopenharmony_ci	}
6746cd6a6acSopenharmony_ci
6756cd6a6acSopenharmony_ci	node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
6766cd6a6acSopenharmony_ci	if (!node_ptr) {
6776cd6a6acSopenharmony_ci		ERR(NULL, "security: could not insert rule.");
6786cd6a6acSopenharmony_ci		return -1;
6796cd6a6acSopenharmony_ci	}
6806cd6a6acSopenharmony_ci	node_ptr->parse_context = (void *)1;
6816cd6a6acSopenharmony_ci
6826cd6a6acSopenharmony_ci	list = malloc(sizeof(cond_av_list_t));
6836cd6a6acSopenharmony_ci	if (!list)
6846cd6a6acSopenharmony_ci		return -1;
6856cd6a6acSopenharmony_ci	memset(list, 0, sizeof(cond_av_list_t));
6866cd6a6acSopenharmony_ci
6876cd6a6acSopenharmony_ci	list->node = node_ptr;
6886cd6a6acSopenharmony_ci	if (!data->head)
6896cd6a6acSopenharmony_ci		data->head = list;
6906cd6a6acSopenharmony_ci	else
6916cd6a6acSopenharmony_ci		data->tail->next = list;
6926cd6a6acSopenharmony_ci	data->tail = list;
6936cd6a6acSopenharmony_ci	return 0;
6946cd6a6acSopenharmony_ci}
6956cd6a6acSopenharmony_ci
6966cd6a6acSopenharmony_cistatic int cond_read_av_list(policydb_t * p, void *fp,
6976cd6a6acSopenharmony_ci			     cond_av_list_t ** ret_list, cond_av_list_t * other)
6986cd6a6acSopenharmony_ci{
6996cd6a6acSopenharmony_ci	unsigned int i;
7006cd6a6acSopenharmony_ci	int rc;
7016cd6a6acSopenharmony_ci	uint32_t buf[1], len;
7026cd6a6acSopenharmony_ci	struct cond_insertf_data data;
7036cd6a6acSopenharmony_ci
7046cd6a6acSopenharmony_ci	*ret_list = NULL;
7056cd6a6acSopenharmony_ci
7066cd6a6acSopenharmony_ci	rc = next_entry(buf, fp, sizeof(uint32_t));
7076cd6a6acSopenharmony_ci	if (rc < 0)
7086cd6a6acSopenharmony_ci		return -1;
7096cd6a6acSopenharmony_ci
7106cd6a6acSopenharmony_ci	len = le32_to_cpu(buf[0]);
7116cd6a6acSopenharmony_ci	if (len == 0) {
7126cd6a6acSopenharmony_ci		return 0;
7136cd6a6acSopenharmony_ci	}
7146cd6a6acSopenharmony_ci
7156cd6a6acSopenharmony_ci	data.p = p;
7166cd6a6acSopenharmony_ci	data.other = other;
7176cd6a6acSopenharmony_ci	data.head = NULL;
7186cd6a6acSopenharmony_ci	data.tail = NULL;
7196cd6a6acSopenharmony_ci	for (i = 0; i < len; i++) {
7206cd6a6acSopenharmony_ci		rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab,
7216cd6a6acSopenharmony_ci				     cond_insertf, &data);
7226cd6a6acSopenharmony_ci		if (rc) {
7236cd6a6acSopenharmony_ci			cond_av_list_destroy(data.head);
7246cd6a6acSopenharmony_ci			return rc;
7256cd6a6acSopenharmony_ci		}
7266cd6a6acSopenharmony_ci
7276cd6a6acSopenharmony_ci	}
7286cd6a6acSopenharmony_ci
7296cd6a6acSopenharmony_ci	*ret_list = data.head;
7306cd6a6acSopenharmony_ci	return 0;
7316cd6a6acSopenharmony_ci}
7326cd6a6acSopenharmony_ci
7336cd6a6acSopenharmony_cistatic int expr_isvalid(policydb_t * p, cond_expr_t * expr)
7346cd6a6acSopenharmony_ci{
7356cd6a6acSopenharmony_ci	if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
7366cd6a6acSopenharmony_ci		WARN(NULL, "security: conditional expressions uses unknown operator.");
7376cd6a6acSopenharmony_ci		return 0;
7386cd6a6acSopenharmony_ci	}
7396cd6a6acSopenharmony_ci
7406cd6a6acSopenharmony_ci	if (expr->bool > p->p_bools.nprim) {
7416cd6a6acSopenharmony_ci		WARN(NULL, "security: conditional expressions uses unknown bool.");
7426cd6a6acSopenharmony_ci		return 0;
7436cd6a6acSopenharmony_ci	}
7446cd6a6acSopenharmony_ci	return 1;
7456cd6a6acSopenharmony_ci}
7466cd6a6acSopenharmony_ci
7476cd6a6acSopenharmony_cistatic int cond_read_node(policydb_t * p, cond_node_t * node, void *fp)
7486cd6a6acSopenharmony_ci{
7496cd6a6acSopenharmony_ci	uint32_t buf[2];
7506cd6a6acSopenharmony_ci	int len, i, rc;
7516cd6a6acSopenharmony_ci	cond_expr_t *expr = NULL, *last = NULL;
7526cd6a6acSopenharmony_ci
7536cd6a6acSopenharmony_ci	rc = next_entry(buf, fp, sizeof(uint32_t));
7546cd6a6acSopenharmony_ci	if (rc < 0)
7556cd6a6acSopenharmony_ci		goto err;
7566cd6a6acSopenharmony_ci
7576cd6a6acSopenharmony_ci	node->cur_state = le32_to_cpu(buf[0]);
7586cd6a6acSopenharmony_ci
7596cd6a6acSopenharmony_ci	rc = next_entry(buf, fp, sizeof(uint32_t));
7606cd6a6acSopenharmony_ci	if (rc < 0)
7616cd6a6acSopenharmony_ci		goto err;
7626cd6a6acSopenharmony_ci
7636cd6a6acSopenharmony_ci	/* expr */
7646cd6a6acSopenharmony_ci	len = le32_to_cpu(buf[0]);
7656cd6a6acSopenharmony_ci
7666cd6a6acSopenharmony_ci	for (i = 0; i < len; i++) {
7676cd6a6acSopenharmony_ci		rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
7686cd6a6acSopenharmony_ci		if (rc < 0)
7696cd6a6acSopenharmony_ci			goto err;
7706cd6a6acSopenharmony_ci
7716cd6a6acSopenharmony_ci		expr = malloc(sizeof(cond_expr_t));
7726cd6a6acSopenharmony_ci		if (!expr) {
7736cd6a6acSopenharmony_ci			goto err;
7746cd6a6acSopenharmony_ci		}
7756cd6a6acSopenharmony_ci		memset(expr, 0, sizeof(cond_expr_t));
7766cd6a6acSopenharmony_ci
7776cd6a6acSopenharmony_ci		expr->expr_type = le32_to_cpu(buf[0]);
7786cd6a6acSopenharmony_ci		expr->bool = le32_to_cpu(buf[1]);
7796cd6a6acSopenharmony_ci
7806cd6a6acSopenharmony_ci		if (!expr_isvalid(p, expr)) {
7816cd6a6acSopenharmony_ci			free(expr);
7826cd6a6acSopenharmony_ci			goto err;
7836cd6a6acSopenharmony_ci		}
7846cd6a6acSopenharmony_ci
7856cd6a6acSopenharmony_ci		if (i == 0) {
7866cd6a6acSopenharmony_ci			node->expr = expr;
7876cd6a6acSopenharmony_ci		} else {
7886cd6a6acSopenharmony_ci			last->next = expr;
7896cd6a6acSopenharmony_ci		}
7906cd6a6acSopenharmony_ci		last = expr;
7916cd6a6acSopenharmony_ci	}
7926cd6a6acSopenharmony_ci
7936cd6a6acSopenharmony_ci	if (p->policy_type == POLICY_KERN) {
7946cd6a6acSopenharmony_ci		if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0)
7956cd6a6acSopenharmony_ci			goto err;
7966cd6a6acSopenharmony_ci		if (cond_read_av_list(p, fp, &node->false_list, node->true_list)
7976cd6a6acSopenharmony_ci		    != 0)
7986cd6a6acSopenharmony_ci			goto err;
7996cd6a6acSopenharmony_ci	} else {
8006cd6a6acSopenharmony_ci		if (avrule_read_list(p, &node->avtrue_list, fp))
8016cd6a6acSopenharmony_ci			goto err;
8026cd6a6acSopenharmony_ci		if (avrule_read_list(p, &node->avfalse_list, fp))
8036cd6a6acSopenharmony_ci			goto err;
8046cd6a6acSopenharmony_ci	}
8056cd6a6acSopenharmony_ci
8066cd6a6acSopenharmony_ci	if (p->policy_type != POLICY_KERN &&
8076cd6a6acSopenharmony_ci	    p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) {
8086cd6a6acSopenharmony_ci		rc = next_entry(buf, fp, sizeof(uint32_t));
8096cd6a6acSopenharmony_ci		if (rc < 0)
8106cd6a6acSopenharmony_ci			goto err;
8116cd6a6acSopenharmony_ci		node->flags = le32_to_cpu(buf[0]);
8126cd6a6acSopenharmony_ci	}
8136cd6a6acSopenharmony_ci
8146cd6a6acSopenharmony_ci	return 0;
8156cd6a6acSopenharmony_ci      err:
8166cd6a6acSopenharmony_ci	cond_node_destroy(node);
8176cd6a6acSopenharmony_ci	free(node);
8186cd6a6acSopenharmony_ci	return -1;
8196cd6a6acSopenharmony_ci}
8206cd6a6acSopenharmony_ci
8216cd6a6acSopenharmony_ciint cond_read_list(policydb_t * p, cond_list_t ** list, void *fp)
8226cd6a6acSopenharmony_ci{
8236cd6a6acSopenharmony_ci	cond_node_t *node, *last = NULL;
8246cd6a6acSopenharmony_ci	uint32_t buf[1];
8256cd6a6acSopenharmony_ci	int i, len, rc;
8266cd6a6acSopenharmony_ci
8276cd6a6acSopenharmony_ci	rc = next_entry(buf, fp, sizeof(uint32_t));
8286cd6a6acSopenharmony_ci	if (rc < 0)
8296cd6a6acSopenharmony_ci		return -1;
8306cd6a6acSopenharmony_ci
8316cd6a6acSopenharmony_ci	len = le32_to_cpu(buf[0]);
8326cd6a6acSopenharmony_ci
8336cd6a6acSopenharmony_ci	rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel);
8346cd6a6acSopenharmony_ci	if (rc)
8356cd6a6acSopenharmony_ci		goto err;
8366cd6a6acSopenharmony_ci
8376cd6a6acSopenharmony_ci	for (i = 0; i < len; i++) {
8386cd6a6acSopenharmony_ci		node = malloc(sizeof(cond_node_t));
8396cd6a6acSopenharmony_ci		if (!node)
8406cd6a6acSopenharmony_ci			goto err;
8416cd6a6acSopenharmony_ci		memset(node, 0, sizeof(cond_node_t));
8426cd6a6acSopenharmony_ci
8436cd6a6acSopenharmony_ci		if (cond_read_node(p, node, fp) != 0)
8446cd6a6acSopenharmony_ci			goto err;
8456cd6a6acSopenharmony_ci
8466cd6a6acSopenharmony_ci		if (i == 0) {
8476cd6a6acSopenharmony_ci			*list = node;
8486cd6a6acSopenharmony_ci		} else {
8496cd6a6acSopenharmony_ci			last->next = node;
8506cd6a6acSopenharmony_ci		}
8516cd6a6acSopenharmony_ci		last = node;
8526cd6a6acSopenharmony_ci	}
8536cd6a6acSopenharmony_ci	return 0;
8546cd6a6acSopenharmony_ci      err:
8556cd6a6acSopenharmony_ci	return -1;
8566cd6a6acSopenharmony_ci}
8576cd6a6acSopenharmony_ci
8586cd6a6acSopenharmony_ci/* Determine whether additional permissions are granted by the conditional
8596cd6a6acSopenharmony_ci * av table, and if so, add them to the result
8606cd6a6acSopenharmony_ci */
8616cd6a6acSopenharmony_civoid cond_compute_av(avtab_t * ctab, avtab_key_t * key,
8626cd6a6acSopenharmony_ci		     struct sepol_av_decision *avd)
8636cd6a6acSopenharmony_ci{
8646cd6a6acSopenharmony_ci	avtab_ptr_t node;
8656cd6a6acSopenharmony_ci
8666cd6a6acSopenharmony_ci	if (!ctab || !key || !avd)
8676cd6a6acSopenharmony_ci		return;
8686cd6a6acSopenharmony_ci
8696cd6a6acSopenharmony_ci	for (node = avtab_search_node(ctab, key); node != NULL;
8706cd6a6acSopenharmony_ci	     node = avtab_search_node_next(node, key->specified)) {
8716cd6a6acSopenharmony_ci		if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) ==
8726cd6a6acSopenharmony_ci		    (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
8736cd6a6acSopenharmony_ci			avd->allowed |= node->datum.data;
8746cd6a6acSopenharmony_ci		if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) ==
8756cd6a6acSopenharmony_ci		    (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
8766cd6a6acSopenharmony_ci			/* Since a '0' in an auditdeny mask represents a
8776cd6a6acSopenharmony_ci			 * permission we do NOT want to audit (dontaudit), we use
8786cd6a6acSopenharmony_ci			 * the '&' operand to ensure that all '0's in the mask
8796cd6a6acSopenharmony_ci			 * are retained (much unlike the allow and auditallow cases).
8806cd6a6acSopenharmony_ci			 */
8816cd6a6acSopenharmony_ci			avd->auditdeny &= node->datum.data;
8826cd6a6acSopenharmony_ci		if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
8836cd6a6acSopenharmony_ci		    (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
8846cd6a6acSopenharmony_ci			avd->auditallow |= node->datum.data;
8856cd6a6acSopenharmony_ci	}
8866cd6a6acSopenharmony_ci	return;
8876cd6a6acSopenharmony_ci}
8886cd6a6acSopenharmony_ci
8896cd6a6acSopenharmony_ciavtab_datum_t *cond_av_list_search(avtab_key_t * key,
8906cd6a6acSopenharmony_ci				   cond_av_list_t * cond_list)
8916cd6a6acSopenharmony_ci{
8926cd6a6acSopenharmony_ci
8936cd6a6acSopenharmony_ci	cond_av_list_t *cur_av;
8946cd6a6acSopenharmony_ci
8956cd6a6acSopenharmony_ci	for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) {
8966cd6a6acSopenharmony_ci
8976cd6a6acSopenharmony_ci		if (cur_av->node->key.source_type == key->source_type &&
8986cd6a6acSopenharmony_ci		    cur_av->node->key.target_type == key->target_type &&
8996cd6a6acSopenharmony_ci		    cur_av->node->key.target_class == key->target_class)
9006cd6a6acSopenharmony_ci
9016cd6a6acSopenharmony_ci			return &cur_av->node->datum;
9026cd6a6acSopenharmony_ci
9036cd6a6acSopenharmony_ci	}
9046cd6a6acSopenharmony_ci	return NULL;
9056cd6a6acSopenharmony_ci
9066cd6a6acSopenharmony_ci}
907