~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/selinux/ss/conditional.c

Version: ~ [ linux-6.0-rc1 ] ~ [ linux-5.19.1 ] ~ [ linux-5.18.17 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.60 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.136 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.210 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.255 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.290 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.325 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.302 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  */
 26 static 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  */
 90 int 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                         printk(KERN_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 
119 int 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 
133 static 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 
143 static 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 
156 static 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 
169 void 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 
176 int cond_init_bool_indexes(struct policydb *p)
177 {
178         kfree(p->bool_val_to_struct);
179         p->bool_val_to_struct =
180                 kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
181         if (!p->bool_val_to_struct)
182                 return -ENOMEM;
183         return 0;
184 }
185 
186 int cond_destroy_bool(void *key, void *datum, void *p)
187 {
188         kfree(key);
189         kfree(datum);
190         return 0;
191 }
192 
193 int cond_index_bool(void *key, void *datum, void *datap)
194 {
195         struct policydb *p;
196         struct cond_bool_datum *booldatum;
197         struct flex_array *fa;
198 
199         booldatum = datum;
200         p = datap;
201 
202         if (!booldatum->value || booldatum->value > p->p_bools.nprim)
203                 return -EINVAL;
204 
205         fa = p->sym_val_to_name[SYM_BOOLS];
206         if (flex_array_put_ptr(fa, booldatum->value - 1, key,
207                                GFP_KERNEL | __GFP_ZERO))
208                 BUG();
209         p->bool_val_to_struct[booldatum->value - 1] = booldatum;
210 
211         return 0;
212 }
213 
214 static int bool_isvalid(struct cond_bool_datum *b)
215 {
216         if (!(b->state == 0 || b->state == 1))
217                 return 0;
218         return 1;
219 }
220 
221 int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
222 {
223         char *key = NULL;
224         struct cond_bool_datum *booldatum;
225         __le32 buf[3];
226         u32 len;
227         int rc;
228 
229         booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
230         if (!booldatum)
231                 return -ENOMEM;
232 
233         rc = next_entry(buf, fp, sizeof buf);
234         if (rc)
235                 goto err;
236 
237         booldatum->value = le32_to_cpu(buf[0]);
238         booldatum->state = le32_to_cpu(buf[1]);
239 
240         rc = -EINVAL;
241         if (!bool_isvalid(booldatum))
242                 goto err;
243 
244         len = le32_to_cpu(buf[2]);
245 
246         rc = -ENOMEM;
247         key = kmalloc(len + 1, GFP_KERNEL);
248         if (!key)
249                 goto err;
250         rc = next_entry(key, fp, len);
251         if (rc)
252                 goto err;
253         key[len] = '\0';
254         rc = hashtab_insert(h, key, booldatum);
255         if (rc)
256                 goto err;
257 
258         return 0;
259 err:
260         cond_destroy_bool(key, booldatum, NULL);
261         return rc;
262 }
263 
264 struct cond_insertf_data {
265         struct policydb *p;
266         struct cond_av_list *other;
267         struct cond_av_list *head;
268         struct cond_av_list *tail;
269 };
270 
271 static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
272 {
273         struct cond_insertf_data *data = ptr;
274         struct policydb *p = data->p;
275         struct cond_av_list *other = data->other, *list, *cur;
276         struct avtab_node *node_ptr;
277         u8 found;
278         int rc = -EINVAL;
279 
280         /*
281          * For type rules we have to make certain there aren't any
282          * conflicting rules by searching the te_avtab and the
283          * cond_te_avtab.
284          */
285         if (k->specified & AVTAB_TYPE) {
286                 if (avtab_search(&p->te_avtab, k)) {
287                         printk(KERN_ERR "SELinux: type rule already exists outside of a conditional.\n");
288                         goto err;
289                 }
290                 /*
291                  * If we are reading the false list other will be a pointer to
292                  * the true list. We can have duplicate entries if there is only
293                  * 1 other entry and it is in our true list.
294                  *
295                  * If we are reading the true list (other == NULL) there shouldn't
296                  * be any other entries.
297                  */
298                 if (other) {
299                         node_ptr = avtab_search_node(&p->te_cond_avtab, k);
300                         if (node_ptr) {
301                                 if (avtab_search_node_next(node_ptr, k->specified)) {
302                                         printk(KERN_ERR "SELinux: too many conflicting type rules.\n");
303                                         goto err;
304                                 }
305                                 found = 0;
306                                 for (cur = other; cur; cur = cur->next) {
307                                         if (cur->node == node_ptr) {
308                                                 found = 1;
309                                                 break;
310                                         }
311                                 }
312                                 if (!found) {
313                                         printk(KERN_ERR "SELinux: conflicting type rules.\n");
314                                         goto err;
315                                 }
316                         }
317                 } else {
318                         if (avtab_search(&p->te_cond_avtab, k)) {
319                                 printk(KERN_ERR "SELinux: conflicting type rules when adding type rule for true.\n");
320                                 goto err;
321                         }
322                 }
323         }
324 
325         node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
326         if (!node_ptr) {
327                 printk(KERN_ERR "SELinux: could not insert rule.\n");
328                 rc = -ENOMEM;
329                 goto err;
330         }
331 
332         list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL);
333         if (!list) {
334                 rc = -ENOMEM;
335                 goto err;
336         }
337 
338         list->node = node_ptr;
339         if (!data->head)
340                 data->head = list;
341         else
342                 data->tail->next = list;
343         data->tail = list;
344         return 0;
345 
346 err:
347         cond_av_list_destroy(data->head);
348         data->head = NULL;
349         return rc;
350 }
351 
352 static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
353 {
354         int i, rc;
355         __le32 buf[1];
356         u32 len;
357         struct cond_insertf_data data;
358 
359         *ret_list = NULL;
360 
361         len = 0;
362         rc = next_entry(buf, fp, sizeof(u32));
363         if (rc)
364                 return rc;
365 
366         len = le32_to_cpu(buf[0]);
367         if (len == 0)
368                 return 0;
369 
370         data.p = p;
371         data.other = other;
372         data.head = NULL;
373         data.tail = NULL;
374         for (i = 0; i < len; i++) {
375                 rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
376                                      &data);
377                 if (rc)
378                         return rc;
379         }
380 
381         *ret_list = data.head;
382         return 0;
383 }
384 
385 static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
386 {
387         if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
388                 printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n");
389                 return 0;
390         }
391 
392         if (expr->bool > p->p_bools.nprim) {
393                 printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n");
394                 return 0;
395         }
396         return 1;
397 }
398 
399 static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
400 {
401         __le32 buf[2];
402         u32 len, i;
403         int rc;
404         struct cond_expr *expr = NULL, *last = NULL;
405 
406         rc = next_entry(buf, fp, sizeof(u32) * 2);
407         if (rc)
408                 goto err;
409 
410         node->cur_state = le32_to_cpu(buf[0]);
411 
412         /* expr */
413         len = le32_to_cpu(buf[1]);
414 
415         for (i = 0; i < len; i++) {
416                 rc = next_entry(buf, fp, sizeof(u32) * 2);
417                 if (rc)
418                         goto err;
419 
420                 rc = -ENOMEM;
421                 expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
422                 if (!expr)
423                         goto err;
424 
425                 expr->expr_type = le32_to_cpu(buf[0]);
426                 expr->bool = le32_to_cpu(buf[1]);
427 
428                 if (!expr_isvalid(p, expr)) {
429                         rc = -EINVAL;
430                         kfree(expr);
431                         goto err;
432                 }
433 
434                 if (i == 0)
435                         node->expr = expr;
436                 else
437                         last->next = expr;
438                 last = expr;
439         }
440 
441         rc = cond_read_av_list(p, fp, &node->true_list, NULL);
442         if (rc)
443                 goto err;
444         rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
445         if (rc)
446                 goto err;
447         return 0;
448 err:
449         cond_node_destroy(node);
450         return rc;
451 }
452 
453 int cond_read_list(struct policydb *p, void *fp)
454 {
455         struct cond_node *node, *last = NULL;
456         __le32 buf[1];
457         u32 i, len;
458         int rc;
459 
460         rc = next_entry(buf, fp, sizeof buf);
461         if (rc)
462                 return rc;
463 
464         len = le32_to_cpu(buf[0]);
465 
466         rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
467         if (rc)
468                 goto err;
469 
470         for (i = 0; i < len; i++) {
471                 rc = -ENOMEM;
472                 node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
473                 if (!node)
474                         goto err;
475 
476                 rc = cond_read_node(p, node, fp);
477                 if (rc)
478                         goto err;
479 
480                 if (i == 0)
481                         p->cond_list = node;
482                 else
483                         last->next = node;
484                 last = node;
485         }
486         return 0;
487 err:
488         cond_list_destroy(p->cond_list);
489         p->cond_list = NULL;
490         return rc;
491 }
492 
493 int cond_write_bool(void *vkey, void *datum, void *ptr)
494 {
495         char *key = vkey;
496         struct cond_bool_datum *booldatum = datum;
497         struct policy_data *pd = ptr;
498         void *fp = pd->fp;
499         __le32 buf[3];
500         u32 len;
501         int rc;
502 
503         len = strlen(key);
504         buf[0] = cpu_to_le32(booldatum->value);
505         buf[1] = cpu_to_le32(booldatum->state);
506         buf[2] = cpu_to_le32(len);
507         rc = put_entry(buf, sizeof(u32), 3, fp);
508         if (rc)
509                 return rc;
510         rc = put_entry(key, 1, len, fp);
511         if (rc)
512                 return rc;
513         return 0;
514 }
515 
516 /*
517  * cond_write_cond_av_list doesn't write out the av_list nodes.
518  * Instead it writes out the key/value pairs from the avtab. This
519  * is necessary because there is no way to uniquely identifying rules
520  * in the avtab so it is not possible to associate individual rules
521  * in the avtab with a conditional without saving them as part of
522  * the conditional. This means that the avtab with the conditional
523  * rules will not be saved but will be rebuilt on policy load.
524  */
525 static int cond_write_av_list(struct policydb *p,
526                               struct cond_av_list *list, struct policy_file *fp)
527 {
528         __le32 buf[1];
529         struct cond_av_list *cur_list;
530         u32 len;
531         int rc;
532 
533         len = 0;
534         for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
535                 len++;
536 
537         buf[0] = cpu_to_le32(len);
538         rc = put_entry(buf, sizeof(u32), 1, fp);
539         if (rc)
540                 return rc;
541 
542         if (len == 0)
543                 return 0;
544 
545         for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
546                 rc = avtab_write_item(p, cur_list->node, fp);
547                 if (rc)
548                         return rc;
549         }
550 
551         return 0;
552 }
553 
554 static int cond_write_node(struct policydb *p, struct cond_node *node,
555                     struct policy_file *fp)
556 {
557         struct cond_expr *cur_expr;
558         __le32 buf[2];
559         int rc;
560         u32 len = 0;
561 
562         buf[0] = cpu_to_le32(node->cur_state);
563         rc = put_entry(buf, sizeof(u32), 1, fp);
564         if (rc)
565                 return rc;
566 
567         for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
568                 len++;
569 
570         buf[0] = cpu_to_le32(len);
571         rc = put_entry(buf, sizeof(u32), 1, fp);
572         if (rc)
573                 return rc;
574 
575         for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
576                 buf[0] = cpu_to_le32(cur_expr->expr_type);
577                 buf[1] = cpu_to_le32(cur_expr->bool);
578                 rc = put_entry(buf, sizeof(u32), 2, fp);
579                 if (rc)
580                         return rc;
581         }
582 
583         rc = cond_write_av_list(p, node->true_list, fp);
584         if (rc)
585                 return rc;
586         rc = cond_write_av_list(p, node->false_list, fp);
587         if (rc)
588                 return rc;
589 
590         return 0;
591 }
592 
593 int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
594 {
595         struct cond_node *cur;
596         u32 len;
597         __le32 buf[1];
598         int rc;
599 
600         len = 0;
601         for (cur = list; cur != NULL; cur = cur->next)
602                 len++;
603         buf[0] = cpu_to_le32(len);
604         rc = put_entry(buf, sizeof(u32), 1, fp);
605         if (rc)
606                 return rc;
607 
608         for (cur = list; cur != NULL; cur = cur->next) {
609                 rc = cond_write_node(p, cur, fp);
610                 if (rc)
611                         return rc;
612         }
613 
614         return 0;
615 }
616 
617 void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
618                 struct extended_perms_decision *xpermd)
619 {
620         struct avtab_node *node;
621 
622         if (!ctab || !key || !xpermd)
623                 return;
624 
625         for (node = avtab_search_node(ctab, key); node;
626                         node = avtab_search_node_next(node, key->specified)) {
627                 if (node->key.specified & AVTAB_ENABLED)
628                         services_compute_xperms_decision(xpermd, node);
629         }
630         return;
631 
632 }
633 /* Determine whether additional permissions are granted by the conditional
634  * av table, and if so, add them to the result
635  */
636 void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
637                 struct av_decision *avd, struct extended_perms *xperms)
638 {
639         struct avtab_node *node;
640 
641         if (!ctab || !key || !avd)
642                 return;
643 
644         for (node = avtab_search_node(ctab, key); node;
645                                 node = avtab_search_node_next(node, key->specified)) {
646                 if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
647                     (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
648                         avd->allowed |= node->datum.u.data;
649                 if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
650                     (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
651                         /* Since a '' in an auditdeny mask represents a
652                          * permission we do NOT want to audit (dontaudit), we use
653                          * the '&' operand to ensure that all ''s in the mask
654                          * are retained (much unlike the allow and auditallow cases).
655                          */
656                         avd->auditdeny &= node->datum.u.data;
657                 if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
658                     (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
659                         avd->auditallow |= node->datum.u.data;
660                 if (xperms && (node->key.specified & AVTAB_ENABLED) &&
661                                 (node->key.specified & AVTAB_XPERMS))
662                         services_compute_xperms_drivers(xperms, node);
663         }
664         return;
665 }
666 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp