16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * Author: Ondrej Mosnacek <omosnacek@gmail.com> 36cd6a6acSopenharmony_ci * 46cd6a6acSopenharmony_ci * Copyright (C) 2019 Red Hat Inc. 56cd6a6acSopenharmony_ci * 66cd6a6acSopenharmony_ci * This library is free software; you can redistribute it and/or 76cd6a6acSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 86cd6a6acSopenharmony_ci * License as published by the Free Software Foundation; either 96cd6a6acSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 106cd6a6acSopenharmony_ci * 116cd6a6acSopenharmony_ci * This library is distributed in the hope that it will be useful, 126cd6a6acSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 136cd6a6acSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 146cd6a6acSopenharmony_ci * Lesser General Public License for more details. 156cd6a6acSopenharmony_ci * 166cd6a6acSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 176cd6a6acSopenharmony_ci * License along with this library; if not, write to the Free Software 186cd6a6acSopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 196cd6a6acSopenharmony_ci */ 206cd6a6acSopenharmony_ci 216cd6a6acSopenharmony_ci/* 226cd6a6acSopenharmony_ci * Binary policy optimization. 236cd6a6acSopenharmony_ci * 246cd6a6acSopenharmony_ci * Defines the policydb_optimize() function, which finds and removes 256cd6a6acSopenharmony_ci * redundant rules from the binary policy to reduce its size and potentially 266cd6a6acSopenharmony_ci * improve rule matching times. Only rules that are already covered by a 276cd6a6acSopenharmony_ci * more general rule are removed. The resulting policy is functionally 286cd6a6acSopenharmony_ci * equivalent to the original one. 296cd6a6acSopenharmony_ci */ 306cd6a6acSopenharmony_ci 316cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h> 326cd6a6acSopenharmony_ci#include <sepol/policydb/conditional.h> 336cd6a6acSopenharmony_ci 346cd6a6acSopenharmony_ci#include "debug.h" 356cd6a6acSopenharmony_ci#include "private.h" 366cd6a6acSopenharmony_ci 376cd6a6acSopenharmony_ci#define TYPE_VEC_INIT_SIZE 16 386cd6a6acSopenharmony_ci 396cd6a6acSopenharmony_cistruct type_vec { 406cd6a6acSopenharmony_ci uint32_t *types; 416cd6a6acSopenharmony_ci unsigned int count, capacity; 426cd6a6acSopenharmony_ci}; 436cd6a6acSopenharmony_ci 446cd6a6acSopenharmony_cistatic int type_vec_init(struct type_vec *v) 456cd6a6acSopenharmony_ci{ 466cd6a6acSopenharmony_ci v->capacity = TYPE_VEC_INIT_SIZE; 476cd6a6acSopenharmony_ci v->count = 0; 486cd6a6acSopenharmony_ci v->types = calloc(v->capacity, sizeof(*v->types)); 496cd6a6acSopenharmony_ci if (!v->types) 506cd6a6acSopenharmony_ci return -1; 516cd6a6acSopenharmony_ci return 0; 526cd6a6acSopenharmony_ci} 536cd6a6acSopenharmony_ci 546cd6a6acSopenharmony_cistatic void type_vec_destroy(struct type_vec *v) 556cd6a6acSopenharmony_ci{ 566cd6a6acSopenharmony_ci free(v->types); 576cd6a6acSopenharmony_ci} 586cd6a6acSopenharmony_ci 596cd6a6acSopenharmony_cistatic int type_vec_append(struct type_vec *v, uint32_t type) 606cd6a6acSopenharmony_ci{ 616cd6a6acSopenharmony_ci if (v->capacity == v->count) { 626cd6a6acSopenharmony_ci unsigned int new_capacity = v->capacity * 2; 636cd6a6acSopenharmony_ci uint32_t *new_types = reallocarray(v->types, 646cd6a6acSopenharmony_ci new_capacity, 656cd6a6acSopenharmony_ci sizeof(*v->types)); 666cd6a6acSopenharmony_ci if (!new_types) 676cd6a6acSopenharmony_ci return -1; 686cd6a6acSopenharmony_ci 696cd6a6acSopenharmony_ci v->types = new_types; 706cd6a6acSopenharmony_ci v->capacity = new_capacity; 716cd6a6acSopenharmony_ci } 726cd6a6acSopenharmony_ci 736cd6a6acSopenharmony_ci v->types[v->count++] = type; 746cd6a6acSopenharmony_ci return 0; 756cd6a6acSopenharmony_ci} 766cd6a6acSopenharmony_ci 776cd6a6acSopenharmony_cistatic int type_vec_contains(const struct type_vec *v, uint32_t type) 786cd6a6acSopenharmony_ci{ 796cd6a6acSopenharmony_ci unsigned int s = 0, e = v->count; 806cd6a6acSopenharmony_ci 816cd6a6acSopenharmony_ci while (s != e) { 826cd6a6acSopenharmony_ci unsigned int mid = (s + e) / 2; 836cd6a6acSopenharmony_ci 846cd6a6acSopenharmony_ci if (v->types[mid] == type) 856cd6a6acSopenharmony_ci return 1; 866cd6a6acSopenharmony_ci 876cd6a6acSopenharmony_ci if (v->types[mid] < type) 886cd6a6acSopenharmony_ci s = mid + 1; 896cd6a6acSopenharmony_ci else 906cd6a6acSopenharmony_ci e = mid; 916cd6a6acSopenharmony_ci } 926cd6a6acSopenharmony_ci return 0; 936cd6a6acSopenharmony_ci} 946cd6a6acSopenharmony_ci 956cd6a6acSopenharmony_ci/* builds map: type/attribute -> {all attributes that are a superset of it} */ 966cd6a6acSopenharmony_cistatic struct type_vec *build_type_map(const policydb_t *p) 976cd6a6acSopenharmony_ci{ 986cd6a6acSopenharmony_ci unsigned int i, k; 996cd6a6acSopenharmony_ci ebitmap_node_t *n; 1006cd6a6acSopenharmony_ci struct type_vec *map = calloc(p->p_types.nprim, sizeof(*map)); 1016cd6a6acSopenharmony_ci if (!map) 1026cd6a6acSopenharmony_ci return NULL; 1036cd6a6acSopenharmony_ci 1046cd6a6acSopenharmony_ci for (i = 0; i < p->p_types.nprim; i++) { 1056cd6a6acSopenharmony_ci if (type_vec_init(&map[i])) 1066cd6a6acSopenharmony_ci goto err; 1076cd6a6acSopenharmony_ci 1086cd6a6acSopenharmony_ci if (!p->type_val_to_struct[i]) 1096cd6a6acSopenharmony_ci continue; 1106cd6a6acSopenharmony_ci 1116cd6a6acSopenharmony_ci if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) { 1126cd6a6acSopenharmony_ci ebitmap_for_each_positive_bit(&p->type_attr_map[i], 1136cd6a6acSopenharmony_ci n, k) { 1146cd6a6acSopenharmony_ci if (type_vec_append(&map[i], k)) 1156cd6a6acSopenharmony_ci goto err; 1166cd6a6acSopenharmony_ci } 1176cd6a6acSopenharmony_ci } else { 1186cd6a6acSopenharmony_ci ebitmap_t *types_i = &p->attr_type_map[i]; 1196cd6a6acSopenharmony_ci 1206cd6a6acSopenharmony_ci for (k = 0; k < p->p_types.nprim; k++) { 1216cd6a6acSopenharmony_ci const ebitmap_t *types_k; 1226cd6a6acSopenharmony_ci 1236cd6a6acSopenharmony_ci if (!p->type_val_to_struct[k] || p->type_val_to_struct[k]->flavor != TYPE_ATTRIB) 1246cd6a6acSopenharmony_ci continue; 1256cd6a6acSopenharmony_ci 1266cd6a6acSopenharmony_ci types_k = &p->attr_type_map[k]; 1276cd6a6acSopenharmony_ci 1286cd6a6acSopenharmony_ci if (ebitmap_contains(types_k, types_i)) { 1296cd6a6acSopenharmony_ci if (type_vec_append(&map[i], k)) 1306cd6a6acSopenharmony_ci goto err; 1316cd6a6acSopenharmony_ci } 1326cd6a6acSopenharmony_ci } 1336cd6a6acSopenharmony_ci } 1346cd6a6acSopenharmony_ci } 1356cd6a6acSopenharmony_ci return map; 1366cd6a6acSopenharmony_cierr: 1376cd6a6acSopenharmony_ci for (k = 0; k <= i; k++) 1386cd6a6acSopenharmony_ci type_vec_destroy(&map[k]); 1396cd6a6acSopenharmony_ci free(map); 1406cd6a6acSopenharmony_ci return NULL; 1416cd6a6acSopenharmony_ci} 1426cd6a6acSopenharmony_ci 1436cd6a6acSopenharmony_cistatic void destroy_type_map(const policydb_t *p, struct type_vec *type_map) 1446cd6a6acSopenharmony_ci{ 1456cd6a6acSopenharmony_ci unsigned int i; 1466cd6a6acSopenharmony_ci for (i = 0; i < p->p_types.nprim; i++) 1476cd6a6acSopenharmony_ci type_vec_destroy(&type_map[i]); 1486cd6a6acSopenharmony_ci free(type_map); 1496cd6a6acSopenharmony_ci} 1506cd6a6acSopenharmony_ci 1516cd6a6acSopenharmony_cistatic int process_xperms(uint32_t *p1, const uint32_t *p2) 1526cd6a6acSopenharmony_ci{ 1536cd6a6acSopenharmony_ci size_t i; 1546cd6a6acSopenharmony_ci int ret = 1; 1556cd6a6acSopenharmony_ci 1566cd6a6acSopenharmony_ci for (i = 0; i < EXTENDED_PERMS_LEN; i++) { 1576cd6a6acSopenharmony_ci p1[i] &= ~p2[i]; 1586cd6a6acSopenharmony_ci if (p1[i] != 0) 1596cd6a6acSopenharmony_ci ret = 0; 1606cd6a6acSopenharmony_ci } 1616cd6a6acSopenharmony_ci return ret; 1626cd6a6acSopenharmony_ci} 1636cd6a6acSopenharmony_ci 1646cd6a6acSopenharmony_cistatic int process_avtab_datum(uint16_t specified, 1656cd6a6acSopenharmony_ci avtab_datum_t *d1, const avtab_datum_t *d2) 1666cd6a6acSopenharmony_ci{ 1676cd6a6acSopenharmony_ci /* inverse logic needed for AUDITDENY rules */ 1686cd6a6acSopenharmony_ci if (specified & AVTAB_AUDITDENY) 1696cd6a6acSopenharmony_ci return (d1->data |= ~d2->data) == UINT32_C(0xFFFFFFFF); 1706cd6a6acSopenharmony_ci 1716cd6a6acSopenharmony_ci if (specified & AVTAB_AV) 1726cd6a6acSopenharmony_ci return (d1->data &= ~d2->data) == 0; 1736cd6a6acSopenharmony_ci 1746cd6a6acSopenharmony_ci if (specified & AVTAB_XPERMS) { 1756cd6a6acSopenharmony_ci avtab_extended_perms_t *x1 = d1->xperms; 1766cd6a6acSopenharmony_ci const avtab_extended_perms_t *x2 = d2->xperms; 1776cd6a6acSopenharmony_ci 1786cd6a6acSopenharmony_ci if (x1->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 1796cd6a6acSopenharmony_ci if (x2->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 1806cd6a6acSopenharmony_ci if (x1->driver != x2->driver) 1816cd6a6acSopenharmony_ci return 0; 1826cd6a6acSopenharmony_ci return process_xperms(x1->perms, x2->perms); 1836cd6a6acSopenharmony_ci } 1846cd6a6acSopenharmony_ci if (x2->specified == AVTAB_XPERMS_IOCTLDRIVER) 1856cd6a6acSopenharmony_ci return xperm_test(x1->driver, x2->perms); 1866cd6a6acSopenharmony_ci } else if (x1->specified == AVTAB_XPERMS_IOCTLDRIVER) { 1876cd6a6acSopenharmony_ci if (x2->specified == AVTAB_XPERMS_IOCTLFUNCTION) 1886cd6a6acSopenharmony_ci return 0; 1896cd6a6acSopenharmony_ci 1906cd6a6acSopenharmony_ci if (x2->specified == AVTAB_XPERMS_IOCTLDRIVER) 1916cd6a6acSopenharmony_ci return process_xperms(x1->perms, x2->perms); 1926cd6a6acSopenharmony_ci } 1936cd6a6acSopenharmony_ci return 0; 1946cd6a6acSopenharmony_ci } 1956cd6a6acSopenharmony_ci return 0; 1966cd6a6acSopenharmony_ci} 1976cd6a6acSopenharmony_ci 1986cd6a6acSopenharmony_ci/* checks if avtab contains a rule that covers the given rule */ 1996cd6a6acSopenharmony_cistatic int is_avrule_redundant(avtab_ptr_t entry, avtab_t *tab, 2006cd6a6acSopenharmony_ci const struct type_vec *type_map, 2016cd6a6acSopenharmony_ci unsigned char not_cond) 2026cd6a6acSopenharmony_ci{ 2036cd6a6acSopenharmony_ci unsigned int i, k, s_idx, t_idx; 2046cd6a6acSopenharmony_ci uint32_t st, tt; 2056cd6a6acSopenharmony_ci avtab_datum_t *d1, *d2; 2066cd6a6acSopenharmony_ci avtab_key_t key; 2076cd6a6acSopenharmony_ci 2086cd6a6acSopenharmony_ci /* we only care about AV rules */ 2096cd6a6acSopenharmony_ci if (!(entry->key.specified & (AVTAB_AV|AVTAB_XPERMS))) 2106cd6a6acSopenharmony_ci return 0; 2116cd6a6acSopenharmony_ci 2126cd6a6acSopenharmony_ci s_idx = entry->key.source_type - 1; 2136cd6a6acSopenharmony_ci t_idx = entry->key.target_type - 1; 2146cd6a6acSopenharmony_ci 2156cd6a6acSopenharmony_ci key.target_class = entry->key.target_class; 2166cd6a6acSopenharmony_ci key.specified = entry->key.specified; 2176cd6a6acSopenharmony_ci 2186cd6a6acSopenharmony_ci d1 = &entry->datum; 2196cd6a6acSopenharmony_ci 2206cd6a6acSopenharmony_ci for (i = 0; i < type_map[s_idx].count; i++) { 2216cd6a6acSopenharmony_ci st = type_map[s_idx].types[i]; 2226cd6a6acSopenharmony_ci key.source_type = st + 1; 2236cd6a6acSopenharmony_ci 2246cd6a6acSopenharmony_ci for (k = 0; k < type_map[t_idx].count; k++) { 2256cd6a6acSopenharmony_ci tt = type_map[t_idx].types[k]; 2266cd6a6acSopenharmony_ci 2276cd6a6acSopenharmony_ci if (not_cond && s_idx == st && t_idx == tt) 2286cd6a6acSopenharmony_ci continue; 2296cd6a6acSopenharmony_ci 2306cd6a6acSopenharmony_ci key.target_type = tt + 1; 2316cd6a6acSopenharmony_ci 2326cd6a6acSopenharmony_ci d2 = avtab_search(tab, &key); 2336cd6a6acSopenharmony_ci if (!d2) 2346cd6a6acSopenharmony_ci continue; 2356cd6a6acSopenharmony_ci 2366cd6a6acSopenharmony_ci if (process_avtab_datum(key.specified, d1, d2)) 2376cd6a6acSopenharmony_ci return 1; 2386cd6a6acSopenharmony_ci } 2396cd6a6acSopenharmony_ci } 2406cd6a6acSopenharmony_ci return 0; 2416cd6a6acSopenharmony_ci} 2426cd6a6acSopenharmony_ci 2436cd6a6acSopenharmony_cistatic int is_type_attr(policydb_t *p, unsigned int id) 2446cd6a6acSopenharmony_ci{ 2456cd6a6acSopenharmony_ci return p->type_val_to_struct[id]->flavor == TYPE_ATTRIB; 2466cd6a6acSopenharmony_ci} 2476cd6a6acSopenharmony_ci 2486cd6a6acSopenharmony_cistatic int is_avrule_with_attr(avtab_ptr_t entry, policydb_t *p) 2496cd6a6acSopenharmony_ci{ 2506cd6a6acSopenharmony_ci unsigned int s_idx = entry->key.source_type - 1; 2516cd6a6acSopenharmony_ci unsigned int t_idx = entry->key.target_type - 1; 2526cd6a6acSopenharmony_ci 2536cd6a6acSopenharmony_ci return is_type_attr(p, s_idx) || is_type_attr(p, t_idx); 2546cd6a6acSopenharmony_ci} 2556cd6a6acSopenharmony_ci 2566cd6a6acSopenharmony_ci/* checks if conditional list contains a rule that covers the given rule */ 2576cd6a6acSopenharmony_cistatic int is_cond_rule_redundant(avtab_ptr_t e1, cond_av_list_t *list, 2586cd6a6acSopenharmony_ci const struct type_vec *type_map) 2596cd6a6acSopenharmony_ci{ 2606cd6a6acSopenharmony_ci unsigned int s1, t1, c1, k1, s2, t2, c2, k2; 2616cd6a6acSopenharmony_ci 2626cd6a6acSopenharmony_ci /* we only care about AV rules */ 2636cd6a6acSopenharmony_ci if (!(e1->key.specified & (AVTAB_AV|AVTAB_XPERMS))) 2646cd6a6acSopenharmony_ci return 0; 2656cd6a6acSopenharmony_ci 2666cd6a6acSopenharmony_ci s1 = e1->key.source_type - 1; 2676cd6a6acSopenharmony_ci t1 = e1->key.target_type - 1; 2686cd6a6acSopenharmony_ci c1 = e1->key.target_class; 2696cd6a6acSopenharmony_ci k1 = e1->key.specified; 2706cd6a6acSopenharmony_ci 2716cd6a6acSopenharmony_ci for (; list; list = list->next) { 2726cd6a6acSopenharmony_ci avtab_ptr_t e2 = list->node; 2736cd6a6acSopenharmony_ci 2746cd6a6acSopenharmony_ci s2 = e2->key.source_type - 1; 2756cd6a6acSopenharmony_ci t2 = e2->key.target_type - 1; 2766cd6a6acSopenharmony_ci c2 = e2->key.target_class; 2776cd6a6acSopenharmony_ci k2 = e2->key.specified; 2786cd6a6acSopenharmony_ci 2796cd6a6acSopenharmony_ci if (k1 != k2 || c1 != c2) 2806cd6a6acSopenharmony_ci continue; 2816cd6a6acSopenharmony_ci 2826cd6a6acSopenharmony_ci if (s1 == s2 && t1 == t2) 2836cd6a6acSopenharmony_ci continue; 2846cd6a6acSopenharmony_ci if (!type_vec_contains(&type_map[s1], s2)) 2856cd6a6acSopenharmony_ci continue; 2866cd6a6acSopenharmony_ci if (!type_vec_contains(&type_map[t1], t2)) 2876cd6a6acSopenharmony_ci continue; 2886cd6a6acSopenharmony_ci 2896cd6a6acSopenharmony_ci if (process_avtab_datum(k1, &e1->datum, &e2->datum)) 2906cd6a6acSopenharmony_ci return 1; 2916cd6a6acSopenharmony_ci } 2926cd6a6acSopenharmony_ci return 0; 2936cd6a6acSopenharmony_ci} 2946cd6a6acSopenharmony_ci 2956cd6a6acSopenharmony_cistatic void optimize_avtab(policydb_t *p, const struct type_vec *type_map) 2966cd6a6acSopenharmony_ci{ 2976cd6a6acSopenharmony_ci avtab_t *tab = &p->te_avtab; 2986cd6a6acSopenharmony_ci unsigned int i; 2996cd6a6acSopenharmony_ci avtab_ptr_t *cur; 3006cd6a6acSopenharmony_ci 3016cd6a6acSopenharmony_ci for (i = 0; i < tab->nslot; i++) { 3026cd6a6acSopenharmony_ci cur = &tab->htable[i]; 3036cd6a6acSopenharmony_ci while (*cur) { 3046cd6a6acSopenharmony_ci if (is_avrule_redundant(*cur, tab, type_map, 1)) { 3056cd6a6acSopenharmony_ci /* redundant rule -> remove it */ 3066cd6a6acSopenharmony_ci avtab_ptr_t tmp = *cur; 3076cd6a6acSopenharmony_ci 3086cd6a6acSopenharmony_ci *cur = tmp->next; 3096cd6a6acSopenharmony_ci if (tmp->key.specified & AVTAB_XPERMS) 3106cd6a6acSopenharmony_ci free(tmp->datum.xperms); 3116cd6a6acSopenharmony_ci free(tmp); 3126cd6a6acSopenharmony_ci 3136cd6a6acSopenharmony_ci tab->nel--; 3146cd6a6acSopenharmony_ci } else { 3156cd6a6acSopenharmony_ci /* rule not redundant -> move to next rule */ 3166cd6a6acSopenharmony_ci cur = &(*cur)->next; 3176cd6a6acSopenharmony_ci } 3186cd6a6acSopenharmony_ci } 3196cd6a6acSopenharmony_ci } 3206cd6a6acSopenharmony_ci} 3216cd6a6acSopenharmony_ci 3226cd6a6acSopenharmony_ci/* find redundant rules in (*cond) and put them into (*del) */ 3236cd6a6acSopenharmony_cistatic void optimize_cond_av_list(cond_av_list_t **cond, cond_av_list_t **del, 3246cd6a6acSopenharmony_ci policydb_t *p, const struct type_vec *type_map) 3256cd6a6acSopenharmony_ci{ 3266cd6a6acSopenharmony_ci cond_av_list_t **listp = cond; 3276cd6a6acSopenharmony_ci cond_av_list_t *pcov = NULL; 3286cd6a6acSopenharmony_ci cond_av_list_t **pcov_cur; 3296cd6a6acSopenharmony_ci 3306cd6a6acSopenharmony_ci /* 3316cd6a6acSopenharmony_ci * Separate out all "potentially covering" rules (src or tgt is an attr) 3326cd6a6acSopenharmony_ci * and move them to the end of the list. This is needed to avoid 3336cd6a6acSopenharmony_ci * polynomial complexity when almost all rules are expanded. 3346cd6a6acSopenharmony_ci */ 3356cd6a6acSopenharmony_ci while (*cond) { 3366cd6a6acSopenharmony_ci if (is_avrule_with_attr((*cond)->node, p)) { 3376cd6a6acSopenharmony_ci cond_av_list_t *tmp = *cond; 3386cd6a6acSopenharmony_ci 3396cd6a6acSopenharmony_ci *cond = tmp->next; 3406cd6a6acSopenharmony_ci tmp->next = pcov; 3416cd6a6acSopenharmony_ci pcov = tmp; 3426cd6a6acSopenharmony_ci } else { 3436cd6a6acSopenharmony_ci cond = &(*cond)->next; 3446cd6a6acSopenharmony_ci } 3456cd6a6acSopenharmony_ci } 3466cd6a6acSopenharmony_ci /* link the "potentially covering" rules to the end of the list */ 3476cd6a6acSopenharmony_ci *cond = pcov; 3486cd6a6acSopenharmony_ci 3496cd6a6acSopenharmony_ci /* now go through the list and find the redundant rules */ 3506cd6a6acSopenharmony_ci cond = listp; 3516cd6a6acSopenharmony_ci pcov_cur = &pcov; 3526cd6a6acSopenharmony_ci while (*cond) { 3536cd6a6acSopenharmony_ci /* needed because pcov itself may get deleted */ 3546cd6a6acSopenharmony_ci if (*cond == pcov) 3556cd6a6acSopenharmony_ci pcov_cur = cond; 3566cd6a6acSopenharmony_ci /* 3576cd6a6acSopenharmony_ci * First check if covered by an unconditional rule, then also 3586cd6a6acSopenharmony_ci * check if covered by another rule in the same list. 3596cd6a6acSopenharmony_ci */ 3606cd6a6acSopenharmony_ci if (is_avrule_redundant((*cond)->node, &p->te_avtab, type_map, 0) || 3616cd6a6acSopenharmony_ci is_cond_rule_redundant((*cond)->node, *pcov_cur, type_map)) { 3626cd6a6acSopenharmony_ci cond_av_list_t *tmp = *cond; 3636cd6a6acSopenharmony_ci 3646cd6a6acSopenharmony_ci *cond = tmp->next; 3656cd6a6acSopenharmony_ci tmp->next = *del; 3666cd6a6acSopenharmony_ci *del = tmp; 3676cd6a6acSopenharmony_ci } else { 3686cd6a6acSopenharmony_ci cond = &(*cond)->next; 3696cd6a6acSopenharmony_ci } 3706cd6a6acSopenharmony_ci } 3716cd6a6acSopenharmony_ci} 3726cd6a6acSopenharmony_ci 3736cd6a6acSopenharmony_cistatic void optimize_cond_avtab(policydb_t *p, const struct type_vec *type_map) 3746cd6a6acSopenharmony_ci{ 3756cd6a6acSopenharmony_ci avtab_t *tab = &p->te_cond_avtab; 3766cd6a6acSopenharmony_ci unsigned int i; 3776cd6a6acSopenharmony_ci avtab_ptr_t *cur; 3786cd6a6acSopenharmony_ci cond_node_t **cond; 3796cd6a6acSopenharmony_ci cond_av_list_t **avcond, *del = NULL; 3806cd6a6acSopenharmony_ci 3816cd6a6acSopenharmony_ci /* First go through all conditionals and collect redundant rules. */ 3826cd6a6acSopenharmony_ci cond = &p->cond_list; 3836cd6a6acSopenharmony_ci while (*cond) { 3846cd6a6acSopenharmony_ci optimize_cond_av_list(&(*cond)->true_list, &del, p, type_map); 3856cd6a6acSopenharmony_ci optimize_cond_av_list(&(*cond)->false_list, &del, p, type_map); 3866cd6a6acSopenharmony_ci /* TODO: maybe also check for rules present in both lists */ 3876cd6a6acSopenharmony_ci 3886cd6a6acSopenharmony_ci /* nothing left in both lists -> remove the whole conditional */ 3896cd6a6acSopenharmony_ci if (!(*cond)->true_list && !(*cond)->false_list) { 3906cd6a6acSopenharmony_ci cond_node_t *cond_tmp = *cond; 3916cd6a6acSopenharmony_ci 3926cd6a6acSopenharmony_ci *cond = cond_tmp->next; 3936cd6a6acSopenharmony_ci cond_node_destroy(cond_tmp); 3946cd6a6acSopenharmony_ci free(cond_tmp); 3956cd6a6acSopenharmony_ci } else { 3966cd6a6acSopenharmony_ci cond = &(*cond)->next; 3976cd6a6acSopenharmony_ci } 3986cd6a6acSopenharmony_ci } 3996cd6a6acSopenharmony_ci 4006cd6a6acSopenharmony_ci if (!del) 4016cd6a6acSopenharmony_ci return; 4026cd6a6acSopenharmony_ci 4036cd6a6acSopenharmony_ci /* 4046cd6a6acSopenharmony_ci * Now go through the whole cond_avtab and remove all rules that are 4056cd6a6acSopenharmony_ci * found in the 'del' list. 4066cd6a6acSopenharmony_ci */ 4076cd6a6acSopenharmony_ci for (i = 0; i < tab->nslot; i++) { 4086cd6a6acSopenharmony_ci cur = &tab->htable[i]; 4096cd6a6acSopenharmony_ci while (*cur) { 4106cd6a6acSopenharmony_ci int redundant = 0; 4116cd6a6acSopenharmony_ci avcond = &del; 4126cd6a6acSopenharmony_ci while (*avcond) { 4136cd6a6acSopenharmony_ci if ((*avcond)->node == *cur) { 4146cd6a6acSopenharmony_ci cond_av_list_t *cond_tmp = *avcond; 4156cd6a6acSopenharmony_ci 4166cd6a6acSopenharmony_ci *avcond = cond_tmp->next; 4176cd6a6acSopenharmony_ci free(cond_tmp); 4186cd6a6acSopenharmony_ci redundant = 1; 4196cd6a6acSopenharmony_ci break; 4206cd6a6acSopenharmony_ci } else { 4216cd6a6acSopenharmony_ci avcond = &(*avcond)->next; 4226cd6a6acSopenharmony_ci } 4236cd6a6acSopenharmony_ci } 4246cd6a6acSopenharmony_ci if (redundant) { 4256cd6a6acSopenharmony_ci avtab_ptr_t tmp = *cur; 4266cd6a6acSopenharmony_ci 4276cd6a6acSopenharmony_ci *cur = tmp->next; 4286cd6a6acSopenharmony_ci if (tmp->key.specified & AVTAB_XPERMS) 4296cd6a6acSopenharmony_ci free(tmp->datum.xperms); 4306cd6a6acSopenharmony_ci free(tmp); 4316cd6a6acSopenharmony_ci 4326cd6a6acSopenharmony_ci tab->nel--; 4336cd6a6acSopenharmony_ci } else { 4346cd6a6acSopenharmony_ci cur = &(*cur)->next; 4356cd6a6acSopenharmony_ci } 4366cd6a6acSopenharmony_ci } 4376cd6a6acSopenharmony_ci } 4386cd6a6acSopenharmony_ci} 4396cd6a6acSopenharmony_ci 4406cd6a6acSopenharmony_ciint policydb_optimize(policydb_t *p) 4416cd6a6acSopenharmony_ci{ 4426cd6a6acSopenharmony_ci struct type_vec *type_map; 4436cd6a6acSopenharmony_ci 4446cd6a6acSopenharmony_ci if (p->policy_type != POLICY_KERN) 4456cd6a6acSopenharmony_ci return -1; 4466cd6a6acSopenharmony_ci 4476cd6a6acSopenharmony_ci if (p->policyvers >= POLICYDB_VERSION_AVTAB && p->policyvers <= POLICYDB_VERSION_PERMISSIVE) { 4486cd6a6acSopenharmony_ci /* 4496cd6a6acSopenharmony_ci * For policy versions between 20 and 23, attributes exist in the policy, 4506cd6a6acSopenharmony_ci * but only in the type_attr_map. This means that there are gaps in both 4516cd6a6acSopenharmony_ci * the type_val_to_struct and p_type_val_to_name arrays and policy rules 4526cd6a6acSopenharmony_ci * can refer to those gaps. 4536cd6a6acSopenharmony_ci */ 4546cd6a6acSopenharmony_ci ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported"); 4556cd6a6acSopenharmony_ci return -1; 4566cd6a6acSopenharmony_ci } 4576cd6a6acSopenharmony_ci 4586cd6a6acSopenharmony_ci type_map = build_type_map(p); 4596cd6a6acSopenharmony_ci if (!type_map) 4606cd6a6acSopenharmony_ci return -1; 4616cd6a6acSopenharmony_ci 4626cd6a6acSopenharmony_ci optimize_avtab(p, type_map); 4636cd6a6acSopenharmony_ci optimize_cond_avtab(p, type_map); 4646cd6a6acSopenharmony_ci 4656cd6a6acSopenharmony_ci destroy_type_map(p, type_map); 4666cd6a6acSopenharmony_ci return 0; 4676cd6a6acSopenharmony_ci} 468