Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /* Authors: Karl MacMillan <kmacmillan@tresys.com>
3 : : * Frank Mayer <mayerf@tresys.com>
4 : : *
5 : : * Copyright (C) 2003 - 2004 Tresys Technology, LLC
6 : : */
7 : :
8 : : #include <linux/kernel.h>
9 : : #include <linux/errno.h>
10 : : #include <linux/string.h>
11 : : #include <linux/spinlock.h>
12 : : #include <linux/slab.h>
13 : :
14 : : #include "security.h"
15 : : #include "conditional.h"
16 : : #include "services.h"
17 : :
18 : : /*
19 : : * cond_evaluate_expr evaluates a conditional expr
20 : : * in reverse polish notation. It returns true (1), false (0),
21 : : * or undefined (-1). Undefined occurs when the expression
22 : : * exceeds the stack depth of COND_EXPR_MAXDEPTH.
23 : : */
24 : : static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
25 : : {
26 : :
27 : : struct cond_expr *cur;
28 : : int s[COND_EXPR_MAXDEPTH];
29 : : int sp = -1;
30 : :
31 : : for (cur = expr; cur; cur = cur->next) {
32 : : switch (cur->expr_type) {
33 : : case COND_BOOL:
34 : : if (sp == (COND_EXPR_MAXDEPTH - 1))
35 : : return -1;
36 : : sp++;
37 : : s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
38 : : break;
39 : : case COND_NOT:
40 : : if (sp < 0)
41 : : return -1;
42 : : s[sp] = !s[sp];
43 : : break;
44 : : case COND_OR:
45 : : if (sp < 1)
46 : : return -1;
47 : : sp--;
48 : : s[sp] |= s[sp + 1];
49 : : break;
50 : : case COND_AND:
51 : : if (sp < 1)
52 : : return -1;
53 : : sp--;
54 : : s[sp] &= s[sp + 1];
55 : : break;
56 : : case COND_XOR:
57 : : if (sp < 1)
58 : : return -1;
59 : : sp--;
60 : : s[sp] ^= s[sp + 1];
61 : : break;
62 : : case COND_EQ:
63 : : if (sp < 1)
64 : : return -1;
65 : : sp--;
66 : : s[sp] = (s[sp] == s[sp + 1]);
67 : : break;
68 : : case COND_NEQ:
69 : : if (sp < 1)
70 : : return -1;
71 : : sp--;
72 : : s[sp] = (s[sp] != s[sp + 1]);
73 : : break;
74 : : default:
75 : : return -1;
76 : : }
77 : : }
78 : : return s[0];
79 : : }
80 : :
81 : : /*
82 : : * evaluate_cond_node evaluates the conditional stored in
83 : : * a struct cond_node and if the result is different than the
84 : : * current state of the node it sets the rules in the true/false
85 : : * list appropriately. If the result of the expression is undefined
86 : : * all of the rules are disabled for safety.
87 : : */
88 : 0 : int evaluate_cond_node(struct policydb *p, struct cond_node *node)
89 : : {
90 : 0 : int new_state;
91 : 0 : struct cond_av_list *cur;
92 : :
93 : 0 : new_state = cond_evaluate_expr(p, node->expr);
94 [ # # ]: 0 : if (new_state != node->cur_state) {
95 : 0 : node->cur_state = new_state;
96 [ # # ]: 0 : if (new_state == -1)
97 : 0 : pr_err("SELinux: expression result was undefined - disabling all rules.\n");
98 : : /* turn the rules on or off */
99 [ # # ]: 0 : for (cur = node->true_list; cur; cur = cur->next) {
100 [ # # ]: 0 : if (new_state <= 0)
101 : 0 : cur->node->key.specified &= ~AVTAB_ENABLED;
102 : : else
103 : 0 : cur->node->key.specified |= AVTAB_ENABLED;
104 : : }
105 : :
106 [ # # ]: 0 : for (cur = node->false_list; cur; cur = cur->next) {
107 : : /* -1 or 1 */
108 [ # # ]: 0 : if (new_state)
109 : 0 : cur->node->key.specified &= ~AVTAB_ENABLED;
110 : : else
111 : 0 : cur->node->key.specified |= AVTAB_ENABLED;
112 : : }
113 : : }
114 : 0 : return 0;
115 : : }
116 : :
117 : 0 : int cond_policydb_init(struct policydb *p)
118 : : {
119 : 0 : int rc;
120 : :
121 : 0 : p->bool_val_to_struct = NULL;
122 : 0 : p->cond_list = NULL;
123 : :
124 : 0 : rc = avtab_init(&p->te_cond_avtab);
125 [ # # ]: 0 : if (rc)
126 : 0 : return rc;
127 : :
128 : : return 0;
129 : : }
130 : :
131 : 0 : static void cond_av_list_destroy(struct cond_av_list *list)
132 : : {
133 : 0 : struct cond_av_list *cur, *next;
134 [ # # # # : 0 : for (cur = list; cur; cur = next) {
# # ]
135 : 0 : next = cur->next;
136 : : /* the avtab_ptr_t node is destroy by the avtab */
137 : 0 : kfree(cur);
138 : : }
139 : : }
140 : :
141 : 0 : static void cond_node_destroy(struct cond_node *node)
142 : : {
143 : 0 : struct cond_expr *cur_expr, *next_expr;
144 : :
145 [ # # ]: 0 : for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
146 : 0 : next_expr = cur_expr->next;
147 : 0 : kfree(cur_expr);
148 : : }
149 : 0 : cond_av_list_destroy(node->true_list);
150 : 0 : cond_av_list_destroy(node->false_list);
151 : 0 : kfree(node);
152 : 0 : }
153 : :
154 : 0 : static void cond_list_destroy(struct cond_node *list)
155 : : {
156 : 0 : struct cond_node *next, *cur;
157 : :
158 : 0 : if (list == NULL)
159 : : return;
160 : :
161 [ # # # # ]: 0 : for (cur = list; cur; cur = next) {
162 : 0 : next = cur->next;
163 : 0 : cond_node_destroy(cur);
164 : : }
165 : : }
166 : :
167 : 0 : void cond_policydb_destroy(struct policydb *p)
168 : : {
169 : 0 : kfree(p->bool_val_to_struct);
170 : 0 : avtab_destroy(&p->te_cond_avtab);
171 [ # # ]: 0 : cond_list_destroy(p->cond_list);
172 : 0 : }
173 : :
174 : 0 : int cond_init_bool_indexes(struct policydb *p)
175 : : {
176 : 0 : kfree(p->bool_val_to_struct);
177 : 0 : p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim,
178 : : sizeof(*p->bool_val_to_struct),
179 : : GFP_KERNEL);
180 [ # # ]: 0 : if (!p->bool_val_to_struct)
181 : 0 : return -ENOMEM;
182 : : return 0;
183 : : }
184 : :
185 : 0 : int cond_destroy_bool(void *key, void *datum, void *p)
186 : : {
187 : 0 : kfree(key);
188 : 0 : kfree(datum);
189 : 0 : return 0;
190 : : }
191 : :
192 : 0 : int cond_index_bool(void *key, void *datum, void *datap)
193 : : {
194 : 0 : struct policydb *p;
195 : 0 : struct cond_bool_datum *booldatum;
196 : :
197 : 0 : booldatum = datum;
198 : 0 : p = datap;
199 : :
200 [ # # # # ]: 0 : if (!booldatum->value || booldatum->value > p->p_bools.nprim)
201 : : return -EINVAL;
202 : :
203 : 0 : p->sym_val_to_name[SYM_BOOLS][booldatum->value - 1] = key;
204 : 0 : p->bool_val_to_struct[booldatum->value - 1] = booldatum;
205 : :
206 : 0 : return 0;
207 : : }
208 : :
209 : 0 : static int bool_isvalid(struct cond_bool_datum *b)
210 : : {
211 : 0 : if (!(b->state == 0 || b->state == 1))
212 : 0 : return 0;
213 : : return 1;
214 : : }
215 : :
216 : 0 : int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
217 : : {
218 : 0 : char *key = NULL;
219 : 0 : struct cond_bool_datum *booldatum;
220 : 0 : __le32 buf[3];
221 : 0 : u32 len;
222 : 0 : int rc;
223 : :
224 : 0 : booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL);
225 [ # # ]: 0 : if (!booldatum)
226 : : return -ENOMEM;
227 : :
228 [ # # ]: 0 : rc = next_entry(buf, fp, sizeof buf);
229 : 0 : if (rc)
230 : 0 : goto err;
231 : :
232 : 0 : booldatum->value = le32_to_cpu(buf[0]);
233 : 0 : booldatum->state = le32_to_cpu(buf[1]);
234 : :
235 : 0 : rc = -EINVAL;
236 [ # # ]: 0 : if (!bool_isvalid(booldatum))
237 : 0 : goto err;
238 : :
239 : 0 : len = le32_to_cpu(buf[2]);
240 [ # # ]: 0 : if (((len == 0) || (len == (u32)-1)))
241 : 0 : goto err;
242 : :
243 : 0 : rc = -ENOMEM;
244 [ # # ]: 0 : key = kmalloc(len + 1, GFP_KERNEL);
245 [ # # ]: 0 : if (!key)
246 : 0 : goto err;
247 [ # # ]: 0 : rc = next_entry(key, fp, len);
248 : 0 : if (rc)
249 : 0 : goto err;
250 : 0 : key[len] = '\0';
251 : 0 : rc = hashtab_insert(h, key, booldatum);
252 [ # # ]: 0 : if (rc)
253 : 0 : goto err;
254 : :
255 : : return 0;
256 : 0 : err:
257 : 0 : cond_destroy_bool(key, booldatum, NULL);
258 : 0 : return rc;
259 : : }
260 : :
261 : : struct cond_insertf_data {
262 : : struct policydb *p;
263 : : struct cond_av_list *other;
264 : : struct cond_av_list *head;
265 : : struct cond_av_list *tail;
266 : : };
267 : :
268 : 0 : static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
269 : : {
270 : 0 : struct cond_insertf_data *data = ptr;
271 : 0 : struct policydb *p = data->p;
272 : 0 : struct cond_av_list *other = data->other, *list, *cur;
273 : 0 : struct avtab_node *node_ptr;
274 : 0 : u8 found;
275 : 0 : int rc = -EINVAL;
276 : :
277 : : /*
278 : : * For type rules we have to make certain there aren't any
279 : : * conflicting rules by searching the te_avtab and the
280 : : * cond_te_avtab.
281 : : */
282 [ # # ]: 0 : if (k->specified & AVTAB_TYPE) {
283 [ # # ]: 0 : if (avtab_search(&p->te_avtab, k)) {
284 : 0 : pr_err("SELinux: type rule already exists outside of a conditional.\n");
285 : 0 : goto err;
286 : : }
287 : : /*
288 : : * If we are reading the false list other will be a pointer to
289 : : * the true list. We can have duplicate entries if there is only
290 : : * 1 other entry and it is in our true list.
291 : : *
292 : : * If we are reading the true list (other == NULL) there shouldn't
293 : : * be any other entries.
294 : : */
295 [ # # ]: 0 : if (other) {
296 : 0 : node_ptr = avtab_search_node(&p->te_cond_avtab, k);
297 [ # # ]: 0 : if (node_ptr) {
298 [ # # ]: 0 : if (avtab_search_node_next(node_ptr, k->specified)) {
299 : 0 : pr_err("SELinux: too many conflicting type rules.\n");
300 : 0 : goto err;
301 : : }
302 : : found = 0;
303 [ # # ]: 0 : for (cur = other; cur; cur = cur->next) {
304 [ # # ]: 0 : if (cur->node == node_ptr) {
305 : : found = 1;
306 : : break;
307 : : }
308 : : }
309 [ # # ]: 0 : if (!found) {
310 : 0 : pr_err("SELinux: conflicting type rules.\n");
311 : 0 : goto err;
312 : : }
313 : : }
314 : : } else {
315 [ # # ]: 0 : if (avtab_search(&p->te_cond_avtab, k)) {
316 : 0 : pr_err("SELinux: conflicting type rules when adding type rule for true.\n");
317 : 0 : goto err;
318 : : }
319 : : }
320 : : }
321 : :
322 : 0 : node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
323 [ # # ]: 0 : if (!node_ptr) {
324 : 0 : pr_err("SELinux: could not insert rule.\n");
325 : 0 : rc = -ENOMEM;
326 : 0 : goto err;
327 : : }
328 : :
329 : 0 : list = kzalloc(sizeof(*list), GFP_KERNEL);
330 [ # # ]: 0 : if (!list) {
331 : 0 : rc = -ENOMEM;
332 : 0 : goto err;
333 : : }
334 : :
335 : 0 : list->node = node_ptr;
336 [ # # ]: 0 : if (!data->head)
337 : 0 : data->head = list;
338 : : else
339 : 0 : data->tail->next = list;
340 : 0 : data->tail = list;
341 : 0 : return 0;
342 : :
343 : 0 : err:
344 : 0 : cond_av_list_destroy(data->head);
345 : 0 : data->head = NULL;
346 : 0 : return rc;
347 : : }
348 : :
349 : 0 : static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
350 : : {
351 : 0 : int i, rc;
352 : 0 : __le32 buf[1];
353 : 0 : u32 len;
354 : 0 : struct cond_insertf_data data;
355 : :
356 : 0 : *ret_list = NULL;
357 : :
358 [ # # ]: 0 : rc = next_entry(buf, fp, sizeof(u32));
359 : 0 : if (rc)
360 : : return rc;
361 : :
362 : 0 : len = le32_to_cpu(buf[0]);
363 [ # # ]: 0 : if (len == 0)
364 : : return 0;
365 : :
366 : 0 : data.p = p;
367 : 0 : data.other = other;
368 : 0 : data.head = NULL;
369 : 0 : data.tail = NULL;
370 [ # # ]: 0 : for (i = 0; i < len; i++) {
371 : 0 : rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
372 : : &data);
373 [ # # ]: 0 : if (rc)
374 : 0 : return rc;
375 : : }
376 : :
377 : 0 : *ret_list = data.head;
378 : 0 : return 0;
379 : : }
380 : :
381 : : static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
382 : : {
383 : : if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
384 : : pr_err("SELinux: conditional expressions uses unknown operator.\n");
385 : : return 0;
386 : : }
387 : :
388 : : if (expr->bool > p->p_bools.nprim) {
389 : : pr_err("SELinux: conditional expressions uses unknown bool.\n");
390 : : return 0;
391 : : }
392 : : return 1;
393 : : }
394 : :
395 : 0 : static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
396 : : {
397 : 0 : __le32 buf[2];
398 : 0 : u32 len, i;
399 : 0 : int rc;
400 : 0 : struct cond_expr *expr = NULL, *last = NULL;
401 : :
402 [ # # ]: 0 : rc = next_entry(buf, fp, sizeof(u32) * 2);
403 : 0 : if (rc)
404 : 0 : goto err;
405 : :
406 : 0 : node->cur_state = le32_to_cpu(buf[0]);
407 : :
408 : : /* expr */
409 : 0 : len = le32_to_cpu(buf[1]);
410 : :
411 [ # # ]: 0 : for (i = 0; i < len; i++) {
412 [ # # ]: 0 : rc = next_entry(buf, fp, sizeof(u32) * 2);
413 : 0 : if (rc)
414 : 0 : goto err;
415 : :
416 : 0 : rc = -ENOMEM;
417 : 0 : expr = kzalloc(sizeof(*expr), GFP_KERNEL);
418 [ # # ]: 0 : if (!expr)
419 : 0 : goto err;
420 : :
421 : 0 : expr->expr_type = le32_to_cpu(buf[0]);
422 : 0 : expr->bool = le32_to_cpu(buf[1]);
423 : :
424 [ # # ]: 0 : if (!expr_isvalid(p, expr)) {
425 : 0 : rc = -EINVAL;
426 : 0 : kfree(expr);
427 : 0 : goto err;
428 : : }
429 : :
430 [ # # ]: 0 : if (i == 0)
431 : 0 : node->expr = expr;
432 : : else
433 : 0 : last->next = expr;
434 : 0 : last = expr;
435 : : }
436 : :
437 : 0 : rc = cond_read_av_list(p, fp, &node->true_list, NULL);
438 [ # # ]: 0 : if (rc)
439 : 0 : goto err;
440 : 0 : rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
441 [ # # ]: 0 : if (rc)
442 : 0 : goto err;
443 : : return 0;
444 : 0 : err:
445 : 0 : cond_node_destroy(node);
446 : 0 : return rc;
447 : : }
448 : :
449 : 0 : int cond_read_list(struct policydb *p, void *fp)
450 : : {
451 : 0 : struct cond_node *node, *last = NULL;
452 : 0 : __le32 buf[1];
453 : 0 : u32 i, len;
454 : 0 : int rc;
455 : :
456 [ # # ]: 0 : rc = next_entry(buf, fp, sizeof buf);
457 : 0 : if (rc)
458 : : return rc;
459 : :
460 : 0 : len = le32_to_cpu(buf[0]);
461 : :
462 : 0 : rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
463 [ # # ]: 0 : if (rc)
464 : 0 : goto err;
465 : :
466 [ # # ]: 0 : for (i = 0; i < len; i++) {
467 : 0 : rc = -ENOMEM;
468 : 0 : node = kzalloc(sizeof(*node), GFP_KERNEL);
469 [ # # ]: 0 : if (!node)
470 : 0 : goto err;
471 : :
472 : 0 : rc = cond_read_node(p, node, fp);
473 [ # # ]: 0 : if (rc)
474 : 0 : goto err;
475 : :
476 [ # # ]: 0 : if (i == 0)
477 : 0 : p->cond_list = node;
478 : : else
479 : 0 : last->next = node;
480 : 0 : last = node;
481 : : }
482 : : return 0;
483 : 0 : err:
484 [ # # ]: 0 : cond_list_destroy(p->cond_list);
485 : 0 : p->cond_list = NULL;
486 : 0 : return rc;
487 : : }
488 : :
489 : 0 : int cond_write_bool(void *vkey, void *datum, void *ptr)
490 : : {
491 : 0 : char *key = vkey;
492 : 0 : struct cond_bool_datum *booldatum = datum;
493 : 0 : struct policy_data *pd = ptr;
494 : 0 : void *fp = pd->fp;
495 : 0 : __le32 buf[3];
496 : 0 : u32 len;
497 : 0 : int rc;
498 : :
499 : 0 : len = strlen(key);
500 : 0 : buf[0] = cpu_to_le32(booldatum->value);
501 : 0 : buf[1] = cpu_to_le32(booldatum->state);
502 : 0 : buf[2] = cpu_to_le32(len);
503 : 0 : rc = put_entry(buf, sizeof(u32), 3, fp);
504 : 0 : if (rc)
505 : : return rc;
506 : 0 : rc = put_entry(key, 1, len, fp);
507 : 0 : if (rc)
508 : : return rc;
509 : 0 : return 0;
510 : : }
511 : :
512 : : /*
513 : : * cond_write_cond_av_list doesn't write out the av_list nodes.
514 : : * Instead it writes out the key/value pairs from the avtab. This
515 : : * is necessary because there is no way to uniquely identifying rules
516 : : * in the avtab so it is not possible to associate individual rules
517 : : * in the avtab with a conditional without saving them as part of
518 : : * the conditional. This means that the avtab with the conditional
519 : : * rules will not be saved but will be rebuilt on policy load.
520 : : */
521 : 0 : static int cond_write_av_list(struct policydb *p,
522 : : struct cond_av_list *list, struct policy_file *fp)
523 : : {
524 : 0 : __le32 buf[1];
525 : 0 : struct cond_av_list *cur_list;
526 : 0 : u32 len;
527 : 0 : int rc;
528 : :
529 : 0 : len = 0;
530 [ # # ]: 0 : for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
531 : 0 : len++;
532 : :
533 : 0 : buf[0] = cpu_to_le32(len);
534 [ # # ]: 0 : rc = put_entry(buf, sizeof(u32), 1, fp);
535 : 0 : if (rc)
536 : : return rc;
537 : :
538 [ # # ]: 0 : if (len == 0)
539 : : return 0;
540 : :
541 [ # # ]: 0 : for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
542 : 0 : rc = avtab_write_item(p, cur_list->node, fp);
543 [ # # ]: 0 : if (rc)
544 : 0 : return rc;
545 : : }
546 : :
547 : : return 0;
548 : : }
549 : :
550 : 0 : static int cond_write_node(struct policydb *p, struct cond_node *node,
551 : : struct policy_file *fp)
552 : : {
553 : 0 : struct cond_expr *cur_expr;
554 : 0 : __le32 buf[2];
555 : 0 : int rc;
556 : 0 : u32 len = 0;
557 : :
558 : 0 : buf[0] = cpu_to_le32(node->cur_state);
559 : 0 : rc = put_entry(buf, sizeof(u32), 1, fp);
560 : 0 : if (rc)
561 : : return rc;
562 : :
563 [ # # ]: 0 : for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
564 : 0 : len++;
565 : :
566 : 0 : buf[0] = cpu_to_le32(len);
567 : 0 : rc = put_entry(buf, sizeof(u32), 1, fp);
568 : 0 : if (rc)
569 : : return rc;
570 : :
571 [ # # ]: 0 : for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
572 : 0 : buf[0] = cpu_to_le32(cur_expr->expr_type);
573 : 0 : buf[1] = cpu_to_le32(cur_expr->bool);
574 : 0 : rc = put_entry(buf, sizeof(u32), 2, fp);
575 : 0 : if (rc)
576 : : return rc;
577 : : }
578 : :
579 : 0 : rc = cond_write_av_list(p, node->true_list, fp);
580 [ # # ]: 0 : if (rc)
581 : : return rc;
582 : 0 : rc = cond_write_av_list(p, node->false_list, fp);
583 [ # # ]: 0 : if (rc)
584 : 0 : return rc;
585 : :
586 : : return 0;
587 : : }
588 : :
589 : 0 : int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
590 : : {
591 : 0 : struct cond_node *cur;
592 : 0 : u32 len;
593 : 0 : __le32 buf[1];
594 : 0 : int rc;
595 : :
596 : 0 : len = 0;
597 [ # # ]: 0 : for (cur = list; cur != NULL; cur = cur->next)
598 : 0 : len++;
599 : 0 : buf[0] = cpu_to_le32(len);
600 : 0 : rc = put_entry(buf, sizeof(u32), 1, fp);
601 : 0 : if (rc)
602 : : return rc;
603 : :
604 [ # # ]: 0 : for (cur = list; cur != NULL; cur = cur->next) {
605 : 0 : rc = cond_write_node(p, cur, fp);
606 [ # # ]: 0 : if (rc)
607 : 0 : return rc;
608 : : }
609 : :
610 : : return 0;
611 : : }
612 : :
613 : 0 : void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
614 : : struct extended_perms_decision *xpermd)
615 : : {
616 : 0 : struct avtab_node *node;
617 : :
618 [ # # # # ]: 0 : if (!ctab || !key || !xpermd)
619 : : return;
620 : :
621 [ # # ]: 0 : for (node = avtab_search_node(ctab, key); node;
622 : 0 : node = avtab_search_node_next(node, key->specified)) {
623 [ # # ]: 0 : if (node->key.specified & AVTAB_ENABLED)
624 : 0 : services_compute_xperms_decision(xpermd, node);
625 : : }
626 : : return;
627 : :
628 : : }
629 : : /* Determine whether additional permissions are granted by the conditional
630 : : * av table, and if so, add them to the result
631 : : */
632 : 0 : void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
633 : : struct av_decision *avd, struct extended_perms *xperms)
634 : : {
635 : 0 : struct avtab_node *node;
636 : :
637 [ # # # # ]: 0 : if (!ctab || !key || !avd)
638 : : return;
639 : :
640 [ # # ]: 0 : for (node = avtab_search_node(ctab, key); node;
641 : 0 : node = avtab_search_node_next(node, key->specified)) {
642 : 0 : if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
643 [ # # ]: 0 : (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
644 : 0 : avd->allowed |= node->datum.u.data;
645 : 0 : if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
646 [ # # ]: 0 : (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
647 : : /* Since a '0' in an auditdeny mask represents a
648 : : * permission we do NOT want to audit (dontaudit), we use
649 : : * the '&' operand to ensure that all '0's in the mask
650 : : * are retained (much unlike the allow and auditallow cases).
651 : : */
652 : 0 : avd->auditdeny &= node->datum.u.data;
653 : 0 : if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
654 [ # # ]: 0 : (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
655 : 0 : avd->auditallow |= node->datum.u.data;
656 [ # # # # : 0 : if (xperms && (node->key.specified & AVTAB_ENABLED) &&
# # ]
657 : : (node->key.specified & AVTAB_XPERMS))
658 : 0 : services_compute_xperms_drivers(xperms, node);
659 : : }
660 : : }
|