xref: /aosp_15_r20/external/selinux/libsepol/src/optimize.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker  * Author: Ondrej Mosnacek <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker  *
4*2d543d20SAndroid Build Coastguard Worker  * Copyright (C) 2019 Red Hat Inc.
5*2d543d20SAndroid Build Coastguard Worker  *
6*2d543d20SAndroid Build Coastguard Worker  *  This library is free software; you can redistribute it and/or
7*2d543d20SAndroid Build Coastguard Worker  *  modify it under the terms of the GNU Lesser General Public
8*2d543d20SAndroid Build Coastguard Worker  *  License as published by the Free Software Foundation; either
9*2d543d20SAndroid Build Coastguard Worker  *  version 2.1 of the License, or (at your option) any later version.
10*2d543d20SAndroid Build Coastguard Worker  *
11*2d543d20SAndroid Build Coastguard Worker  *  This library is distributed in the hope that it will be useful,
12*2d543d20SAndroid Build Coastguard Worker  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13*2d543d20SAndroid Build Coastguard Worker  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*2d543d20SAndroid Build Coastguard Worker  *  Lesser General Public License for more details.
15*2d543d20SAndroid Build Coastguard Worker  *
16*2d543d20SAndroid Build Coastguard Worker  *  You should have received a copy of the GNU Lesser General Public
17*2d543d20SAndroid Build Coastguard Worker  *  License along with this library; if not, write to the Free Software
18*2d543d20SAndroid Build Coastguard Worker  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19*2d543d20SAndroid Build Coastguard Worker  */
20*2d543d20SAndroid Build Coastguard Worker 
21*2d543d20SAndroid Build Coastguard Worker /*
22*2d543d20SAndroid Build Coastguard Worker  * Binary policy optimization.
23*2d543d20SAndroid Build Coastguard Worker  *
24*2d543d20SAndroid Build Coastguard Worker  * Defines the policydb_optimize() function, which finds and removes
25*2d543d20SAndroid Build Coastguard Worker  * redundant rules from the binary policy to reduce its size and potentially
26*2d543d20SAndroid Build Coastguard Worker  * improve rule matching times. Only rules that are already covered by a
27*2d543d20SAndroid Build Coastguard Worker  * more general rule are removed. The resulting policy is functionally
28*2d543d20SAndroid Build Coastguard Worker  * equivalent to the original one.
29*2d543d20SAndroid Build Coastguard Worker  */
30*2d543d20SAndroid Build Coastguard Worker 
31*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/policydb.h>
32*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/conditional.h>
33*2d543d20SAndroid Build Coastguard Worker 
34*2d543d20SAndroid Build Coastguard Worker #include "debug.h"
35*2d543d20SAndroid Build Coastguard Worker #include "private.h"
36*2d543d20SAndroid Build Coastguard Worker 
37*2d543d20SAndroid Build Coastguard Worker #define TYPE_VEC_INIT_SIZE 16
38*2d543d20SAndroid Build Coastguard Worker 
39*2d543d20SAndroid Build Coastguard Worker struct type_vec {
40*2d543d20SAndroid Build Coastguard Worker 	uint32_t *types;
41*2d543d20SAndroid Build Coastguard Worker 	unsigned int count, capacity;
42*2d543d20SAndroid Build Coastguard Worker };
43*2d543d20SAndroid Build Coastguard Worker 
type_vec_init(struct type_vec * v)44*2d543d20SAndroid Build Coastguard Worker static int type_vec_init(struct type_vec *v)
45*2d543d20SAndroid Build Coastguard Worker {
46*2d543d20SAndroid Build Coastguard Worker 	v->capacity = TYPE_VEC_INIT_SIZE;
47*2d543d20SAndroid Build Coastguard Worker 	v->count = 0;
48*2d543d20SAndroid Build Coastguard Worker 	v->types = calloc(v->capacity, sizeof(*v->types));
49*2d543d20SAndroid Build Coastguard Worker 	if (!v->types)
50*2d543d20SAndroid Build Coastguard Worker 		return -1;
51*2d543d20SAndroid Build Coastguard Worker 	return 0;
52*2d543d20SAndroid Build Coastguard Worker }
53*2d543d20SAndroid Build Coastguard Worker 
type_vec_destroy(struct type_vec * v)54*2d543d20SAndroid Build Coastguard Worker static void type_vec_destroy(struct type_vec *v)
55*2d543d20SAndroid Build Coastguard Worker {
56*2d543d20SAndroid Build Coastguard Worker 	free(v->types);
57*2d543d20SAndroid Build Coastguard Worker }
58*2d543d20SAndroid Build Coastguard Worker 
type_vec_append(struct type_vec * v,uint32_t type)59*2d543d20SAndroid Build Coastguard Worker static int type_vec_append(struct type_vec *v, uint32_t type)
60*2d543d20SAndroid Build Coastguard Worker {
61*2d543d20SAndroid Build Coastguard Worker 	if (v->capacity == v->count) {
62*2d543d20SAndroid Build Coastguard Worker 		unsigned int new_capacity = v->capacity * 2;
63*2d543d20SAndroid Build Coastguard Worker 		uint32_t *new_types = reallocarray(v->types,
64*2d543d20SAndroid Build Coastguard Worker 						   new_capacity,
65*2d543d20SAndroid Build Coastguard Worker 						   sizeof(*v->types));
66*2d543d20SAndroid Build Coastguard Worker 		if (!new_types)
67*2d543d20SAndroid Build Coastguard Worker 			return -1;
68*2d543d20SAndroid Build Coastguard Worker 
69*2d543d20SAndroid Build Coastguard Worker 		v->types = new_types;
70*2d543d20SAndroid Build Coastguard Worker 		v->capacity = new_capacity;
71*2d543d20SAndroid Build Coastguard Worker 	}
72*2d543d20SAndroid Build Coastguard Worker 
73*2d543d20SAndroid Build Coastguard Worker 	v->types[v->count++] = type;
74*2d543d20SAndroid Build Coastguard Worker 	return 0;
75*2d543d20SAndroid Build Coastguard Worker }
76*2d543d20SAndroid Build Coastguard Worker 
type_vec_contains(const struct type_vec * v,uint32_t type)77*2d543d20SAndroid Build Coastguard Worker static int type_vec_contains(const struct type_vec *v, uint32_t type)
78*2d543d20SAndroid Build Coastguard Worker {
79*2d543d20SAndroid Build Coastguard Worker 	unsigned int s = 0, e = v->count;
80*2d543d20SAndroid Build Coastguard Worker 
81*2d543d20SAndroid Build Coastguard Worker 	while (s != e) {
82*2d543d20SAndroid Build Coastguard Worker 		unsigned int mid = (s + e) / 2;
83*2d543d20SAndroid Build Coastguard Worker 
84*2d543d20SAndroid Build Coastguard Worker 		if (v->types[mid] == type)
85*2d543d20SAndroid Build Coastguard Worker 			return 1;
86*2d543d20SAndroid Build Coastguard Worker 
87*2d543d20SAndroid Build Coastguard Worker 		if (v->types[mid] < type)
88*2d543d20SAndroid Build Coastguard Worker 			s = mid + 1;
89*2d543d20SAndroid Build Coastguard Worker 		else
90*2d543d20SAndroid Build Coastguard Worker 			e = mid;
91*2d543d20SAndroid Build Coastguard Worker 	}
92*2d543d20SAndroid Build Coastguard Worker 	return 0;
93*2d543d20SAndroid Build Coastguard Worker }
94*2d543d20SAndroid Build Coastguard Worker 
95*2d543d20SAndroid Build Coastguard Worker /* builds map: type/attribute -> {all attributes that are a superset of it} */
build_type_map(const policydb_t * p)96*2d543d20SAndroid Build Coastguard Worker static struct type_vec *build_type_map(const policydb_t *p)
97*2d543d20SAndroid Build Coastguard Worker {
98*2d543d20SAndroid Build Coastguard Worker 	unsigned int i, k;
99*2d543d20SAndroid Build Coastguard Worker 	ebitmap_node_t *n;
100*2d543d20SAndroid Build Coastguard Worker 	struct type_vec *map = calloc(p->p_types.nprim, sizeof(*map));
101*2d543d20SAndroid Build Coastguard Worker 	if (!map)
102*2d543d20SAndroid Build Coastguard Worker 		return NULL;
103*2d543d20SAndroid Build Coastguard Worker 
104*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < p->p_types.nprim; i++) {
105*2d543d20SAndroid Build Coastguard Worker 		if (type_vec_init(&map[i]))
106*2d543d20SAndroid Build Coastguard Worker 			goto err;
107*2d543d20SAndroid Build Coastguard Worker 
108*2d543d20SAndroid Build Coastguard Worker 		if (!p->type_val_to_struct[i])
109*2d543d20SAndroid Build Coastguard Worker 			continue;
110*2d543d20SAndroid Build Coastguard Worker 
111*2d543d20SAndroid Build Coastguard Worker 		if (p->type_val_to_struct[i]->flavor != TYPE_ATTRIB) {
112*2d543d20SAndroid Build Coastguard Worker 			ebitmap_for_each_positive_bit(&p->type_attr_map[i],
113*2d543d20SAndroid Build Coastguard Worker 						      n, k) {
114*2d543d20SAndroid Build Coastguard Worker 				if (type_vec_append(&map[i], k))
115*2d543d20SAndroid Build Coastguard Worker 					goto err;
116*2d543d20SAndroid Build Coastguard Worker 			}
117*2d543d20SAndroid Build Coastguard Worker 		} else {
118*2d543d20SAndroid Build Coastguard Worker 			ebitmap_t *types_i = &p->attr_type_map[i];
119*2d543d20SAndroid Build Coastguard Worker 
120*2d543d20SAndroid Build Coastguard Worker 			for (k = 0; k < p->p_types.nprim; k++) {
121*2d543d20SAndroid Build Coastguard Worker 				const ebitmap_t *types_k;
122*2d543d20SAndroid Build Coastguard Worker 
123*2d543d20SAndroid Build Coastguard Worker 				if (!p->type_val_to_struct[k] || p->type_val_to_struct[k]->flavor != TYPE_ATTRIB)
124*2d543d20SAndroid Build Coastguard Worker 					continue;
125*2d543d20SAndroid Build Coastguard Worker 
126*2d543d20SAndroid Build Coastguard Worker 				types_k = &p->attr_type_map[k];
127*2d543d20SAndroid Build Coastguard Worker 
128*2d543d20SAndroid Build Coastguard Worker 				if (ebitmap_contains(types_k, types_i)) {
129*2d543d20SAndroid Build Coastguard Worker 					if (type_vec_append(&map[i], k))
130*2d543d20SAndroid Build Coastguard Worker 						goto err;
131*2d543d20SAndroid Build Coastguard Worker 				}
132*2d543d20SAndroid Build Coastguard Worker 			}
133*2d543d20SAndroid Build Coastguard Worker 		}
134*2d543d20SAndroid Build Coastguard Worker 	}
135*2d543d20SAndroid Build Coastguard Worker 	return map;
136*2d543d20SAndroid Build Coastguard Worker err:
137*2d543d20SAndroid Build Coastguard Worker 	for (k = 0; k <= i; k++)
138*2d543d20SAndroid Build Coastguard Worker 		type_vec_destroy(&map[k]);
139*2d543d20SAndroid Build Coastguard Worker 	free(map);
140*2d543d20SAndroid Build Coastguard Worker 	return NULL;
141*2d543d20SAndroid Build Coastguard Worker }
142*2d543d20SAndroid Build Coastguard Worker 
destroy_type_map(const policydb_t * p,struct type_vec * type_map)143*2d543d20SAndroid Build Coastguard Worker static void destroy_type_map(const policydb_t *p, struct type_vec *type_map)
144*2d543d20SAndroid Build Coastguard Worker {
145*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
146*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < p->p_types.nprim; i++)
147*2d543d20SAndroid Build Coastguard Worker 		type_vec_destroy(&type_map[i]);
148*2d543d20SAndroid Build Coastguard Worker 	free(type_map);
149*2d543d20SAndroid Build Coastguard Worker }
150*2d543d20SAndroid Build Coastguard Worker 
process_xperms(uint32_t * p1,const uint32_t * p2)151*2d543d20SAndroid Build Coastguard Worker static int process_xperms(uint32_t *p1, const uint32_t *p2)
152*2d543d20SAndroid Build Coastguard Worker {
153*2d543d20SAndroid Build Coastguard Worker 	size_t i;
154*2d543d20SAndroid Build Coastguard Worker 	int ret = 1;
155*2d543d20SAndroid Build Coastguard Worker 
156*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < EXTENDED_PERMS_LEN; i++) {
157*2d543d20SAndroid Build Coastguard Worker 		p1[i] &= ~p2[i];
158*2d543d20SAndroid Build Coastguard Worker 		if (p1[i] != 0)
159*2d543d20SAndroid Build Coastguard Worker 			ret = 0;
160*2d543d20SAndroid Build Coastguard Worker 	}
161*2d543d20SAndroid Build Coastguard Worker 	return ret;
162*2d543d20SAndroid Build Coastguard Worker }
163*2d543d20SAndroid Build Coastguard Worker 
process_avtab_datum(uint16_t specified,avtab_datum_t * d1,const avtab_datum_t * d2)164*2d543d20SAndroid Build Coastguard Worker static int process_avtab_datum(uint16_t specified,
165*2d543d20SAndroid Build Coastguard Worker 			       avtab_datum_t *d1, const avtab_datum_t *d2)
166*2d543d20SAndroid Build Coastguard Worker {
167*2d543d20SAndroid Build Coastguard Worker 	/* inverse logic needed for AUDITDENY rules */
168*2d543d20SAndroid Build Coastguard Worker 	if (specified & AVTAB_AUDITDENY)
169*2d543d20SAndroid Build Coastguard Worker 		return (d1->data |= ~d2->data) == UINT32_C(0xFFFFFFFF);
170*2d543d20SAndroid Build Coastguard Worker 
171*2d543d20SAndroid Build Coastguard Worker 	if (specified & AVTAB_AV)
172*2d543d20SAndroid Build Coastguard Worker 		return (d1->data &= ~d2->data) == 0;
173*2d543d20SAndroid Build Coastguard Worker 
174*2d543d20SAndroid Build Coastguard Worker 	if (specified & AVTAB_XPERMS) {
175*2d543d20SAndroid Build Coastguard Worker 		avtab_extended_perms_t *x1 = d1->xperms;
176*2d543d20SAndroid Build Coastguard Worker 		const avtab_extended_perms_t *x2 = d2->xperms;
177*2d543d20SAndroid Build Coastguard Worker 
178*2d543d20SAndroid Build Coastguard Worker 		if (x1->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
179*2d543d20SAndroid Build Coastguard Worker 			if (x2->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
180*2d543d20SAndroid Build Coastguard Worker 				if (x1->driver != x2->driver)
181*2d543d20SAndroid Build Coastguard Worker 					return 0;
182*2d543d20SAndroid Build Coastguard Worker 				return process_xperms(x1->perms, x2->perms);
183*2d543d20SAndroid Build Coastguard Worker 			}
184*2d543d20SAndroid Build Coastguard Worker 			if (x2->specified == AVTAB_XPERMS_IOCTLDRIVER)
185*2d543d20SAndroid Build Coastguard Worker 				return xperm_test(x1->driver, x2->perms);
186*2d543d20SAndroid Build Coastguard Worker 		} else if (x1->specified == AVTAB_XPERMS_IOCTLDRIVER) {
187*2d543d20SAndroid Build Coastguard Worker 			if (x2->specified == AVTAB_XPERMS_IOCTLFUNCTION)
188*2d543d20SAndroid Build Coastguard Worker 				return 0;
189*2d543d20SAndroid Build Coastguard Worker 
190*2d543d20SAndroid Build Coastguard Worker 			if (x2->specified == AVTAB_XPERMS_IOCTLDRIVER)
191*2d543d20SAndroid Build Coastguard Worker 				return process_xperms(x1->perms, x2->perms);
192*2d543d20SAndroid Build Coastguard Worker 		} else if (x1->specified == AVTAB_XPERMS_NLMSG
193*2d543d20SAndroid Build Coastguard Worker 				&& x2->specified == AVTAB_XPERMS_NLMSG) {
194*2d543d20SAndroid Build Coastguard Worker 			if (x1->driver != x2->driver)
195*2d543d20SAndroid Build Coastguard Worker 				return 0;
196*2d543d20SAndroid Build Coastguard Worker 			return process_xperms(x1->perms, x2->perms);
197*2d543d20SAndroid Build Coastguard Worker 		}
198*2d543d20SAndroid Build Coastguard Worker 		return 0;
199*2d543d20SAndroid Build Coastguard Worker 	}
200*2d543d20SAndroid Build Coastguard Worker 	return 0;
201*2d543d20SAndroid Build Coastguard Worker }
202*2d543d20SAndroid Build Coastguard Worker 
203*2d543d20SAndroid Build Coastguard Worker /* checks if avtab contains a rule that covers the given rule */
is_avrule_redundant(avtab_ptr_t entry,avtab_t * tab,const struct type_vec * type_map,unsigned char not_cond)204*2d543d20SAndroid Build Coastguard Worker static int is_avrule_redundant(avtab_ptr_t entry, avtab_t *tab,
205*2d543d20SAndroid Build Coastguard Worker 			       const struct type_vec *type_map,
206*2d543d20SAndroid Build Coastguard Worker 			       unsigned char not_cond)
207*2d543d20SAndroid Build Coastguard Worker {
208*2d543d20SAndroid Build Coastguard Worker 	unsigned int i, k, s_idx, t_idx;
209*2d543d20SAndroid Build Coastguard Worker 	uint32_t st, tt;
210*2d543d20SAndroid Build Coastguard Worker 	avtab_datum_t *d1, *d2;
211*2d543d20SAndroid Build Coastguard Worker 	avtab_key_t key;
212*2d543d20SAndroid Build Coastguard Worker 
213*2d543d20SAndroid Build Coastguard Worker 	/* we only care about AV rules */
214*2d543d20SAndroid Build Coastguard Worker 	if (!(entry->key.specified & (AVTAB_AV|AVTAB_XPERMS)))
215*2d543d20SAndroid Build Coastguard Worker 		return 0;
216*2d543d20SAndroid Build Coastguard Worker 
217*2d543d20SAndroid Build Coastguard Worker 	s_idx = entry->key.source_type - 1;
218*2d543d20SAndroid Build Coastguard Worker 	t_idx = entry->key.target_type - 1;
219*2d543d20SAndroid Build Coastguard Worker 
220*2d543d20SAndroid Build Coastguard Worker 	key.target_class = entry->key.target_class;
221*2d543d20SAndroid Build Coastguard Worker 	key.specified    = entry->key.specified;
222*2d543d20SAndroid Build Coastguard Worker 
223*2d543d20SAndroid Build Coastguard Worker 	d1 = &entry->datum;
224*2d543d20SAndroid Build Coastguard Worker 
225*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < type_map[s_idx].count; i++) {
226*2d543d20SAndroid Build Coastguard Worker 		st = type_map[s_idx].types[i];
227*2d543d20SAndroid Build Coastguard Worker 		key.source_type = st + 1;
228*2d543d20SAndroid Build Coastguard Worker 
229*2d543d20SAndroid Build Coastguard Worker 		for (k = 0; k < type_map[t_idx].count; k++) {
230*2d543d20SAndroid Build Coastguard Worker 			tt = type_map[t_idx].types[k];
231*2d543d20SAndroid Build Coastguard Worker 
232*2d543d20SAndroid Build Coastguard Worker 			if (not_cond && s_idx == st && t_idx == tt)
233*2d543d20SAndroid Build Coastguard Worker 				continue;
234*2d543d20SAndroid Build Coastguard Worker 
235*2d543d20SAndroid Build Coastguard Worker 			key.target_type = tt + 1;
236*2d543d20SAndroid Build Coastguard Worker 
237*2d543d20SAndroid Build Coastguard Worker 			d2 = avtab_search(tab, &key);
238*2d543d20SAndroid Build Coastguard Worker 			if (!d2)
239*2d543d20SAndroid Build Coastguard Worker 				continue;
240*2d543d20SAndroid Build Coastguard Worker 
241*2d543d20SAndroid Build Coastguard Worker 			if (process_avtab_datum(key.specified, d1, d2))
242*2d543d20SAndroid Build Coastguard Worker 				return 1;
243*2d543d20SAndroid Build Coastguard Worker 		}
244*2d543d20SAndroid Build Coastguard Worker 	}
245*2d543d20SAndroid Build Coastguard Worker 	return 0;
246*2d543d20SAndroid Build Coastguard Worker }
247*2d543d20SAndroid Build Coastguard Worker 
is_type_attr(policydb_t * p,unsigned int id)248*2d543d20SAndroid Build Coastguard Worker static int is_type_attr(policydb_t *p, unsigned int id)
249*2d543d20SAndroid Build Coastguard Worker {
250*2d543d20SAndroid Build Coastguard Worker 	return p->type_val_to_struct[id]->flavor == TYPE_ATTRIB;
251*2d543d20SAndroid Build Coastguard Worker }
252*2d543d20SAndroid Build Coastguard Worker 
is_avrule_with_attr(avtab_ptr_t entry,policydb_t * p)253*2d543d20SAndroid Build Coastguard Worker static int is_avrule_with_attr(avtab_ptr_t entry, policydb_t *p)
254*2d543d20SAndroid Build Coastguard Worker {
255*2d543d20SAndroid Build Coastguard Worker 	unsigned int s_idx = entry->key.source_type - 1;
256*2d543d20SAndroid Build Coastguard Worker 	unsigned int t_idx = entry->key.target_type - 1;
257*2d543d20SAndroid Build Coastguard Worker 
258*2d543d20SAndroid Build Coastguard Worker 	return is_type_attr(p, s_idx) || is_type_attr(p, t_idx);
259*2d543d20SAndroid Build Coastguard Worker }
260*2d543d20SAndroid Build Coastguard Worker 
261*2d543d20SAndroid Build Coastguard Worker /* checks if conditional list contains a rule that covers the given rule */
is_cond_rule_redundant(avtab_ptr_t e1,cond_av_list_t * list,const struct type_vec * type_map)262*2d543d20SAndroid Build Coastguard Worker static int is_cond_rule_redundant(avtab_ptr_t e1, cond_av_list_t *list,
263*2d543d20SAndroid Build Coastguard Worker 				  const struct type_vec *type_map)
264*2d543d20SAndroid Build Coastguard Worker {
265*2d543d20SAndroid Build Coastguard Worker 	unsigned int s1, t1, c1, k1, s2, t2, c2, k2;
266*2d543d20SAndroid Build Coastguard Worker 
267*2d543d20SAndroid Build Coastguard Worker 	/* we only care about AV rules */
268*2d543d20SAndroid Build Coastguard Worker 	if (!(e1->key.specified & (AVTAB_AV|AVTAB_XPERMS)))
269*2d543d20SAndroid Build Coastguard Worker 		return 0;
270*2d543d20SAndroid Build Coastguard Worker 
271*2d543d20SAndroid Build Coastguard Worker 	s1 = e1->key.source_type - 1;
272*2d543d20SAndroid Build Coastguard Worker 	t1 = e1->key.target_type - 1;
273*2d543d20SAndroid Build Coastguard Worker 	c1 = e1->key.target_class;
274*2d543d20SAndroid Build Coastguard Worker 	k1 = e1->key.specified;
275*2d543d20SAndroid Build Coastguard Worker 
276*2d543d20SAndroid Build Coastguard Worker 	for (; list; list = list->next) {
277*2d543d20SAndroid Build Coastguard Worker 		avtab_ptr_t e2 = list->node;
278*2d543d20SAndroid Build Coastguard Worker 
279*2d543d20SAndroid Build Coastguard Worker 		s2 = e2->key.source_type - 1;
280*2d543d20SAndroid Build Coastguard Worker 		t2 = e2->key.target_type - 1;
281*2d543d20SAndroid Build Coastguard Worker 		c2 = e2->key.target_class;
282*2d543d20SAndroid Build Coastguard Worker 		k2 = e2->key.specified;
283*2d543d20SAndroid Build Coastguard Worker 
284*2d543d20SAndroid Build Coastguard Worker 		if (k1 != k2 || c1 != c2)
285*2d543d20SAndroid Build Coastguard Worker 			continue;
286*2d543d20SAndroid Build Coastguard Worker 
287*2d543d20SAndroid Build Coastguard Worker 		if (s1 == s2 && t1 == t2)
288*2d543d20SAndroid Build Coastguard Worker 			continue;
289*2d543d20SAndroid Build Coastguard Worker 		if (!type_vec_contains(&type_map[s1], s2))
290*2d543d20SAndroid Build Coastguard Worker 			continue;
291*2d543d20SAndroid Build Coastguard Worker 		if (!type_vec_contains(&type_map[t1], t2))
292*2d543d20SAndroid Build Coastguard Worker 			continue;
293*2d543d20SAndroid Build Coastguard Worker 
294*2d543d20SAndroid Build Coastguard Worker 		if (process_avtab_datum(k1, &e1->datum, &e2->datum))
295*2d543d20SAndroid Build Coastguard Worker 			return 1;
296*2d543d20SAndroid Build Coastguard Worker 	}
297*2d543d20SAndroid Build Coastguard Worker 	return 0;
298*2d543d20SAndroid Build Coastguard Worker }
299*2d543d20SAndroid Build Coastguard Worker 
optimize_avtab(policydb_t * p,const struct type_vec * type_map)300*2d543d20SAndroid Build Coastguard Worker static void optimize_avtab(policydb_t *p, const struct type_vec *type_map)
301*2d543d20SAndroid Build Coastguard Worker {
302*2d543d20SAndroid Build Coastguard Worker 	avtab_t *tab = &p->te_avtab;
303*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
304*2d543d20SAndroid Build Coastguard Worker 	avtab_ptr_t *cur;
305*2d543d20SAndroid Build Coastguard Worker 
306*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < tab->nslot; i++) {
307*2d543d20SAndroid Build Coastguard Worker 		cur = &tab->htable[i];
308*2d543d20SAndroid Build Coastguard Worker 		while (*cur) {
309*2d543d20SAndroid Build Coastguard Worker 			if (is_avrule_redundant(*cur, tab, type_map, 1)) {
310*2d543d20SAndroid Build Coastguard Worker 				/* redundant rule -> remove it */
311*2d543d20SAndroid Build Coastguard Worker 				avtab_ptr_t tmp = *cur;
312*2d543d20SAndroid Build Coastguard Worker 
313*2d543d20SAndroid Build Coastguard Worker 				*cur = tmp->next;
314*2d543d20SAndroid Build Coastguard Worker 				if (tmp->key.specified & AVTAB_XPERMS)
315*2d543d20SAndroid Build Coastguard Worker 					free(tmp->datum.xperms);
316*2d543d20SAndroid Build Coastguard Worker 				free(tmp);
317*2d543d20SAndroid Build Coastguard Worker 
318*2d543d20SAndroid Build Coastguard Worker 				tab->nel--;
319*2d543d20SAndroid Build Coastguard Worker 			} else {
320*2d543d20SAndroid Build Coastguard Worker 				/* rule not redundant -> move to next rule */
321*2d543d20SAndroid Build Coastguard Worker 				cur = &(*cur)->next;
322*2d543d20SAndroid Build Coastguard Worker 			}
323*2d543d20SAndroid Build Coastguard Worker 		}
324*2d543d20SAndroid Build Coastguard Worker 	}
325*2d543d20SAndroid Build Coastguard Worker }
326*2d543d20SAndroid Build Coastguard Worker 
327*2d543d20SAndroid Build Coastguard Worker /* find redundant rules in (*cond) and put them into (*del) */
optimize_cond_av_list(cond_av_list_t ** cond,cond_av_list_t ** del,policydb_t * p,const struct type_vec * type_map)328*2d543d20SAndroid Build Coastguard Worker static void optimize_cond_av_list(cond_av_list_t **cond, cond_av_list_t **del,
329*2d543d20SAndroid Build Coastguard Worker 				  policydb_t *p, const struct type_vec *type_map)
330*2d543d20SAndroid Build Coastguard Worker {
331*2d543d20SAndroid Build Coastguard Worker 	cond_av_list_t **listp = cond;
332*2d543d20SAndroid Build Coastguard Worker 	cond_av_list_t *pcov = NULL;
333*2d543d20SAndroid Build Coastguard Worker 	cond_av_list_t **pcov_cur;
334*2d543d20SAndroid Build Coastguard Worker 
335*2d543d20SAndroid Build Coastguard Worker 	/*
336*2d543d20SAndroid Build Coastguard Worker 	 * Separate out all "potentially covering" rules (src or tgt is an attr)
337*2d543d20SAndroid Build Coastguard Worker 	 * and move them to the end of the list. This is needed to avoid
338*2d543d20SAndroid Build Coastguard Worker 	 * polynomial complexity when almost all rules are expanded.
339*2d543d20SAndroid Build Coastguard Worker 	 */
340*2d543d20SAndroid Build Coastguard Worker 	while (*cond) {
341*2d543d20SAndroid Build Coastguard Worker 		if (is_avrule_with_attr((*cond)->node, p)) {
342*2d543d20SAndroid Build Coastguard Worker 			cond_av_list_t *tmp = *cond;
343*2d543d20SAndroid Build Coastguard Worker 
344*2d543d20SAndroid Build Coastguard Worker 			*cond = tmp->next;
345*2d543d20SAndroid Build Coastguard Worker 			tmp->next = pcov;
346*2d543d20SAndroid Build Coastguard Worker 			pcov = tmp;
347*2d543d20SAndroid Build Coastguard Worker 		} else {
348*2d543d20SAndroid Build Coastguard Worker 			cond = &(*cond)->next;
349*2d543d20SAndroid Build Coastguard Worker 		}
350*2d543d20SAndroid Build Coastguard Worker 	}
351*2d543d20SAndroid Build Coastguard Worker 	/* link the "potentially covering" rules to the end of the list */
352*2d543d20SAndroid Build Coastguard Worker 	*cond = pcov;
353*2d543d20SAndroid Build Coastguard Worker 
354*2d543d20SAndroid Build Coastguard Worker 	/* now go through the list and find the redundant rules */
355*2d543d20SAndroid Build Coastguard Worker 	cond = listp;
356*2d543d20SAndroid Build Coastguard Worker 	pcov_cur = &pcov;
357*2d543d20SAndroid Build Coastguard Worker 	while (*cond) {
358*2d543d20SAndroid Build Coastguard Worker 		/* needed because pcov itself may get deleted */
359*2d543d20SAndroid Build Coastguard Worker 		if (*cond == pcov)
360*2d543d20SAndroid Build Coastguard Worker 			pcov_cur = cond;
361*2d543d20SAndroid Build Coastguard Worker 		/*
362*2d543d20SAndroid Build Coastguard Worker 		 * First check if covered by an unconditional rule, then also
363*2d543d20SAndroid Build Coastguard Worker 		 * check if covered by another rule in the same list.
364*2d543d20SAndroid Build Coastguard Worker 		 */
365*2d543d20SAndroid Build Coastguard Worker 		if (is_avrule_redundant((*cond)->node, &p->te_avtab, type_map, 0) ||
366*2d543d20SAndroid Build Coastguard Worker 		    is_cond_rule_redundant((*cond)->node, *pcov_cur, type_map)) {
367*2d543d20SAndroid Build Coastguard Worker 			cond_av_list_t *tmp = *cond;
368*2d543d20SAndroid Build Coastguard Worker 
369*2d543d20SAndroid Build Coastguard Worker 			*cond = tmp->next;
370*2d543d20SAndroid Build Coastguard Worker 			tmp->next = *del;
371*2d543d20SAndroid Build Coastguard Worker 			*del = tmp;
372*2d543d20SAndroid Build Coastguard Worker 		} else {
373*2d543d20SAndroid Build Coastguard Worker 			cond = &(*cond)->next;
374*2d543d20SAndroid Build Coastguard Worker 		}
375*2d543d20SAndroid Build Coastguard Worker 	}
376*2d543d20SAndroid Build Coastguard Worker }
377*2d543d20SAndroid Build Coastguard Worker 
optimize_cond_avtab(policydb_t * p,const struct type_vec * type_map)378*2d543d20SAndroid Build Coastguard Worker static void optimize_cond_avtab(policydb_t *p, const struct type_vec *type_map)
379*2d543d20SAndroid Build Coastguard Worker {
380*2d543d20SAndroid Build Coastguard Worker 	avtab_t *tab = &p->te_cond_avtab;
381*2d543d20SAndroid Build Coastguard Worker 	unsigned int i;
382*2d543d20SAndroid Build Coastguard Worker 	avtab_ptr_t *cur;
383*2d543d20SAndroid Build Coastguard Worker 	cond_node_t **cond;
384*2d543d20SAndroid Build Coastguard Worker 	cond_av_list_t **avcond, *del = NULL;
385*2d543d20SAndroid Build Coastguard Worker 
386*2d543d20SAndroid Build Coastguard Worker 	/* First go through all conditionals and collect redundant rules. */
387*2d543d20SAndroid Build Coastguard Worker 	cond = &p->cond_list;
388*2d543d20SAndroid Build Coastguard Worker 	while (*cond) {
389*2d543d20SAndroid Build Coastguard Worker 		optimize_cond_av_list(&(*cond)->true_list,  &del, p, type_map);
390*2d543d20SAndroid Build Coastguard Worker 		optimize_cond_av_list(&(*cond)->false_list, &del, p, type_map);
391*2d543d20SAndroid Build Coastguard Worker 		/* TODO: maybe also check for rules present in both lists */
392*2d543d20SAndroid Build Coastguard Worker 
393*2d543d20SAndroid Build Coastguard Worker 		/* nothing left in both lists -> remove the whole conditional */
394*2d543d20SAndroid Build Coastguard Worker 		if (!(*cond)->true_list && !(*cond)->false_list) {
395*2d543d20SAndroid Build Coastguard Worker 			cond_node_t *cond_tmp = *cond;
396*2d543d20SAndroid Build Coastguard Worker 
397*2d543d20SAndroid Build Coastguard Worker 			*cond = cond_tmp->next;
398*2d543d20SAndroid Build Coastguard Worker 			cond_node_destroy(cond_tmp);
399*2d543d20SAndroid Build Coastguard Worker 			free(cond_tmp);
400*2d543d20SAndroid Build Coastguard Worker 		} else {
401*2d543d20SAndroid Build Coastguard Worker 			cond = &(*cond)->next;
402*2d543d20SAndroid Build Coastguard Worker 		}
403*2d543d20SAndroid Build Coastguard Worker 	}
404*2d543d20SAndroid Build Coastguard Worker 
405*2d543d20SAndroid Build Coastguard Worker 	if (!del)
406*2d543d20SAndroid Build Coastguard Worker 		return;
407*2d543d20SAndroid Build Coastguard Worker 
408*2d543d20SAndroid Build Coastguard Worker 	/*
409*2d543d20SAndroid Build Coastguard Worker 	 * Now go through the whole cond_avtab and remove all rules that are
410*2d543d20SAndroid Build Coastguard Worker 	 * found in the 'del' list.
411*2d543d20SAndroid Build Coastguard Worker 	 */
412*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < tab->nslot; i++) {
413*2d543d20SAndroid Build Coastguard Worker 		cur = &tab->htable[i];
414*2d543d20SAndroid Build Coastguard Worker 		while (*cur) {
415*2d543d20SAndroid Build Coastguard Worker 			int redundant = 0;
416*2d543d20SAndroid Build Coastguard Worker 			avcond = &del;
417*2d543d20SAndroid Build Coastguard Worker 			while (*avcond) {
418*2d543d20SAndroid Build Coastguard Worker 				if ((*avcond)->node == *cur) {
419*2d543d20SAndroid Build Coastguard Worker 					cond_av_list_t *cond_tmp = *avcond;
420*2d543d20SAndroid Build Coastguard Worker 
421*2d543d20SAndroid Build Coastguard Worker 					*avcond = cond_tmp->next;
422*2d543d20SAndroid Build Coastguard Worker 					free(cond_tmp);
423*2d543d20SAndroid Build Coastguard Worker 					redundant = 1;
424*2d543d20SAndroid Build Coastguard Worker 					break;
425*2d543d20SAndroid Build Coastguard Worker 				} else {
426*2d543d20SAndroid Build Coastguard Worker 					avcond = &(*avcond)->next;
427*2d543d20SAndroid Build Coastguard Worker 				}
428*2d543d20SAndroid Build Coastguard Worker 			}
429*2d543d20SAndroid Build Coastguard Worker 			if (redundant) {
430*2d543d20SAndroid Build Coastguard Worker 				avtab_ptr_t tmp = *cur;
431*2d543d20SAndroid Build Coastguard Worker 
432*2d543d20SAndroid Build Coastguard Worker 				*cur = tmp->next;
433*2d543d20SAndroid Build Coastguard Worker 				if (tmp->key.specified & AVTAB_XPERMS)
434*2d543d20SAndroid Build Coastguard Worker 					free(tmp->datum.xperms);
435*2d543d20SAndroid Build Coastguard Worker 				free(tmp);
436*2d543d20SAndroid Build Coastguard Worker 
437*2d543d20SAndroid Build Coastguard Worker 				tab->nel--;
438*2d543d20SAndroid Build Coastguard Worker 			} else {
439*2d543d20SAndroid Build Coastguard Worker 				cur = &(*cur)->next;
440*2d543d20SAndroid Build Coastguard Worker 			}
441*2d543d20SAndroid Build Coastguard Worker 		}
442*2d543d20SAndroid Build Coastguard Worker 	}
443*2d543d20SAndroid Build Coastguard Worker }
444*2d543d20SAndroid Build Coastguard Worker 
policydb_optimize(policydb_t * p)445*2d543d20SAndroid Build Coastguard Worker int policydb_optimize(policydb_t *p)
446*2d543d20SAndroid Build Coastguard Worker {
447*2d543d20SAndroid Build Coastguard Worker 	struct type_vec *type_map;
448*2d543d20SAndroid Build Coastguard Worker 
449*2d543d20SAndroid Build Coastguard Worker 	if (p->policy_type != POLICY_KERN)
450*2d543d20SAndroid Build Coastguard Worker 		return -1;
451*2d543d20SAndroid Build Coastguard Worker 
452*2d543d20SAndroid Build Coastguard Worker 	if (p->policyvers >= POLICYDB_VERSION_AVTAB && p->policyvers <= POLICYDB_VERSION_PERMISSIVE) {
453*2d543d20SAndroid Build Coastguard Worker 		/*
454*2d543d20SAndroid Build Coastguard Worker 		 * For policy versions between 20 and 23, attributes exist in the policy,
455*2d543d20SAndroid Build Coastguard Worker 		 * but only in the type_attr_map. This means that there are gaps in both
456*2d543d20SAndroid Build Coastguard Worker 		 * the type_val_to_struct and p_type_val_to_name arrays and policy rules
457*2d543d20SAndroid Build Coastguard Worker 		 * can refer to those gaps.
458*2d543d20SAndroid Build Coastguard Worker 		 */
459*2d543d20SAndroid Build Coastguard Worker 		ERR(NULL, "Optimizing policy versions between 20 and 23 is not supported");
460*2d543d20SAndroid Build Coastguard Worker 		return -1;
461*2d543d20SAndroid Build Coastguard Worker 	}
462*2d543d20SAndroid Build Coastguard Worker 
463*2d543d20SAndroid Build Coastguard Worker 	type_map = build_type_map(p);
464*2d543d20SAndroid Build Coastguard Worker 	if (!type_map)
465*2d543d20SAndroid Build Coastguard Worker 		return -1;
466*2d543d20SAndroid Build Coastguard Worker 
467*2d543d20SAndroid Build Coastguard Worker 	optimize_avtab(p, type_map);
468*2d543d20SAndroid Build Coastguard Worker 	optimize_cond_avtab(p, type_map);
469*2d543d20SAndroid Build Coastguard Worker 
470*2d543d20SAndroid Build Coastguard Worker 	destroy_type_map(p, type_map);
471*2d543d20SAndroid Build Coastguard Worker 	return 0;
472*2d543d20SAndroid Build Coastguard Worker }
473