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                        printk(KERN_ERR "SELinux: expression result was undefined - disabling all rules.\n");
 100                /* turn the rules on or off */
 101                for (cur = node->true_list; cur; cur = cur->next) {
 102                        if (new_state <= 0)
 103                                cur->node->key.specified &= ~AVTAB_ENABLED;
 104                        else
 105                                cur->node->key.specified |= AVTAB_ENABLED;
 106                }
 107
 108                for (cur = node->false_list; cur; cur = cur->next) {
 109                        /* -1 or 1 */
 110                        if (new_state)
 111                                cur->node->key.specified &= ~AVTAB_ENABLED;
 112                        else
 113                                cur->node->key.specified |= AVTAB_ENABLED;
 114                }
 115        }
 116        return 0;
 117}
 118
 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                        printk(KERN_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                                        printk(KERN_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                                        printk(KERN_ERR "SELinux: conflicting type rules.\n");
 317                                        goto err;
 318                                }
 319                        }
 320                } else {
 321                        if (avtab_search(&p->te_cond_avtab, k)) {
 322                                printk(KERN_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                printk(KERN_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        len = 0;
 365        rc = next_entry(buf, fp, sizeof(u32));
 366        if (rc)
 367                return rc;
 368
 369        len = le32_to_cpu(buf[0]);
 370        if (len == 0)
 371                return 0;
 372
 373        data.p = p;
 374        data.other = other;
 375        data.head = NULL;
 376        data.tail = NULL;
 377        for (i = 0; i < len; i++) {
 378                rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
 379                                     &data);
 380                if (rc)
 381                        return rc;
 382        }
 383
 384        *ret_list = data.head;
 385        return 0;
 386}
 387
 388static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
 389{
 390        if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
 391                printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n");
 392                return 0;
 393        }
 394
 395        if (expr->bool > p->p_bools.nprim) {
 396                printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n");
 397                return 0;
 398        }
 399        return 1;
 400}
 401
 402static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
 403{
 404        __le32 buf[2];
 405        u32 len, i;
 406        int rc;
 407        struct cond_expr *expr = NULL, *last = NULL;
 408
 409        rc = next_entry(buf, fp, sizeof(u32) * 2);
 410        if (rc)
 411                goto err;
 412
 413        node->cur_state = le32_to_cpu(buf[0]);
 414
 415        /* expr */
 416        len = le32_to_cpu(buf[1]);
 417
 418        for (i = 0; i < len; i++) {
 419                rc = next_entry(buf, fp, sizeof(u32) * 2);
 420                if (rc)
 421                        goto err;
 422
 423                rc = -ENOMEM;
 424                expr = kzalloc(sizeof(*expr), GFP_KERNEL);
 425                if (!expr)
 426                        goto err;
 427
 428                expr->expr_type = le32_to_cpu(buf[0]);
 429                expr->bool = le32_to_cpu(buf[1]);
 430
 431                if (!expr_isvalid(p, expr)) {
 432                        rc = -EINVAL;
 433                        kfree(expr);
 434                        goto err;
 435                }
 436
 437                if (i == 0)
 438                        node->expr = expr;
 439                else
 440                        last->next = expr;
 441                last = expr;
 442        }
 443
 444        rc = cond_read_av_list(p, fp, &node->true_list, NULL);
 445        if (rc)
 446                goto err;
 447        rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
 448        if (rc)
 449                goto err;
 450        return 0;
 451err:
 452        cond_node_destroy(node);
 453        return rc;
 454}
 455
 456int cond_read_list(struct policydb *p, void *fp)
 457{
 458        struct cond_node *node, *last = NULL;
 459        __le32 buf[1];
 460        u32 i, len;
 461        int rc;
 462
 463        rc = next_entry(buf, fp, sizeof buf);
 464        if (rc)
 465                return rc;
 466
 467        len = le32_to_cpu(buf[0]);
 468
 469        rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
 470        if (rc)
 471                goto err;
 472
 473        for (i = 0; i < len; i++) {
 474                rc = -ENOMEM;
 475                node = kzalloc(sizeof(*node), GFP_KERNEL);
 476                if (!node)
 477                        goto err;
 478
 479                rc = cond_read_node(p, node, fp);
 480                if (rc)
 481                        goto err;
 482
 483                if (i == 0)
 484                        p->cond_list = node;
 485                else
 486                        last->next = node;
 487                last = node;
 488        }
 489        return 0;
 490err:
 491        cond_list_destroy(p->cond_list);
 492        p->cond_list = NULL;
 493        return rc;
 494}
 495
 496int cond_write_bool(void *vkey, void *datum, void *ptr)
 497{
 498        char *key = vkey;
 499        struct cond_bool_datum *booldatum = datum;
 500        struct policy_data *pd = ptr;
 501        void *fp = pd->fp;
 502        __le32 buf[3];
 503        u32 len;
 504        int rc;
 505
 506        len = strlen(key);
 507        buf[0] = cpu_to_le32(booldatum->value);
 508        buf[1] = cpu_to_le32(booldatum->state);
 509        buf[2] = cpu_to_le32(len);
 510        rc = put_entry(buf, sizeof(u32), 3, fp);
 511        if (rc)
 512                return rc;
 513        rc = put_entry(key, 1, len, fp);
 514        if (rc)
 515                return rc;
 516        return 0;
 517}
 518
 519/*
 520 * cond_write_cond_av_list doesn't write out the av_list nodes.
 521 * Instead it writes out the key/value pairs from the avtab. This
 522 * is necessary because there is no way to uniquely identifying rules
 523 * in the avtab so it is not possible to associate individual rules
 524 * in the avtab with a conditional without saving them as part of
 525 * the conditional. This means that the avtab with the conditional
 526 * rules will not be saved but will be rebuilt on policy load.
 527 */
 528static int cond_write_av_list(struct policydb *p,
 529                              struct cond_av_list *list, struct policy_file *fp)
 530{
 531        __le32 buf[1];
 532        struct cond_av_list *cur_list;
 533        u32 len;
 534        int rc;
 535
 536        len = 0;
 537        for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
 538                len++;
 539
 540        buf[0] = cpu_to_le32(len);
 541        rc = put_entry(buf, sizeof(u32), 1, fp);
 542        if (rc)
 543                return rc;
 544
 545        if (len == 0)
 546                return 0;
 547
 548        for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
 549                rc = avtab_write_item(p, cur_list->node, fp);
 550                if (rc)
 551                        return rc;
 552        }
 553
 554        return 0;
 555}
 556
 557static int cond_write_node(struct policydb *p, struct cond_node *node,
 558                    struct policy_file *fp)
 559{
 560        struct cond_expr *cur_expr;
 561        __le32 buf[2];
 562        int rc;
 563        u32 len = 0;
 564
 565        buf[0] = cpu_to_le32(node->cur_state);
 566        rc = put_entry(buf, sizeof(u32), 1, fp);
 567        if (rc)
 568                return rc;
 569
 570        for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
 571                len++;
 572
 573        buf[0] = cpu_to_le32(len);
 574        rc = put_entry(buf, sizeof(u32), 1, fp);
 575        if (rc)
 576                return rc;
 577
 578        for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
 579                buf[0] = cpu_to_le32(cur_expr->expr_type);
 580                buf[1] = cpu_to_le32(cur_expr->bool);
 581                rc = put_entry(buf, sizeof(u32), 2, fp);
 582                if (rc)
 583                        return rc;
 584        }
 585
 586        rc = cond_write_av_list(p, node->true_list, fp);
 587        if (rc)
 588                return rc;
 589        rc = cond_write_av_list(p, node->false_list, fp);
 590        if (rc)
 591                return rc;
 592
 593        return 0;
 594}
 595
 596int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
 597{
 598        struct cond_node *cur;
 599        u32 len;
 600        __le32 buf[1];
 601        int rc;
 602
 603        len = 0;
 604        for (cur = list; cur != NULL; cur = cur->next)
 605                len++;
 606        buf[0] = cpu_to_le32(len);
 607        rc = put_entry(buf, sizeof(u32), 1, fp);
 608        if (rc)
 609                return rc;
 610
 611        for (cur = list; cur != NULL; cur = cur->next) {
 612                rc = cond_write_node(p, cur, fp);
 613                if (rc)
 614                        return rc;
 615        }
 616
 617        return 0;
 618}
 619
 620void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
 621                struct extended_perms_decision *xpermd)
 622{
 623        struct avtab_node *node;
 624
 625        if (!ctab || !key || !xpermd)
 626                return;
 627
 628        for (node = avtab_search_node(ctab, key); node;
 629                        node = avtab_search_node_next(node, key->specified)) {
 630                if (node->key.specified & AVTAB_ENABLED)
 631                        services_compute_xperms_decision(xpermd, node);
 632        }
 633        return;
 634
 635}
 636/* Determine whether additional permissions are granted by the conditional
 637 * av table, and if so, add them to the result
 638 */
 639void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
 640                struct av_decision *avd, struct extended_perms *xperms)
 641{
 642        struct avtab_node *node;
 643
 644        if (!ctab || !key || !avd)
 645                return;
 646
 647        for (node = avtab_search_node(ctab, key); node;
 648                                node = avtab_search_node_next(node, key->specified)) {
 649                if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
 650                    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
 651                        avd->allowed |= node->datum.u.data;
 652                if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
 653                    (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
 654                        /* Since a '0' in an auditdeny mask represents a
 655                         * permission we do NOT want to audit (dontaudit), we use
 656                         * the '&' operand to ensure that all '0's in the mask
 657                         * are retained (much unlike the allow and auditallow cases).
 658                         */
 659                        avd->auditdeny &= node->datum.u.data;
 660                if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
 661                    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
 662                        avd->auditallow |= node->datum.u.data;
 663                if (xperms && (node->key.specified & AVTAB_ENABLED) &&
 664                                (node->key.specified & AVTAB_XPERMS))
 665                        services_compute_xperms_drivers(xperms, node);
 666        }
 667}
 668