/src/selinux/libsepol/src/conditional.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Authors: Karl MacMillan <kmacmillan@tresys.com> |
2 | | * Frank Mayer <mayerf@tresys.com> |
3 | | * David Caplan <dac@tresys.com> |
4 | | * |
5 | | * Copyright (C) 2003 - 2005 Tresys Technology, LLC |
6 | | * |
7 | | * This library is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * This library is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with this library; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include <stdlib.h> |
23 | | |
24 | | #include <sepol/policydb/flask_types.h> |
25 | | #include <sepol/policydb/conditional.h> |
26 | | |
27 | | #include "private.h" |
28 | | #include "debug.h" |
29 | | |
30 | | /* move all type rules to top of t/f lists to help kernel on evaluation */ |
31 | | static void cond_optimize(cond_av_list_t ** l) |
32 | 0 | { |
33 | 0 | cond_av_list_t *top, *p, *cur; |
34 | |
|
35 | 0 | top = p = cur = *l; |
36 | |
|
37 | 0 | while (cur) { |
38 | 0 | if ((cur->node->key.specified & AVTAB_TYPE) && (top != cur)) { |
39 | 0 | p->next = cur->next; |
40 | 0 | cur->next = top; |
41 | 0 | top = cur; |
42 | 0 | cur = p->next; |
43 | 0 | } else { |
44 | 0 | p = cur; |
45 | 0 | cur = cur->next; |
46 | 0 | } |
47 | 0 | } |
48 | 0 | *l = top; |
49 | 0 | } |
50 | | |
51 | | /* reorder t/f lists for kernel */ |
52 | | void cond_optimize_lists(cond_list_t * cl) |
53 | 75 | { |
54 | 75 | cond_list_t *n; |
55 | | |
56 | 75 | for (n = cl; n != NULL; n = n->next) { |
57 | 0 | cond_optimize(&n->true_list); |
58 | 0 | cond_optimize(&n->false_list); |
59 | 0 | } |
60 | 75 | } |
61 | | |
62 | | static int bool_present(unsigned int target, unsigned int bools[], |
63 | | unsigned int num_bools) |
64 | 0 | { |
65 | 0 | unsigned int i = 0; |
66 | 0 | int ret = 1; |
67 | |
|
68 | 0 | if (num_bools > COND_MAX_BOOLS) { |
69 | 0 | return 0; |
70 | 0 | } |
71 | 0 | while (i < num_bools && target != bools[i]) |
72 | 0 | i++; |
73 | 0 | if (i == num_bools) |
74 | 0 | ret = 0; /* got to end w/o match */ |
75 | 0 | return ret; |
76 | 0 | } |
77 | | |
78 | | static int same_bools(cond_node_t * a, cond_node_t * b) |
79 | 0 | { |
80 | 0 | unsigned int i, x; |
81 | |
|
82 | 0 | x = a->nbools; |
83 | | |
84 | | /* same number of bools? */ |
85 | 0 | if (x != b->nbools) |
86 | 0 | return 0; |
87 | | |
88 | | /* make sure all the bools in a are also in b */ |
89 | 0 | for (i = 0; i < x; i++) |
90 | 0 | if (!bool_present(a->bool_ids[i], b->bool_ids, x)) |
91 | 0 | return 0; |
92 | 0 | return 1; |
93 | 0 | } |
94 | | |
95 | | /* |
96 | | * Determine if two conditional expressions are equal. |
97 | | */ |
98 | | int cond_expr_equal(cond_node_t * a, cond_node_t * b) |
99 | 0 | { |
100 | 0 | cond_expr_t *cur_a, *cur_b; |
101 | |
|
102 | 0 | if (a == NULL || b == NULL) |
103 | 0 | return 0; |
104 | | |
105 | 0 | if (a->nbools != b->nbools) |
106 | 0 | return 0; |
107 | | |
108 | | /* if exprs have <= COND_MAX_BOOLS we can check the precompute values |
109 | | * for the expressions. |
110 | | */ |
111 | 0 | if (a->nbools <= COND_MAX_BOOLS && b->nbools <= COND_MAX_BOOLS) { |
112 | 0 | if (!same_bools(a, b)) |
113 | 0 | return 0; |
114 | 0 | return (a->expr_pre_comp == b->expr_pre_comp); |
115 | 0 | } |
116 | | |
117 | | /* for long expressions we check for exactly the same expression */ |
118 | 0 | cur_a = a->expr; |
119 | 0 | cur_b = b->expr; |
120 | 0 | while (1) { |
121 | 0 | if (cur_a == NULL && cur_b == NULL) |
122 | 0 | return 1; |
123 | 0 | else if (cur_a == NULL || cur_b == NULL) |
124 | 0 | return 0; |
125 | 0 | if (cur_a->expr_type != cur_b->expr_type) |
126 | 0 | return 0; |
127 | 0 | if (cur_a->expr_type == COND_BOOL) { |
128 | 0 | if (cur_a->boolean != cur_b->boolean) |
129 | 0 | return 0; |
130 | 0 | } |
131 | 0 | cur_a = cur_a->next; |
132 | 0 | cur_b = cur_b->next; |
133 | 0 | } |
134 | 0 | return 1; |
135 | 0 | } |
136 | | |
137 | | /* Create a new conditional node, optionally copying |
138 | | * the conditional expression from an existing node. |
139 | | * If node is NULL then a new node will be created |
140 | | * with no conditional expression. |
141 | | */ |
142 | | cond_node_t *cond_node_create(policydb_t * p, cond_node_t * node) |
143 | 0 | { |
144 | 0 | cond_node_t *new_node; |
145 | 0 | unsigned int i; |
146 | |
|
147 | 0 | new_node = (cond_node_t *)malloc(sizeof(cond_node_t)); |
148 | 0 | if (!new_node) { |
149 | 0 | return NULL; |
150 | 0 | } |
151 | 0 | memset(new_node, 0, sizeof(cond_node_t)); |
152 | |
|
153 | 0 | if (node) { |
154 | 0 | new_node->expr = cond_copy_expr(node->expr); |
155 | 0 | if (!new_node->expr) { |
156 | 0 | free(new_node); |
157 | 0 | return NULL; |
158 | 0 | } |
159 | 0 | new_node->cur_state = cond_evaluate_expr(p, new_node->expr); |
160 | 0 | new_node->nbools = node->nbools; |
161 | 0 | for (i = 0; i < min(node->nbools, COND_MAX_BOOLS); i++) |
162 | 0 | new_node->bool_ids[i] = node->bool_ids[i]; |
163 | 0 | new_node->expr_pre_comp = node->expr_pre_comp; |
164 | 0 | new_node->flags = node->flags; |
165 | 0 | } |
166 | | |
167 | 0 | return new_node; |
168 | 0 | } |
169 | | |
170 | | /* Find a conditional (the needle) within a list of existing ones (the |
171 | | * haystack) that has a matching expression. If found, return a |
172 | | * pointer to the existing node, setting 'was_created' to 0. |
173 | | * Otherwise create a new one and return it, setting 'was_created' to |
174 | | * 1. */ |
175 | | cond_node_t *cond_node_find(policydb_t * p, |
176 | | cond_node_t * needle, cond_node_t * haystack, |
177 | | int *was_created) |
178 | 0 | { |
179 | 0 | while (haystack) { |
180 | 0 | if (cond_expr_equal(needle, haystack)) { |
181 | 0 | *was_created = 0; |
182 | 0 | return haystack; |
183 | 0 | } |
184 | 0 | haystack = haystack->next; |
185 | 0 | } |
186 | 0 | *was_created = 1; |
187 | |
|
188 | 0 | return cond_node_create(p, needle); |
189 | 0 | } |
190 | | |
191 | | /* return either a pre-existing matching node or create a new node */ |
192 | | cond_node_t *cond_node_search(policydb_t * p, cond_node_t * list, |
193 | | cond_node_t * cn) |
194 | 0 | { |
195 | 0 | int was_created; |
196 | 0 | cond_node_t *result = cond_node_find(p, cn, list, &was_created); |
197 | 0 | if (result != NULL && was_created) { |
198 | | /* add conditional node to policy list */ |
199 | 0 | result->next = p->cond_list; |
200 | 0 | p->cond_list = result; |
201 | 0 | } |
202 | 0 | return result; |
203 | 0 | } |
204 | | |
205 | | /* |
206 | | * cond_evaluate_expr evaluates a conditional expr |
207 | | * in reverse polish notation. It returns true (1), false (0), |
208 | | * or undefined (-1). Undefined occurs when the expression |
209 | | * exceeds the stack depth of COND_EXPR_MAXDEPTH. |
210 | | */ |
211 | | int cond_evaluate_expr(policydb_t * p, cond_expr_t * expr) |
212 | 0 | { |
213 | |
|
214 | 0 | cond_expr_t *cur; |
215 | 0 | int s[COND_EXPR_MAXDEPTH]; |
216 | 0 | int sp = -1; |
217 | |
|
218 | 0 | s[0] = -1; |
219 | |
|
220 | 0 | for (cur = expr; cur != NULL; cur = cur->next) { |
221 | 0 | switch (cur->expr_type) { |
222 | 0 | case COND_BOOL: |
223 | 0 | if (sp == (COND_EXPR_MAXDEPTH - 1)) |
224 | 0 | return -1; |
225 | 0 | sp++; |
226 | 0 | s[sp] = p->bool_val_to_struct[cur->boolean - 1]->state; |
227 | 0 | break; |
228 | 0 | case COND_NOT: |
229 | 0 | if (sp < 0) |
230 | 0 | return -1; |
231 | 0 | s[sp] = !s[sp]; |
232 | 0 | break; |
233 | 0 | case COND_OR: |
234 | 0 | if (sp < 1) |
235 | 0 | return -1; |
236 | 0 | sp--; |
237 | 0 | s[sp] |= s[sp + 1]; |
238 | 0 | break; |
239 | 0 | case COND_AND: |
240 | 0 | if (sp < 1) |
241 | 0 | return -1; |
242 | 0 | sp--; |
243 | 0 | s[sp] &= s[sp + 1]; |
244 | 0 | break; |
245 | 0 | case COND_XOR: |
246 | 0 | if (sp < 1) |
247 | 0 | return -1; |
248 | 0 | sp--; |
249 | 0 | s[sp] ^= s[sp + 1]; |
250 | 0 | break; |
251 | 0 | case COND_EQ: |
252 | 0 | if (sp < 1) |
253 | 0 | return -1; |
254 | 0 | sp--; |
255 | 0 | s[sp] = (s[sp] == s[sp + 1]); |
256 | 0 | break; |
257 | 0 | case COND_NEQ: |
258 | 0 | if (sp < 1) |
259 | 0 | return -1; |
260 | 0 | sp--; |
261 | 0 | s[sp] = (s[sp] != s[sp + 1]); |
262 | 0 | break; |
263 | 0 | default: |
264 | 0 | return -1; |
265 | 0 | } |
266 | 0 | } |
267 | 0 | return s[0]; |
268 | 0 | } |
269 | | |
270 | | cond_expr_t *cond_copy_expr(cond_expr_t * expr) |
271 | 0 | { |
272 | 0 | cond_expr_t *cur, *head, *tail, *new_expr; |
273 | 0 | tail = head = NULL; |
274 | 0 | cur = expr; |
275 | 0 | while (cur) { |
276 | 0 | new_expr = (cond_expr_t *) malloc(sizeof(cond_expr_t)); |
277 | 0 | if (!new_expr) |
278 | 0 | goto free_head; |
279 | 0 | memset(new_expr, 0, sizeof(cond_expr_t)); |
280 | |
|
281 | 0 | new_expr->expr_type = cur->expr_type; |
282 | 0 | new_expr->boolean = cur->boolean; |
283 | |
|
284 | 0 | if (!head) |
285 | 0 | head = new_expr; |
286 | 0 | if (tail) |
287 | 0 | tail->next = new_expr; |
288 | 0 | tail = new_expr; |
289 | 0 | cur = cur->next; |
290 | 0 | } |
291 | 0 | return head; |
292 | | |
293 | 0 | free_head: |
294 | 0 | while (head) { |
295 | 0 | tail = head->next; |
296 | 0 | free(head); |
297 | 0 | head = tail; |
298 | 0 | } |
299 | 0 | return NULL; |
300 | 0 | } |
301 | | |
302 | | /* |
303 | | * evaluate_cond_node evaluates the conditional stored in |
304 | | * a cond_node_t and if the result is different than the |
305 | | * current state of the node it sets the rules in the true/false |
306 | | * list appropriately. If the result of the expression is undefined |
307 | | * all of the rules are disabled for safety. |
308 | | */ |
309 | | static int evaluate_cond_node(policydb_t * p, cond_node_t * node) |
310 | 0 | { |
311 | 0 | int new_state; |
312 | 0 | cond_av_list_t *cur; |
313 | |
|
314 | 0 | new_state = cond_evaluate_expr(p, node->expr); |
315 | 0 | if (new_state != node->cur_state) { |
316 | 0 | node->cur_state = new_state; |
317 | 0 | if (new_state == -1) |
318 | 0 | WARN(NULL, "expression result was undefined - disabling all rules."); |
319 | | /* turn the rules on or off */ |
320 | 0 | for (cur = node->true_list; cur != NULL; cur = cur->next) { |
321 | 0 | if (new_state <= 0) { |
322 | 0 | cur->node->key.specified &= ~AVTAB_ENABLED; |
323 | 0 | } else { |
324 | 0 | cur->node->key.specified |= AVTAB_ENABLED; |
325 | 0 | } |
326 | 0 | } |
327 | |
|
328 | 0 | for (cur = node->false_list; cur != NULL; cur = cur->next) { |
329 | | /* -1 or 1 */ |
330 | 0 | if (new_state) { |
331 | 0 | cur->node->key.specified &= ~AVTAB_ENABLED; |
332 | 0 | } else { |
333 | 0 | cur->node->key.specified |= AVTAB_ENABLED; |
334 | 0 | } |
335 | 0 | } |
336 | 0 | } |
337 | 0 | return 0; |
338 | 0 | } |
339 | | |
340 | | /* precompute and simplify an expression if possible. If left with !expression, change |
341 | | * to expression and switch t and f. precompute expression for expressions with limited |
342 | | * number of bools. |
343 | | */ |
344 | | int cond_normalize_expr(policydb_t * p, cond_node_t * cn) |
345 | 0 | { |
346 | 0 | cond_expr_t *ne, *e; |
347 | 0 | cond_av_list_t *tmp; |
348 | 0 | unsigned int i, j, orig_value[COND_MAX_BOOLS]; |
349 | 0 | int k; |
350 | 0 | uint32_t test = 0x0; |
351 | 0 | avrule_t *tmp2; |
352 | |
|
353 | 0 | cn->nbools = 0; |
354 | |
|
355 | 0 | memset(cn->bool_ids, 0, sizeof(cn->bool_ids)); |
356 | 0 | cn->expr_pre_comp = 0x0; |
357 | | |
358 | | /* take care of !expr case */ |
359 | 0 | ne = NULL; |
360 | 0 | e = cn->expr; |
361 | | |
362 | | /* because it's RPN look at last element */ |
363 | 0 | while (e->next != NULL) { |
364 | 0 | ne = e; |
365 | 0 | e = e->next; |
366 | 0 | } |
367 | 0 | if (e->expr_type == COND_NOT) { |
368 | 0 | if (ne) { |
369 | 0 | ne->next = NULL; |
370 | 0 | } else { /* ne should never be NULL */ |
371 | 0 | ERR(NULL, "Found expr with no bools and only a ! - this should never happen."); |
372 | 0 | return -1; |
373 | 0 | } |
374 | | /* swap the true and false lists */ |
375 | 0 | tmp = cn->true_list; |
376 | 0 | cn->true_list = cn->false_list; |
377 | 0 | cn->false_list = tmp; |
378 | 0 | tmp2 = cn->avtrue_list; |
379 | 0 | cn->avtrue_list = cn->avfalse_list; |
380 | 0 | cn->avfalse_list = tmp2; |
381 | | |
382 | | /* free the "not" node in the list */ |
383 | 0 | free(e); |
384 | 0 | } |
385 | | |
386 | | /* find all the bools in the expression */ |
387 | 0 | for (e = cn->expr; e != NULL; e = e->next) { |
388 | 0 | switch (e->expr_type) { |
389 | 0 | case COND_BOOL: |
390 | | /* see if we've already seen this bool */ |
391 | 0 | if (!bool_present(e->boolean, cn->bool_ids, cn->nbools)) { |
392 | | /* count em all but only record up to COND_MAX_BOOLS */ |
393 | 0 | if (cn->nbools < COND_MAX_BOOLS) |
394 | 0 | cn->bool_ids[cn->nbools++] = e->boolean; |
395 | 0 | else |
396 | 0 | cn->nbools++; |
397 | 0 | } |
398 | 0 | break; |
399 | 0 | default: |
400 | 0 | break; |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | | /* only precompute for exprs with <= COND_AX_BOOLS */ |
405 | 0 | if (cn->nbools <= COND_MAX_BOOLS) { |
406 | | /* save the default values for the bools so we can play with them */ |
407 | 0 | for (i = 0; i < cn->nbools; i++) { |
408 | 0 | orig_value[i] = |
409 | 0 | p->bool_val_to_struct[cn->bool_ids[i] - 1]->state; |
410 | 0 | } |
411 | | |
412 | | /* loop through all possible combinations of values for bools in expression */ |
413 | 0 | for (test = 0x0; test < (UINT32_C(1) << cn->nbools); test++) { |
414 | | /* temporarily set the value for all the bools in the |
415 | | * expression using the corr. bit in test */ |
416 | 0 | for (j = 0; j < cn->nbools; j++) { |
417 | 0 | p->bool_val_to_struct[cn->bool_ids[j] - |
418 | 0 | 1]->state = |
419 | 0 | (test & (UINT32_C(1) << j)) ? 1 : 0; |
420 | 0 | } |
421 | 0 | k = cond_evaluate_expr(p, cn->expr); |
422 | 0 | if (k == -1) { |
423 | 0 | ERR(NULL, "While testing expression, expression result " |
424 | 0 | "was undefined - this should never happen."); |
425 | 0 | return -1; |
426 | 0 | } |
427 | | /* set the bit if expression evaluates true */ |
428 | 0 | if (k) |
429 | 0 | cn->expr_pre_comp |= UINT32_C(1) << test; |
430 | 0 | } |
431 | | |
432 | | /* restore bool default values */ |
433 | 0 | for (i = 0; i < cn->nbools; i++) |
434 | 0 | p->bool_val_to_struct[cn->bool_ids[i] - 1]->state = |
435 | 0 | orig_value[i]; |
436 | 0 | } |
437 | 0 | return 0; |
438 | 0 | } |
439 | | |
440 | | int evaluate_conds(policydb_t * p) |
441 | 75 | { |
442 | 75 | int ret; |
443 | 75 | cond_node_t *cur; |
444 | | |
445 | 75 | for (cur = p->cond_list; cur != NULL; cur = cur->next) { |
446 | 0 | ret = evaluate_cond_node(p, cur); |
447 | 0 | if (ret) |
448 | 0 | return ret; |
449 | 0 | } |
450 | 75 | return 0; |
451 | 75 | } |
452 | | |
453 | | int cond_policydb_init(policydb_t * p) |
454 | 12.1k | { |
455 | 12.1k | p->bool_val_to_struct = NULL; |
456 | 12.1k | p->cond_list = NULL; |
457 | 12.1k | if (avtab_init(&p->te_cond_avtab)) |
458 | 0 | return -1; |
459 | | |
460 | 12.1k | return 0; |
461 | 12.1k | } |
462 | | |
463 | | void cond_av_list_destroy(cond_av_list_t * list) |
464 | 7.57k | { |
465 | 7.57k | cond_av_list_t *cur, *next; |
466 | 14.5k | for (cur = list; cur != NULL; cur = next) { |
467 | 6.99k | next = cur->next; |
468 | | /* the avtab_ptr_t node is destroy by the avtab */ |
469 | 6.99k | free(cur); |
470 | 6.99k | } |
471 | 7.57k | } |
472 | | |
473 | | void cond_expr_destroy(cond_expr_t * expr) |
474 | 3.48k | { |
475 | 3.48k | cond_expr_t *cur_expr, *next_expr; |
476 | | |
477 | 3.48k | if (!expr) |
478 | 3.36k | return; |
479 | | |
480 | 16.9k | for (cur_expr = expr; cur_expr != NULL; cur_expr = next_expr) { |
481 | 16.7k | next_expr = cur_expr->next; |
482 | 16.7k | free(cur_expr); |
483 | 16.7k | } |
484 | 126 | } |
485 | | |
486 | | void cond_node_destroy(cond_node_t * node) |
487 | 3.48k | { |
488 | 3.48k | if (!node) |
489 | 0 | return; |
490 | | |
491 | 3.48k | cond_expr_destroy(node->expr); |
492 | 3.48k | avrule_list_destroy(node->avtrue_list); |
493 | 3.48k | avrule_list_destroy(node->avfalse_list); |
494 | 3.48k | cond_av_list_destroy(node->true_list); |
495 | 3.48k | cond_av_list_destroy(node->false_list); |
496 | 3.48k | } |
497 | | |
498 | | void cond_list_destroy(cond_list_t * list) |
499 | 45.2k | { |
500 | 45.2k | cond_node_t *next, *cur; |
501 | | |
502 | 45.2k | if (list == NULL) |
503 | 45.0k | return; |
504 | | |
505 | 2.69k | for (cur = list; cur != NULL; cur = next) { |
506 | 2.46k | next = cur->next; |
507 | 2.46k | cond_node_destroy(cur); |
508 | 2.46k | free(cur); |
509 | 2.46k | } |
510 | 233 | } |
511 | | |
512 | | void cond_policydb_destroy(policydb_t * p) |
513 | 24.1k | { |
514 | 24.1k | if (p->bool_val_to_struct != NULL) |
515 | 5.70k | free(p->bool_val_to_struct); |
516 | 24.1k | avtab_destroy(&p->te_cond_avtab); |
517 | 24.1k | cond_list_destroy(p->cond_list); |
518 | 24.1k | } |
519 | | |
520 | | int cond_init_bool_indexes(policydb_t * p) |
521 | 5.98k | { |
522 | 5.98k | if (p->bool_val_to_struct) |
523 | 274 | free(p->bool_val_to_struct); |
524 | 5.98k | p->bool_val_to_struct = (cond_bool_datum_t **) |
525 | 5.98k | calloc(p->p_bools.nprim, sizeof(cond_bool_datum_t *)); |
526 | 5.98k | if (!p->bool_val_to_struct) |
527 | 0 | return -1; |
528 | 5.98k | return 0; |
529 | 5.98k | } |
530 | | |
531 | | int cond_destroy_bool(hashtab_key_t key, hashtab_datum_t datum, void *p |
532 | | __attribute__ ((unused))) |
533 | 629 | { |
534 | 629 | if (key) |
535 | 548 | free(key); |
536 | 629 | free(datum); |
537 | 629 | return 0; |
538 | 629 | } |
539 | | |
540 | | int cond_index_bool(hashtab_key_t key, hashtab_datum_t datum, void *datap) |
541 | 162 | { |
542 | 162 | policydb_t *p; |
543 | 162 | cond_bool_datum_t *booldatum; |
544 | | |
545 | 162 | booldatum = datum; |
546 | 162 | p = datap; |
547 | | |
548 | 162 | if (!booldatum->s.value || booldatum->s.value > p->p_bools.nprim) |
549 | 44 | return -EINVAL; |
550 | | |
551 | 118 | if (p->p_bool_val_to_name[booldatum->s.value - 1] != NULL) |
552 | 2 | return -EINVAL; |
553 | | |
554 | 116 | p->p_bool_val_to_name[booldatum->s.value - 1] = key; |
555 | 116 | p->bool_val_to_struct[booldatum->s.value - 1] = booldatum; |
556 | | |
557 | 116 | return 0; |
558 | 118 | } |
559 | | |
560 | | static int bool_isvalid(cond_bool_datum_t * b) |
561 | 604 | { |
562 | 604 | if (!(b->state == 0 || b->state == 1)) |
563 | 45 | return 0; |
564 | 559 | return 1; |
565 | 604 | } |
566 | | |
567 | | int cond_read_bool(policydb_t * p, |
568 | | hashtab_t h, |
569 | | struct policy_file *fp) |
570 | 628 | { |
571 | 628 | char *key = 0; |
572 | 628 | cond_bool_datum_t *booldatum; |
573 | 628 | uint32_t buf[3], len; |
574 | 628 | int rc; |
575 | | |
576 | 628 | booldatum = malloc(sizeof(cond_bool_datum_t)); |
577 | 628 | if (!booldatum) |
578 | 0 | return -1; |
579 | 628 | memset(booldatum, 0, sizeof(cond_bool_datum_t)); |
580 | | |
581 | 628 | rc = next_entry(buf, fp, sizeof(uint32_t) * 3); |
582 | 628 | if (rc < 0) |
583 | 24 | goto err; |
584 | | |
585 | 604 | booldatum->s.value = le32_to_cpu(buf[0]); |
586 | 604 | booldatum->state = le32_to_cpu(buf[1]); |
587 | | |
588 | 604 | if (!bool_isvalid(booldatum)) |
589 | 45 | goto err; |
590 | | |
591 | 559 | len = le32_to_cpu(buf[2]); |
592 | 559 | if (str_read(&key, fp, len)) |
593 | 12 | goto err; |
594 | | |
595 | 547 | if (p->policy_type != POLICY_KERN && |
596 | 547 | p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { |
597 | 78 | rc = next_entry(buf, fp, sizeof(uint32_t)); |
598 | 78 | if (rc < 0) |
599 | 2 | goto err; |
600 | 76 | booldatum->flags = le32_to_cpu(buf[0]); |
601 | 76 | } |
602 | | |
603 | 545 | if (hashtab_insert(h, key, booldatum)) |
604 | 1 | goto err; |
605 | | |
606 | 544 | return 0; |
607 | 84 | err: |
608 | 84 | cond_destroy_bool(key, booldatum, 0); |
609 | 84 | return -1; |
610 | 545 | } |
611 | | |
612 | | struct cond_insertf_data { |
613 | | struct policydb *p; |
614 | | cond_av_list_t *other; |
615 | | cond_av_list_t *head; |
616 | | cond_av_list_t *tail; |
617 | | }; |
618 | | |
619 | | static int cond_insertf(avtab_t * a |
620 | | __attribute__ ((unused)), avtab_key_t * k, |
621 | | avtab_datum_t * d, void *ptr) |
622 | 7.03k | { |
623 | 7.03k | struct cond_insertf_data *data = ptr; |
624 | 7.03k | struct policydb *p = data->p; |
625 | 7.03k | cond_av_list_t *other = data->other, *list, *cur; |
626 | 7.03k | avtab_ptr_t node_ptr; |
627 | 7.03k | uint8_t found; |
628 | | |
629 | | /* |
630 | | * For type rules we have to make certain there aren't any |
631 | | * conflicting rules by searching the te_avtab and the |
632 | | * cond_te_avtab. |
633 | | */ |
634 | 7.03k | if (k->specified & AVTAB_TYPE) { |
635 | 2.90k | if (avtab_search(&p->te_avtab, k)) { |
636 | 2 | WARN(NULL, "security: type rule already exists outside of a conditional."); |
637 | 2 | return -1; |
638 | 2 | } |
639 | | /* |
640 | | * If we are reading the false list other will be a pointer to |
641 | | * the true list. We can have duplicate entries if there is only |
642 | | * 1 other entry and it is in our true list. |
643 | | * |
644 | | * If we are reading the true list (other == NULL) there shouldn't |
645 | | * be any other entries. |
646 | | */ |
647 | 2.90k | if (other) { |
648 | 1.23k | node_ptr = avtab_search_node(&p->te_cond_avtab, k); |
649 | 1.23k | if (node_ptr) { |
650 | 389 | if (avtab_search_node_next |
651 | 389 | (node_ptr, k->specified)) { |
652 | 3 | ERR(NULL, "security: too many conflicting type rules."); |
653 | 3 | return -1; |
654 | 3 | } |
655 | 386 | found = 0; |
656 | 3.39k | for (cur = other; cur != NULL; cur = cur->next) { |
657 | 3.35k | if (cur->node == node_ptr) { |
658 | 352 | found = 1; |
659 | 352 | break; |
660 | 352 | } |
661 | 3.35k | } |
662 | 386 | if (!found) { |
663 | 34 | ERR(NULL, "security: conflicting type rules."); |
664 | 34 | return -1; |
665 | 34 | } |
666 | 386 | } |
667 | 1.66k | } else { |
668 | 1.66k | if (avtab_search(&p->te_cond_avtab, k)) { |
669 | 2 | ERR(NULL, "security: conflicting type rules when adding type rule for true."); |
670 | 2 | return -1; |
671 | 2 | } |
672 | 1.66k | } |
673 | 2.90k | } |
674 | | |
675 | 6.99k | node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d); |
676 | 6.99k | if (!node_ptr) { |
677 | 0 | ERR(NULL, "security: could not insert rule."); |
678 | 0 | return -1; |
679 | 0 | } |
680 | 6.99k | node_ptr->parse_context = (void *)1; |
681 | | |
682 | 6.99k | list = malloc(sizeof(cond_av_list_t)); |
683 | 6.99k | if (!list) |
684 | 0 | return -1; |
685 | 6.99k | memset(list, 0, sizeof(cond_av_list_t)); |
686 | | |
687 | 6.99k | list->node = node_ptr; |
688 | 6.99k | if (!data->head) |
689 | 1.27k | data->head = list; |
690 | 5.72k | else |
691 | 5.72k | data->tail->next = list; |
692 | 6.99k | data->tail = list; |
693 | 6.99k | return 0; |
694 | 6.99k | } |
695 | | |
696 | | static int cond_read_av_list(policydb_t * p, void *fp, |
697 | | cond_av_list_t ** ret_list, cond_av_list_t * other) |
698 | 4.10k | { |
699 | 4.10k | unsigned int i; |
700 | 4.10k | int rc; |
701 | 4.10k | uint32_t buf[1], len; |
702 | 4.10k | struct cond_insertf_data data; |
703 | | |
704 | 4.10k | *ret_list = NULL; |
705 | | |
706 | 4.10k | rc = next_entry(buf, fp, sizeof(uint32_t)); |
707 | 4.10k | if (rc < 0) |
708 | 71 | return -1; |
709 | | |
710 | 4.03k | len = le32_to_cpu(buf[0]); |
711 | 4.03k | if (len == 0) { |
712 | 2.67k | return 0; |
713 | 2.67k | } |
714 | | |
715 | 1.35k | data.p = p; |
716 | 1.35k | data.other = other; |
717 | 1.35k | data.head = NULL; |
718 | 1.35k | data.tail = NULL; |
719 | 5.52k | for (i = 0; i < len; i++) { |
720 | 4.76k | rc = avtab_read_item(fp, p->policyvers, &p->te_cond_avtab, |
721 | 4.76k | cond_insertf, &data); |
722 | 4.76k | if (rc) { |
723 | 594 | cond_av_list_destroy(data.head); |
724 | 594 | return rc; |
725 | 594 | } |
726 | | |
727 | 4.76k | } |
728 | | |
729 | 762 | *ret_list = data.head; |
730 | 762 | return 0; |
731 | 1.35k | } |
732 | | |
733 | | static int expr_isvalid(policydb_t * p, cond_expr_t * expr) |
734 | 16.8k | { |
735 | 16.8k | if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) { |
736 | 52 | WARN(NULL, "security: conditional expressions uses unknown operator."); |
737 | 52 | return 0; |
738 | 52 | } |
739 | | |
740 | 16.8k | if (expr->boolean > p->p_bools.nprim) { |
741 | 44 | WARN(NULL, "security: conditional expressions uses unknown bool."); |
742 | 44 | return 0; |
743 | 44 | } |
744 | 16.7k | return 1; |
745 | 16.8k | } |
746 | | |
747 | | static int cond_read_node(policydb_t * p, cond_node_t * node, void *fp) |
748 | 3.48k | { |
749 | 3.48k | uint32_t buf[2], i, len; |
750 | 3.48k | int rc; |
751 | 3.48k | cond_expr_t *expr = NULL, *last = NULL; |
752 | | |
753 | 3.48k | rc = next_entry(buf, fp, sizeof(uint32_t)); |
754 | 3.48k | if (rc < 0) |
755 | 128 | goto err; |
756 | | |
757 | 3.36k | node->cur_state = le32_to_cpu(buf[0]); |
758 | | |
759 | 3.36k | rc = next_entry(buf, fp, sizeof(uint32_t)); |
760 | 3.36k | if (rc < 0) |
761 | 6 | goto err; |
762 | | |
763 | | /* expr */ |
764 | 3.35k | len = le32_to_cpu(buf[0]); |
765 | | |
766 | 20.1k | for (i = 0; i < len; i++) { |
767 | 16.9k | rc = next_entry(buf, fp, sizeof(uint32_t) * 2); |
768 | 16.9k | if (rc < 0) |
769 | 61 | goto err; |
770 | | |
771 | 16.8k | expr = malloc(sizeof(cond_expr_t)); |
772 | 16.8k | if (!expr) { |
773 | 0 | goto err; |
774 | 0 | } |
775 | 16.8k | memset(expr, 0, sizeof(cond_expr_t)); |
776 | | |
777 | 16.8k | expr->expr_type = le32_to_cpu(buf[0]); |
778 | 16.8k | expr->boolean = le32_to_cpu(buf[1]); |
779 | | |
780 | 16.8k | if (!expr_isvalid(p, expr)) { |
781 | 96 | free(expr); |
782 | 96 | goto err; |
783 | 96 | } |
784 | | |
785 | 16.7k | if (i == 0) { |
786 | 126 | node->expr = expr; |
787 | 16.6k | } else { |
788 | 16.6k | last->next = expr; |
789 | 16.6k | } |
790 | 16.7k | last = expr; |
791 | 16.7k | } |
792 | | |
793 | 3.19k | if (p->policy_type == POLICY_KERN) { |
794 | 2.21k | if (cond_read_av_list(p, fp, &node->true_list, NULL) != 0) |
795 | 323 | goto err; |
796 | 1.88k | if (cond_read_av_list(p, fp, &node->false_list, node->true_list) |
797 | 1.88k | != 0) |
798 | 342 | goto err; |
799 | 1.88k | } else { |
800 | 985 | if (avrule_read_list(p, &node->avtrue_list, fp)) |
801 | 56 | goto err; |
802 | 929 | if (avrule_read_list(p, &node->avfalse_list, fp)) |
803 | 8 | goto err; |
804 | 929 | } |
805 | | |
806 | 2.46k | if (p->policy_type != POLICY_KERN && |
807 | 2.46k | p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { |
808 | 224 | rc = next_entry(buf, fp, sizeof(uint32_t)); |
809 | 224 | if (rc < 0) |
810 | 5 | goto err; |
811 | 219 | node->flags = le32_to_cpu(buf[0]); |
812 | 219 | } |
813 | | |
814 | 2.46k | return 0; |
815 | 1.02k | err: |
816 | 1.02k | cond_node_destroy(node); |
817 | 1.02k | free(node); |
818 | 1.02k | return -1; |
819 | 2.46k | } |
820 | | |
821 | | int cond_read_list(policydb_t * p, cond_list_t ** list, void *fp) |
822 | 13.8k | { |
823 | 13.8k | cond_node_t *node, *last = NULL; |
824 | 13.8k | uint32_t buf[1], i, len; |
825 | 13.8k | int rc; |
826 | | |
827 | 13.8k | rc = next_entry(buf, fp, sizeof(uint32_t)); |
828 | 13.8k | if (rc < 0) |
829 | 40 | return -1; |
830 | | |
831 | 13.7k | len = le32_to_cpu(buf[0]); |
832 | | |
833 | 13.7k | rc = avtab_alloc(&p->te_cond_avtab, p->te_avtab.nel); |
834 | 13.7k | if (rc) |
835 | 0 | goto err; |
836 | | |
837 | 16.2k | for (i = 0; i < len; i++) { |
838 | 3.48k | node = malloc(sizeof(cond_node_t)); |
839 | 3.48k | if (!node) |
840 | 0 | goto err; |
841 | 3.48k | memset(node, 0, sizeof(cond_node_t)); |
842 | | |
843 | 3.48k | if (cond_read_node(p, node, fp) != 0) |
844 | 1.02k | goto err; |
845 | | |
846 | 2.46k | if (i == 0) { |
847 | 235 | *list = node; |
848 | 2.22k | } else { |
849 | 2.22k | last->next = node; |
850 | 2.22k | } |
851 | 2.46k | last = node; |
852 | 2.46k | } |
853 | 12.7k | return 0; |
854 | 1.02k | err: |
855 | 1.02k | return -1; |
856 | 13.7k | } |
857 | | |
858 | | /* Determine whether additional permissions are granted by the conditional |
859 | | * av table, and if so, add them to the result |
860 | | */ |
861 | | void cond_compute_av(avtab_t * ctab, avtab_key_t * key, |
862 | | struct sepol_av_decision *avd) |
863 | 0 | { |
864 | 0 | avtab_ptr_t node; |
865 | |
|
866 | 0 | if (!ctab || !key || !avd) |
867 | 0 | return; |
868 | | |
869 | 0 | for (node = avtab_search_node(ctab, key); node != NULL; |
870 | 0 | node = avtab_search_node_next(node, key->specified)) { |
871 | 0 | if ((uint16_t) (AVTAB_ALLOWED | AVTAB_ENABLED) == |
872 | 0 | (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED))) |
873 | 0 | avd->allowed |= node->datum.data; |
874 | 0 | if ((uint16_t) (AVTAB_AUDITDENY | AVTAB_ENABLED) == |
875 | 0 | (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED))) |
876 | | /* Since a '0' in an auditdeny mask represents a |
877 | | * permission we do NOT want to audit (dontaudit), we use |
878 | | * the '&' operand to ensure that all '0's in the mask |
879 | | * are retained (much unlike the allow and auditallow cases). |
880 | | */ |
881 | 0 | avd->auditdeny &= node->datum.data; |
882 | 0 | if ((uint16_t) (AVTAB_AUDITALLOW | AVTAB_ENABLED) == |
883 | 0 | (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED))) |
884 | 0 | avd->auditallow |= node->datum.data; |
885 | 0 | } |
886 | 0 | return; |
887 | 0 | } |
888 | | |
889 | | avtab_datum_t *cond_av_list_search(avtab_key_t * key, |
890 | | cond_av_list_t * cond_list) |
891 | 0 | { |
892 | |
|
893 | 0 | cond_av_list_t *cur_av; |
894 | |
|
895 | 0 | for (cur_av = cond_list; cur_av != NULL; cur_av = cur_av->next) { |
896 | |
|
897 | 0 | if (cur_av->node->key.source_type == key->source_type && |
898 | 0 | cur_av->node->key.target_type == key->target_type && |
899 | 0 | cur_av->node->key.target_class == key->target_class) |
900 | | |
901 | 0 | return &cur_av->node->datum; |
902 | |
|
903 | 0 | } |
904 | 0 | return NULL; |
905 | |
|
906 | 0 | } |