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