linux/security/selinux/ss/conditional.c
<<
>>
Prefs
   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 */
  24static 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 */
  88int 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
 117int 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
 131static 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
 141static 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
 154static 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
 167void 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
 174int 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
 185int cond_destroy_bool(void *key, void *datum, void *p)
 186{
 187        kfree(key);
 188        kfree(datum);
 189        return 0;
 190}
 191
 192int 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
 209static 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
 216int 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;
 256err:
 257        cond_destroy_bool(key, booldatum, NULL);
 258        return rc;
 259}
 260
 261struct 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
 268static 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
 343err:
 344        cond_av_list_destroy(data->head);
 345        data->head = NULL;
 346        return rc;
 347}
 348
 349static 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
 381static 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
 395static 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;
 444err:
 445        cond_node_destroy(node);
 446        return rc;
 447}
 448
 449int 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;
 483err:
 484        cond_list_destroy(p->cond_list);
 485        p->cond_list = NULL;
 486        return rc;
 487}
 488
 489int 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 */
 521static 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
 550static 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
 589int 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
 613void 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 */
 632void 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}
 661