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