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