linux/security/selinux/ss/conditional.c
<<
>>
Prefs
   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
  19/*
  20 * cond_evaluate_expr evaluates a conditional expr
  21 * in reverse polish notation. It returns true (1), false (0),
  22 * or undefined (-1). Undefined occurs when the expression
  23 * exceeds the stack depth of COND_EXPR_MAXDEPTH.
  24 */
  25static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
  26{
  27
  28        struct cond_expr *cur;
  29        int s[COND_EXPR_MAXDEPTH];
  30        int sp = -1;
  31
  32        for (cur = expr; cur; cur = cur->next) {
  33                switch (cur->expr_type) {
  34                case COND_BOOL:
  35                        if (sp == (COND_EXPR_MAXDEPTH - 1))
  36                                return -1;
  37                        sp++;
  38                        s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
  39                        break;
  40                case COND_NOT:
  41                        if (sp < 0)
  42                                return -1;
  43                        s[sp] = !s[sp];
  44                        break;
  45                case COND_OR:
  46                        if (sp < 1)
  47                                return -1;
  48                        sp--;
  49                        s[sp] |= s[sp + 1];
  50                        break;
  51                case COND_AND:
  52                        if (sp < 1)
  53                                return -1;
  54                        sp--;
  55                        s[sp] &= s[sp + 1];
  56                        break;
  57                case COND_XOR:
  58                        if (sp < 1)
  59                                return -1;
  60                        sp--;
  61                        s[sp] ^= s[sp + 1];
  62                        break;
  63                case COND_EQ:
  64                        if (sp < 1)
  65                                return -1;
  66                        sp--;
  67                        s[sp] = (s[sp] == s[sp + 1]);
  68                        break;
  69                case COND_NEQ:
  70                        if (sp < 1)
  71                                return -1;
  72                        sp--;
  73                        s[sp] = (s[sp] != s[sp + 1]);
  74                        break;
  75                default:
  76                        return -1;
  77                }
  78        }
  79        return s[0];
  80}
  81
  82/*
  83 * evaluate_cond_node evaluates the conditional stored in
  84 * a struct cond_node and if the result is different than the
  85 * current state of the node it sets the rules in the true/false
  86 * list appropriately. If the result of the expression is undefined
  87 * all of the rules are disabled for safety.
  88 */
  89int evaluate_cond_node(struct policydb *p, struct cond_node *node)
  90{
  91        int new_state;
  92        struct cond_av_list *cur;
  93
  94        new_state = cond_evaluate_expr(p, node->expr);
  95        if (new_state != node->cur_state) {
  96                node->cur_state = new_state;
  97                if (new_state == -1)
  98                        printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n");
  99                /* turn the rules on or off */
 100                for (cur = node->true_list; cur; cur = cur->next) {
 101                        if (new_state <= 0)
 102                                cur->node->key.specified &= ~AVTAB_ENABLED;
 103                        else
 104                                cur->node->key.specified |= AVTAB_ENABLED;
 105                }
 106
 107                for (cur = node->false_list; cur; cur = cur->next) {
 108                        /* -1 or 1 */
 109                        if (new_state)
 110                                cur->node->key.specified &= ~AVTAB_ENABLED;
 111                        else
 112                                cur->node->key.specified |= AVTAB_ENABLED;
 113                }
 114        }
 115        return 0;
 116}
 117
 118int cond_policydb_init(struct policydb *p)
 119{
 120        int rc;
 121
 122        p->bool_val_to_struct = NULL;
 123        p->cond_list = NULL;
 124
 125        rc = avtab_init(&p->te_cond_avtab);
 126        if (rc)
 127                return rc;
 128
 129        return 0;
 130}
 131
 132static void cond_av_list_destroy(struct cond_av_list *list)
 133{
 134        struct cond_av_list *cur, *next;
 135        for (cur = list; cur; cur = next) {
 136                next = cur->next;
 137                /* the avtab_ptr_t node is destroy by the avtab */
 138                kfree(cur);
 139        }
 140}
 141
 142static void cond_node_destroy(struct cond_node *node)
 143{
 144        struct cond_expr *cur_expr, *next_expr;
 145
 146        for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
 147                next_expr = cur_expr->next;
 148                kfree(cur_expr);
 149        }
 150        cond_av_list_destroy(node->true_list);
 151        cond_av_list_destroy(node->false_list);
 152        kfree(node);
 153}
 154
 155static void cond_list_destroy(struct cond_node *list)
 156{
 157        struct cond_node *next, *cur;
 158
 159        if (list == NULL)
 160                return;
 161
 162        for (cur = list; cur; cur = next) {
 163                next = cur->next;
 164                cond_node_destroy(cur);
 165        }
 166}
 167
 168void cond_policydb_destroy(struct policydb *p)
 169{
 170        kfree(p->bool_val_to_struct);
 171        avtab_destroy(&p->te_cond_avtab);
 172        cond_list_destroy(p->cond_list);
 173}
 174
 175int cond_init_bool_indexes(struct policydb *p)
 176{
 177        kfree(p->bool_val_to_struct);
 178        p->bool_val_to_struct = (struct cond_bool_datum **)
 179                kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), 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        struct flex_array *fa;
 197
 198        booldatum = datum;
 199        p = datap;
 200
 201        if (!booldatum->value || booldatum->value > p->p_bools.nprim)
 202                return -EINVAL;
 203
 204        fa = p->sym_val_to_name[SYM_BOOLS];
 205        if (flex_array_put_ptr(fa, booldatum->value - 1, key,
 206                               GFP_KERNEL | __GFP_ZERO))
 207                BUG();
 208        p->bool_val_to_struct[booldatum->value - 1] = booldatum;
 209
 210        return 0;
 211}
 212
 213static int bool_isvalid(struct cond_bool_datum *b)
 214{
 215        if (!(b->state == 0 || b->state == 1))
 216                return 0;
 217        return 1;
 218}
 219
 220int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
 221{
 222        char *key = NULL;
 223        struct cond_bool_datum *booldatum;
 224        __le32 buf[3];
 225        u32 len;
 226        int rc;
 227
 228        booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
 229        if (!booldatum)
 230                return -ENOMEM;
 231
 232        rc = next_entry(buf, fp, sizeof buf);
 233        if (rc)
 234                goto err;
 235
 236        booldatum->value = le32_to_cpu(buf[0]);
 237        booldatum->state = le32_to_cpu(buf[1]);
 238
 239        rc = -EINVAL;
 240        if (!bool_isvalid(booldatum))
 241                goto err;
 242
 243        len = le32_to_cpu(buf[2]);
 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                        printk(KERN_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                                        printk(KERN_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                                        printk(KERN_ERR "SELinux: conflicting type rules.\n");
 313                                        goto err;
 314                                }
 315                        }
 316                } else {
 317                        if (avtab_search(&p->te_cond_avtab, k)) {
 318                                printk(KERN_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                printk(KERN_ERR "SELinux: could not insert rule.\n");
 327                rc = -ENOMEM;
 328                goto err;
 329        }
 330
 331        list = kzalloc(sizeof(struct cond_av_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        len = 0;
 361        rc = next_entry(buf, fp, sizeof(u32));
 362        if (rc)
 363                return rc;
 364
 365        len = le32_to_cpu(buf[0]);
 366        if (len == 0)
 367                return 0;
 368
 369        data.p = p;
 370        data.other = other;
 371        data.head = NULL;
 372        data.tail = NULL;
 373        for (i = 0; i < len; i++) {
 374                rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
 375                                     &data);
 376                if (rc)
 377                        return rc;
 378        }
 379
 380        *ret_list = data.head;
 381        return 0;
 382}
 383
 384static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
 385{
 386        if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
 387                printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n");
 388                return 0;
 389        }
 390
 391        if (expr->bool > p->p_bools.nprim) {
 392                printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n");
 393                return 0;
 394        }
 395        return 1;
 396}
 397
 398static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
 399{
 400        __le32 buf[2];
 401        u32 len, i;
 402        int rc;
 403        struct cond_expr *expr = NULL, *last = NULL;
 404
 405        rc = next_entry(buf, fp, sizeof(u32));
 406        if (rc)
 407                return rc;
 408
 409        node->cur_state = le32_to_cpu(buf[0]);
 410
 411        len = 0;
 412        rc = next_entry(buf, fp, sizeof(u32));
 413        if (rc)
 414                return rc;
 415
 416        /* expr */
 417        len = le32_to_cpu(buf[0]);
 418
 419        for (i = 0; i < len; i++) {
 420                rc = next_entry(buf, fp, sizeof(u32) * 2);
 421                if (rc)
 422                        goto err;
 423
 424                rc = -ENOMEM;
 425                expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
 426                if (!expr)
 427                        goto err;
 428
 429                expr->expr_type = le32_to_cpu(buf[0]);
 430                expr->bool = le32_to_cpu(buf[1]);
 431
 432                if (!expr_isvalid(p, expr)) {
 433                        rc = -EINVAL;
 434                        kfree(expr);
 435                        goto err;
 436                }
 437
 438                if (i == 0)
 439                        node->expr = expr;
 440                else
 441                        last->next = expr;
 442                last = expr;
 443        }
 444
 445        rc = cond_read_av_list(p, fp, &node->true_list, NULL);
 446        if (rc)
 447                goto err;
 448        rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
 449        if (rc)
 450                goto err;
 451        return 0;
 452err:
 453        cond_node_destroy(node);
 454        return rc;
 455}
 456
 457int cond_read_list(struct policydb *p, void *fp)
 458{
 459        struct cond_node *node, *last = NULL;
 460        __le32 buf[1];
 461        u32 i, len;
 462        int rc;
 463
 464        rc = next_entry(buf, fp, sizeof buf);
 465        if (rc)
 466                return rc;
 467
 468        len = le32_to_cpu(buf[0]);
 469
 470        rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
 471        if (rc)
 472                goto err;
 473
 474        for (i = 0; i < len; i++) {
 475                rc = -ENOMEM;
 476                node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
 477                if (!node)
 478                        goto err;
 479
 480                rc = cond_read_node(p, node, fp);
 481                if (rc)
 482                        goto err;
 483
 484                if (i == 0)
 485                        p->cond_list = node;
 486                else
 487                        last->next = node;
 488                last = node;
 489        }
 490        return 0;
 491err:
 492        cond_list_destroy(p->cond_list);
 493        p->cond_list = NULL;
 494        return rc;
 495}
 496
 497int cond_write_bool(void *vkey, void *datum, void *ptr)
 498{
 499        char *key = vkey;
 500        struct cond_bool_datum *booldatum = datum;
 501        struct policy_data *pd = ptr;
 502        void *fp = pd->fp;
 503        __le32 buf[3];
 504        u32 len;
 505        int rc;
 506
 507        len = strlen(key);
 508        buf[0] = cpu_to_le32(booldatum->value);
 509        buf[1] = cpu_to_le32(booldatum->state);
 510        buf[2] = cpu_to_le32(len);
 511        rc = put_entry(buf, sizeof(u32), 3, fp);
 512        if (rc)
 513                return rc;
 514        rc = put_entry(key, 1, len, fp);
 515        if (rc)
 516                return rc;
 517        return 0;
 518}
 519
 520/*
 521 * cond_write_cond_av_list doesn't write out the av_list nodes.
 522 * Instead it writes out the key/value pairs from the avtab. This
 523 * is necessary because there is no way to uniquely identifying rules
 524 * in the avtab so it is not possible to associate individual rules
 525 * in the avtab with a conditional without saving them as part of
 526 * the conditional. This means that the avtab with the conditional
 527 * rules will not be saved but will be rebuilt on policy load.
 528 */
 529static int cond_write_av_list(struct policydb *p,
 530                              struct cond_av_list *list, struct policy_file *fp)
 531{
 532        __le32 buf[1];
 533        struct cond_av_list *cur_list;
 534        u32 len;
 535        int rc;
 536
 537        len = 0;
 538        for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
 539                len++;
 540
 541        buf[0] = cpu_to_le32(len);
 542        rc = put_entry(buf, sizeof(u32), 1, fp);
 543        if (rc)
 544                return rc;
 545
 546        if (len == 0)
 547                return 0;
 548
 549        for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
 550                rc = avtab_write_item(p, cur_list->node, fp);
 551                if (rc)
 552                        return rc;
 553        }
 554
 555        return 0;
 556}
 557
 558static int cond_write_node(struct policydb *p, struct cond_node *node,
 559                    struct policy_file *fp)
 560{
 561        struct cond_expr *cur_expr;
 562        __le32 buf[2];
 563        int rc;
 564        u32 len = 0;
 565
 566        buf[0] = cpu_to_le32(node->cur_state);
 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                len++;
 573
 574        buf[0] = cpu_to_le32(len);
 575        rc = put_entry(buf, sizeof(u32), 1, fp);
 576        if (rc)
 577                return rc;
 578
 579        for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
 580                buf[0] = cpu_to_le32(cur_expr->expr_type);
 581                buf[1] = cpu_to_le32(cur_expr->bool);
 582                rc = put_entry(buf, sizeof(u32), 2, fp);
 583                if (rc)
 584                        return rc;
 585        }
 586
 587        rc = cond_write_av_list(p, node->true_list, fp);
 588        if (rc)
 589                return rc;
 590        rc = cond_write_av_list(p, node->false_list, fp);
 591        if (rc)
 592                return rc;
 593
 594        return 0;
 595}
 596
 597int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
 598{
 599        struct cond_node *cur;
 600        u32 len;
 601        __le32 buf[1];
 602        int rc;
 603
 604        len = 0;
 605        for (cur = list; cur != NULL; cur = cur->next)
 606                len++;
 607        buf[0] = cpu_to_le32(len);
 608        rc = put_entry(buf, sizeof(u32), 1, fp);
 609        if (rc)
 610                return rc;
 611
 612        for (cur = list; cur != NULL; cur = cur->next) {
 613                rc = cond_write_node(p, cur, fp);
 614                if (rc)
 615                        return rc;
 616        }
 617
 618        return 0;
 619}
 620/* Determine whether additional permissions are granted by the conditional
 621 * av table, and if so, add them to the result
 622 */
 623void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd)
 624{
 625        struct avtab_node *node;
 626
 627        if (!ctab || !key || !avd)
 628                return;
 629
 630        for (node = avtab_search_node(ctab, key); node;
 631                                node = avtab_search_node_next(node, key->specified)) {
 632                if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
 633                    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
 634                        avd->allowed |= node->datum.data;
 635                if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
 636                    (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
 637                        /* Since a '0' in an auditdeny mask represents a
 638                         * permission we do NOT want to audit (dontaudit), we use
 639                         * the '&' operand to ensure that all '0's in the mask
 640                         * are retained (much unlike the allow and auditallow cases).
 641                         */
 642                        avd->auditdeny &= node->datum.data;
 643                if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
 644                    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
 645                        avd->auditallow |= node->datum.data;
 646        }
 647        return;
 648}
 649