root/security/selinux/ss/conditional.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cond_evaluate_expr
  2. evaluate_cond_node
  3. cond_policydb_init
  4. cond_av_list_destroy
  5. cond_node_destroy
  6. cond_list_destroy
  7. cond_policydb_destroy
  8. cond_init_bool_indexes
  9. cond_destroy_bool
  10. cond_index_bool
  11. bool_isvalid
  12. cond_read_bool
  13. cond_insertf
  14. cond_read_av_list
  15. expr_isvalid
  16. cond_read_node
  17. cond_read_list
  18. cond_write_bool
  19. cond_write_av_list
  20. cond_write_node
  21. cond_write_list
  22. cond_compute_xperms
  23. cond_compute_av

   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 int evaluate_cond_node(struct policydb *p, struct cond_node *node)
  89 {
  90         int new_state;
  91         struct cond_av_list *cur;
  92 
  93         new_state = cond_evaluate_expr(p, node->expr);
  94         if (new_state != node->cur_state) {
  95                 node->cur_state = new_state;
  96                 if (new_state == -1)
  97                         pr_err("SELinux: expression result was undefined - disabling all rules.\n");
  98                 /* turn the rules on or off */
  99                 for (cur = node->true_list; cur; cur = cur->next) {
 100                         if (new_state <= 0)
 101                                 cur->node->key.specified &= ~AVTAB_ENABLED;
 102                         else
 103                                 cur->node->key.specified |= AVTAB_ENABLED;
 104                 }
 105 
 106                 for (cur = node->false_list; cur; cur = cur->next) {
 107                         /* -1 or 1 */
 108                         if (new_state)
 109                                 cur->node->key.specified &= ~AVTAB_ENABLED;
 110                         else
 111                                 cur->node->key.specified |= AVTAB_ENABLED;
 112                 }
 113         }
 114         return 0;
 115 }
 116 
 117 int cond_policydb_init(struct policydb *p)
 118 {
 119         int rc;
 120 
 121         p->bool_val_to_struct = NULL;
 122         p->cond_list = NULL;
 123 
 124         rc = avtab_init(&p->te_cond_avtab);
 125         if (rc)
 126                 return rc;
 127 
 128         return 0;
 129 }
 130 
 131 static void cond_av_list_destroy(struct cond_av_list *list)
 132 {
 133         struct cond_av_list *cur, *next;
 134         for (cur = list; cur; cur = next) {
 135                 next = cur->next;
 136                 /* the avtab_ptr_t node is destroy by the avtab */
 137                 kfree(cur);
 138         }
 139 }
 140 
 141 static void cond_node_destroy(struct cond_node *node)
 142 {
 143         struct cond_expr *cur_expr, *next_expr;
 144 
 145         for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
 146                 next_expr = cur_expr->next;
 147                 kfree(cur_expr);
 148         }
 149         cond_av_list_destroy(node->true_list);
 150         cond_av_list_destroy(node->false_list);
 151         kfree(node);
 152 }
 153 
 154 static void cond_list_destroy(struct cond_node *list)
 155 {
 156         struct cond_node *next, *cur;
 157 
 158         if (list == NULL)
 159                 return;
 160 
 161         for (cur = list; cur; cur = next) {
 162                 next = cur->next;
 163                 cond_node_destroy(cur);
 164         }
 165 }
 166 
 167 void cond_policydb_destroy(struct policydb *p)
 168 {
 169         kfree(p->bool_val_to_struct);
 170         avtab_destroy(&p->te_cond_avtab);
 171         cond_list_destroy(p->cond_list);
 172 }
 173 
 174 int cond_init_bool_indexes(struct policydb *p)
 175 {
 176         kfree(p->bool_val_to_struct);
 177         p->bool_val_to_struct = kmalloc_array(p->p_bools.nprim,
 178                                               sizeof(*p->bool_val_to_struct),
 179                                               GFP_KERNEL);
 180         if (!p->bool_val_to_struct)
 181                 return -ENOMEM;
 182         return 0;
 183 }
 184 
 185 int cond_destroy_bool(void *key, void *datum, void *p)
 186 {
 187         kfree(key);
 188         kfree(datum);
 189         return 0;
 190 }
 191 
 192 int cond_index_bool(void *key, void *datum, void *datap)
 193 {
 194         struct policydb *p;
 195         struct cond_bool_datum *booldatum;
 196 
 197         booldatum = datum;
 198         p = datap;
 199 
 200         if (!booldatum->value || booldatum->value > p->p_bools.nprim)
 201                 return -EINVAL;
 202 
 203         p->sym_val_to_name[SYM_BOOLS][booldatum->value - 1] = key;
 204         p->bool_val_to_struct[booldatum->value - 1] = booldatum;
 205 
 206         return 0;
 207 }
 208 
 209 static int bool_isvalid(struct cond_bool_datum *b)
 210 {
 211         if (!(b->state == 0 || b->state == 1))
 212                 return 0;
 213         return 1;
 214 }
 215 
 216 int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
 217 {
 218         char *key = NULL;
 219         struct cond_bool_datum *booldatum;
 220         __le32 buf[3];
 221         u32 len;
 222         int rc;
 223 
 224         booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL);
 225         if (!booldatum)
 226                 return -ENOMEM;
 227 
 228         rc = next_entry(buf, fp, sizeof buf);
 229         if (rc)
 230                 goto err;
 231 
 232         booldatum->value = le32_to_cpu(buf[0]);
 233         booldatum->state = le32_to_cpu(buf[1]);
 234 
 235         rc = -EINVAL;
 236         if (!bool_isvalid(booldatum))
 237                 goto err;
 238 
 239         len = le32_to_cpu(buf[2]);
 240         if (((len == 0) || (len == (u32)-1)))
 241                 goto err;
 242 
 243         rc = -ENOMEM;
 244         key = kmalloc(len + 1, GFP_KERNEL);
 245         if (!key)
 246                 goto err;
 247         rc = next_entry(key, fp, len);
 248         if (rc)
 249                 goto err;
 250         key[len] = '\0';
 251         rc = hashtab_insert(h, key, booldatum);
 252         if (rc)
 253                 goto err;
 254 
 255         return 0;
 256 err:
 257         cond_destroy_bool(key, booldatum, NULL);
 258         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 static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
 269 {
 270         struct cond_insertf_data *data = ptr;
 271         struct policydb *p = data->p;
 272         struct cond_av_list *other = data->other, *list, *cur;
 273         struct avtab_node *node_ptr;
 274         u8 found;
 275         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         if (k->specified & AVTAB_TYPE) {
 283                 if (avtab_search(&p->te_avtab, k)) {
 284                         pr_err("SELinux: type rule already exists outside of a conditional.\n");
 285                         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                 if (other) {
 296                         node_ptr = avtab_search_node(&p->te_cond_avtab, k);
 297                         if (node_ptr) {
 298                                 if (avtab_search_node_next(node_ptr, k->specified)) {
 299                                         pr_err("SELinux: too many conflicting type rules.\n");
 300                                         goto err;
 301                                 }
 302                                 found = 0;
 303                                 for (cur = other; cur; cur = cur->next) {
 304                                         if (cur->node == node_ptr) {
 305                                                 found = 1;
 306                                                 break;
 307                                         }
 308                                 }
 309                                 if (!found) {
 310                                         pr_err("SELinux: conflicting type rules.\n");
 311                                         goto err;
 312                                 }
 313                         }
 314                 } else {
 315                         if (avtab_search(&p->te_cond_avtab, k)) {
 316                                 pr_err("SELinux: conflicting type rules when adding type rule for true.\n");
 317                                 goto err;
 318                         }
 319                 }
 320         }
 321 
 322         node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
 323         if (!node_ptr) {
 324                 pr_err("SELinux: could not insert rule.\n");
 325                 rc = -ENOMEM;
 326                 goto err;
 327         }
 328 
 329         list = kzalloc(sizeof(*list), GFP_KERNEL);
 330         if (!list) {
 331                 rc = -ENOMEM;
 332                 goto err;
 333         }
 334 
 335         list->node = node_ptr;
 336         if (!data->head)
 337                 data->head = list;
 338         else
 339                 data->tail->next = list;
 340         data->tail = list;
 341         return 0;
 342 
 343 err:
 344         cond_av_list_destroy(data->head);
 345         data->head = NULL;
 346         return rc;
 347 }
 348 
 349 static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
 350 {
 351         int i, rc;
 352         __le32 buf[1];
 353         u32 len;
 354         struct cond_insertf_data data;
 355 
 356         *ret_list = NULL;
 357 
 358         rc = next_entry(buf, fp, sizeof(u32));
 359         if (rc)
 360                 return rc;
 361 
 362         len = le32_to_cpu(buf[0]);
 363         if (len == 0)
 364                 return 0;
 365 
 366         data.p = p;
 367         data.other = other;
 368         data.head = NULL;
 369         data.tail = NULL;
 370         for (i = 0; i < len; i++) {
 371                 rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
 372                                      &data);
 373                 if (rc)
 374                         return rc;
 375         }
 376 
 377         *ret_list = data.head;
 378         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 static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
 396 {
 397         __le32 buf[2];
 398         u32 len, i;
 399         int rc;
 400         struct cond_expr *expr = NULL, *last = NULL;
 401 
 402         rc = next_entry(buf, fp, sizeof(u32) * 2);
 403         if (rc)
 404                 goto err;
 405 
 406         node->cur_state = le32_to_cpu(buf[0]);
 407 
 408         /* expr */
 409         len = le32_to_cpu(buf[1]);
 410 
 411         for (i = 0; i < len; i++) {
 412                 rc = next_entry(buf, fp, sizeof(u32) * 2);
 413                 if (rc)
 414                         goto err;
 415 
 416                 rc = -ENOMEM;
 417                 expr = kzalloc(sizeof(*expr), GFP_KERNEL);
 418                 if (!expr)
 419                         goto err;
 420 
 421                 expr->expr_type = le32_to_cpu(buf[0]);
 422                 expr->bool = le32_to_cpu(buf[1]);
 423 
 424                 if (!expr_isvalid(p, expr)) {
 425                         rc = -EINVAL;
 426                         kfree(expr);
 427                         goto err;
 428                 }
 429 
 430                 if (i == 0)
 431                         node->expr = expr;
 432                 else
 433                         last->next = expr;
 434                 last = expr;
 435         }
 436 
 437         rc = cond_read_av_list(p, fp, &node->true_list, NULL);
 438         if (rc)
 439                 goto err;
 440         rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
 441         if (rc)
 442                 goto err;
 443         return 0;
 444 err:
 445         cond_node_destroy(node);
 446         return rc;
 447 }
 448 
 449 int cond_read_list(struct policydb *p, void *fp)
 450 {
 451         struct cond_node *node, *last = NULL;
 452         __le32 buf[1];
 453         u32 i, len;
 454         int rc;
 455 
 456         rc = next_entry(buf, fp, sizeof buf);
 457         if (rc)
 458                 return rc;
 459 
 460         len = le32_to_cpu(buf[0]);
 461 
 462         rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
 463         if (rc)
 464                 goto err;
 465 
 466         for (i = 0; i < len; i++) {
 467                 rc = -ENOMEM;
 468                 node = kzalloc(sizeof(*node), GFP_KERNEL);
 469                 if (!node)
 470                         goto err;
 471 
 472                 rc = cond_read_node(p, node, fp);
 473                 if (rc)
 474                         goto err;
 475 
 476                 if (i == 0)
 477                         p->cond_list = node;
 478                 else
 479                         last->next = node;
 480                 last = node;
 481         }
 482         return 0;
 483 err:
 484         cond_list_destroy(p->cond_list);
 485         p->cond_list = NULL;
 486         return rc;
 487 }
 488 
 489 int cond_write_bool(void *vkey, void *datum, void *ptr)
 490 {
 491         char *key = vkey;
 492         struct cond_bool_datum *booldatum = datum;
 493         struct policy_data *pd = ptr;
 494         void *fp = pd->fp;
 495         __le32 buf[3];
 496         u32 len;
 497         int rc;
 498 
 499         len = strlen(key);
 500         buf[0] = cpu_to_le32(booldatum->value);
 501         buf[1] = cpu_to_le32(booldatum->state);
 502         buf[2] = cpu_to_le32(len);
 503         rc = put_entry(buf, sizeof(u32), 3, fp);
 504         if (rc)
 505                 return rc;
 506         rc = put_entry(key, 1, len, fp);
 507         if (rc)
 508                 return rc;
 509         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 static int cond_write_av_list(struct policydb *p,
 522                               struct cond_av_list *list, struct policy_file *fp)
 523 {
 524         __le32 buf[1];
 525         struct cond_av_list *cur_list;
 526         u32 len;
 527         int rc;
 528 
 529         len = 0;
 530         for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
 531                 len++;
 532 
 533         buf[0] = cpu_to_le32(len);
 534         rc = put_entry(buf, sizeof(u32), 1, fp);
 535         if (rc)
 536                 return rc;
 537 
 538         if (len == 0)
 539                 return 0;
 540 
 541         for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
 542                 rc = avtab_write_item(p, cur_list->node, fp);
 543                 if (rc)
 544                         return rc;
 545         }
 546 
 547         return 0;
 548 }
 549 
 550 static int cond_write_node(struct policydb *p, struct cond_node *node,
 551                     struct policy_file *fp)
 552 {
 553         struct cond_expr *cur_expr;
 554         __le32 buf[2];
 555         int rc;
 556         u32 len = 0;
 557 
 558         buf[0] = cpu_to_le32(node->cur_state);
 559         rc = put_entry(buf, sizeof(u32), 1, fp);
 560         if (rc)
 561                 return rc;
 562 
 563         for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
 564                 len++;
 565 
 566         buf[0] = cpu_to_le32(len);
 567         rc = put_entry(buf, sizeof(u32), 1, fp);
 568         if (rc)
 569                 return rc;
 570 
 571         for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
 572                 buf[0] = cpu_to_le32(cur_expr->expr_type);
 573                 buf[1] = cpu_to_le32(cur_expr->bool);
 574                 rc = put_entry(buf, sizeof(u32), 2, fp);
 575                 if (rc)
 576                         return rc;
 577         }
 578 
 579         rc = cond_write_av_list(p, node->true_list, fp);
 580         if (rc)
 581                 return rc;
 582         rc = cond_write_av_list(p, node->false_list, fp);
 583         if (rc)
 584                 return rc;
 585 
 586         return 0;
 587 }
 588 
 589 int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
 590 {
 591         struct cond_node *cur;
 592         u32 len;
 593         __le32 buf[1];
 594         int rc;
 595 
 596         len = 0;
 597         for (cur = list; cur != NULL; cur = cur->next)
 598                 len++;
 599         buf[0] = cpu_to_le32(len);
 600         rc = put_entry(buf, sizeof(u32), 1, fp);
 601         if (rc)
 602                 return rc;
 603 
 604         for (cur = list; cur != NULL; cur = cur->next) {
 605                 rc = cond_write_node(p, cur, fp);
 606                 if (rc)
 607                         return rc;
 608         }
 609 
 610         return 0;
 611 }
 612 
 613 void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
 614                 struct extended_perms_decision *xpermd)
 615 {
 616         struct avtab_node *node;
 617 
 618         if (!ctab || !key || !xpermd)
 619                 return;
 620 
 621         for (node = avtab_search_node(ctab, key); node;
 622                         node = avtab_search_node_next(node, key->specified)) {
 623                 if (node->key.specified & AVTAB_ENABLED)
 624                         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 void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
 633                 struct av_decision *avd, struct extended_perms *xperms)
 634 {
 635         struct avtab_node *node;
 636 
 637         if (!ctab || !key || !avd)
 638                 return;
 639 
 640         for (node = avtab_search_node(ctab, key); node;
 641                                 node = avtab_search_node_next(node, key->specified)) {
 642                 if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
 643                     (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
 644                         avd->allowed |= node->datum.u.data;
 645                 if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
 646                     (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                         avd->auditdeny &= node->datum.u.data;
 653                 if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
 654                     (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
 655                         avd->auditallow |= node->datum.u.data;
 656                 if (xperms && (node->key.specified & AVTAB_ENABLED) &&
 657                                 (node->key.specified & AVTAB_XPERMS))
 658                         services_compute_xperms_drivers(xperms, node);
 659         }
 660 }

/* [<][>][^][v][top][bottom][index][help] */