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 =
 180                kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
 181        if (!p->bool_val_to_struct)
 182                return -ENOMEM;
 183        return 0;
 184}
 185
 186int cond_destroy_bool(void *key, void *datum, void *p)
 187{
 188        kfree(key);
 189        kfree(datum);
 190        return 0;
 191}
 192
 193int cond_index_bool(void *key, void *datum, void *datap)
 194{
 195        struct policydb *p;
 196        struct cond_bool_datum *booldatum;
 197        struct flex_array *fa;
 198
 199        booldatum = datum;
 200        p = datap;
 201
 202        if (!booldatum->value || booldatum->value > p->p_bools.nprim)
 203                return -EINVAL;
 204
 205        fa = p->sym_val_to_name[SYM_BOOLS];
 206        if (flex_array_put_ptr(fa, booldatum->value - 1, key,
 207                               GFP_KERNEL | __GFP_ZERO))
 208                BUG();
 209        p->bool_val_to_struct[booldatum->value - 1] = booldatum;
 210
 211        return 0;
 212}
 213
 214static int bool_isvalid(struct cond_bool_datum *b)
 215{
 216        if (!(b->state == 0 || b->state == 1))
 217                return 0;
 218        return 1;
 219}
 220
 221int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp)
 222{
 223        char *key = NULL;
 224        struct cond_bool_datum *booldatum;
 225        __le32 buf[3];
 226        u32 len;
 227        int rc;
 228
 229        booldatum = kzalloc(sizeof(struct cond_bool_datum), GFP_KERNEL);
 230        if (!booldatum)
 231                return -ENOMEM;
 232
 233        rc = next_entry(buf, fp, sizeof buf);
 234        if (rc)
 235                goto err;
 236
 237        booldatum->value = le32_to_cpu(buf[0]);
 238        booldatum->state = le32_to_cpu(buf[1]);
 239
 240        rc = -EINVAL;
 241        if (!bool_isvalid(booldatum))
 242                goto err;
 243
 244        len = le32_to_cpu(buf[2]);
 245
 246        rc = -ENOMEM;
 247        key = kmalloc(len + 1, GFP_KERNEL);
 248        if (!key)
 249                goto err;
 250        rc = next_entry(key, fp, len);
 251        if (rc)
 252                goto err;
 253        key[len] = '\0';
 254        rc = hashtab_insert(h, key, booldatum);
 255        if (rc)
 256                goto err;
 257
 258        return 0;
 259err:
 260        cond_destroy_bool(key, booldatum, NULL);
 261        return rc;
 262}
 263
 264struct cond_insertf_data {
 265        struct policydb *p;
 266        struct cond_av_list *other;
 267        struct cond_av_list *head;
 268        struct cond_av_list *tail;
 269};
 270
 271static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
 272{
 273        struct cond_insertf_data *data = ptr;
 274        struct policydb *p = data->p;
 275        struct cond_av_list *other = data->other, *list, *cur;
 276        struct avtab_node *node_ptr;
 277        u8 found;
 278        int rc = -EINVAL;
 279
 280        /*
 281         * For type rules we have to make certain there aren't any
 282         * conflicting rules by searching the te_avtab and the
 283         * cond_te_avtab.
 284         */
 285        if (k->specified & AVTAB_TYPE) {
 286                if (avtab_search(&p->te_avtab, k)) {
 287                        printk(KERN_ERR "SELinux: type rule already exists outside of a conditional.\n");
 288                        goto err;
 289                }
 290                /*
 291                 * If we are reading the false list other will be a pointer to
 292                 * the true list. We can have duplicate entries if there is only
 293                 * 1 other entry and it is in our true list.
 294                 *
 295                 * If we are reading the true list (other == NULL) there shouldn't
 296                 * be any other entries.
 297                 */
 298                if (other) {
 299                        node_ptr = avtab_search_node(&p->te_cond_avtab, k);
 300                        if (node_ptr) {
 301                                if (avtab_search_node_next(node_ptr, k->specified)) {
 302                                        printk(KERN_ERR "SELinux: too many conflicting type rules.\n");
 303                                        goto err;
 304                                }
 305                                found = 0;
 306                                for (cur = other; cur; cur = cur->next) {
 307                                        if (cur->node == node_ptr) {
 308                                                found = 1;
 309                                                break;
 310                                        }
 311                                }
 312                                if (!found) {
 313                                        printk(KERN_ERR "SELinux: conflicting type rules.\n");
 314                                        goto err;
 315                                }
 316                        }
 317                } else {
 318                        if (avtab_search(&p->te_cond_avtab, k)) {
 319                                printk(KERN_ERR "SELinux: conflicting type rules when adding type rule for true.\n");
 320                                goto err;
 321                        }
 322                }
 323        }
 324
 325        node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
 326        if (!node_ptr) {
 327                printk(KERN_ERR "SELinux: could not insert rule.\n");
 328                rc = -ENOMEM;
 329                goto err;
 330        }
 331
 332        list = kzalloc(sizeof(struct cond_av_list), GFP_KERNEL);
 333        if (!list) {
 334                rc = -ENOMEM;
 335                goto err;
 336        }
 337
 338        list->node = node_ptr;
 339        if (!data->head)
 340                data->head = list;
 341        else
 342                data->tail->next = list;
 343        data->tail = list;
 344        return 0;
 345
 346err:
 347        cond_av_list_destroy(data->head);
 348        data->head = NULL;
 349        return rc;
 350}
 351
 352static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
 353{
 354        int i, rc;
 355        __le32 buf[1];
 356        u32 len;
 357        struct cond_insertf_data data;
 358
 359        *ret_list = NULL;
 360
 361        len = 0;
 362        rc = next_entry(buf, fp, sizeof(u32));
 363        if (rc)
 364                return rc;
 365
 366        len = le32_to_cpu(buf[0]);
 367        if (len == 0)
 368                return 0;
 369
 370        data.p = p;
 371        data.other = other;
 372        data.head = NULL;
 373        data.tail = NULL;
 374        for (i = 0; i < len; i++) {
 375                rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
 376                                     &data);
 377                if (rc)
 378                        return rc;
 379        }
 380
 381        *ret_list = data.head;
 382        return 0;
 383}
 384
 385static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
 386{
 387        if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
 388                printk(KERN_ERR "SELinux: conditional expressions uses unknown operator.\n");
 389                return 0;
 390        }
 391
 392        if (expr->bool > p->p_bools.nprim) {
 393                printk(KERN_ERR "SELinux: conditional expressions uses unknown bool.\n");
 394                return 0;
 395        }
 396        return 1;
 397}
 398
 399static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
 400{
 401        __le32 buf[2];
 402        u32 len, i;
 403        int rc;
 404        struct cond_expr *expr = NULL, *last = NULL;
 405
 406        rc = next_entry(buf, fp, sizeof(u32) * 2);
 407        if (rc)
 408                goto err;
 409
 410        node->cur_state = le32_to_cpu(buf[0]);
 411
 412        /* expr */
 413        len = le32_to_cpu(buf[1]);
 414
 415        for (i = 0; i < len; i++) {
 416                rc = next_entry(buf, fp, sizeof(u32) * 2);
 417                if (rc)
 418                        goto err;
 419
 420                rc = -ENOMEM;
 421                expr = kzalloc(sizeof(struct cond_expr), GFP_KERNEL);
 422                if (!expr)
 423                        goto err;
 424
 425                expr->expr_type = le32_to_cpu(buf[0]);
 426                expr->bool = le32_to_cpu(buf[1]);
 427
 428                if (!expr_isvalid(p, expr)) {
 429                        rc = -EINVAL;
 430                        kfree(expr);
 431                        goto err;
 432                }
 433
 434                if (i == 0)
 435                        node->expr = expr;
 436                else
 437                        last->next = expr;
 438                last = expr;
 439        }
 440
 441        rc = cond_read_av_list(p, fp, &node->true_list, NULL);
 442        if (rc)
 443                goto err;
 444        rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
 445        if (rc)
 446                goto err;
 447        return 0;
 448err:
 449        cond_node_destroy(node);
 450        return rc;
 451}
 452
 453int cond_read_list(struct policydb *p, void *fp)
 454{
 455        struct cond_node *node, *last = NULL;
 456        __le32 buf[1];
 457        u32 i, len;
 458        int rc;
 459
 460        rc = next_entry(buf, fp, sizeof buf);
 461        if (rc)
 462                return rc;
 463
 464        len = le32_to_cpu(buf[0]);
 465
 466        rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
 467        if (rc)
 468                goto err;
 469
 470        for (i = 0; i < len; i++) {
 471                rc = -ENOMEM;
 472                node = kzalloc(sizeof(struct cond_node), GFP_KERNEL);
 473                if (!node)
 474                        goto err;
 475
 476                rc = cond_read_node(p, node, fp);
 477                if (rc)
 478                        goto err;
 479
 480                if (i == 0)
 481                        p->cond_list = node;
 482                else
 483                        last->next = node;
 484                last = node;
 485        }
 486        return 0;
 487err:
 488        cond_list_destroy(p->cond_list);
 489        p->cond_list = NULL;
 490        return rc;
 491}
 492
 493int cond_write_bool(void *vkey, void *datum, void *ptr)
 494{
 495        char *key = vkey;
 496        struct cond_bool_datum *booldatum = datum;
 497        struct policy_data *pd = ptr;
 498        void *fp = pd->fp;
 499        __le32 buf[3];
 500        u32 len;
 501        int rc;
 502
 503        len = strlen(key);
 504        buf[0] = cpu_to_le32(booldatum->value);
 505        buf[1] = cpu_to_le32(booldatum->state);
 506        buf[2] = cpu_to_le32(len);
 507        rc = put_entry(buf, sizeof(u32), 3, fp);
 508        if (rc)
 509                return rc;
 510        rc = put_entry(key, 1, len, fp);
 511        if (rc)
 512                return rc;
 513        return 0;
 514}
 515
 516/*
 517 * cond_write_cond_av_list doesn't write out the av_list nodes.
 518 * Instead it writes out the key/value pairs from the avtab. This
 519 * is necessary because there is no way to uniquely identifying rules
 520 * in the avtab so it is not possible to associate individual rules
 521 * in the avtab with a conditional without saving them as part of
 522 * the conditional. This means that the avtab with the conditional
 523 * rules will not be saved but will be rebuilt on policy load.
 524 */
 525static int cond_write_av_list(struct policydb *p,
 526                              struct cond_av_list *list, struct policy_file *fp)
 527{
 528        __le32 buf[1];
 529        struct cond_av_list *cur_list;
 530        u32 len;
 531        int rc;
 532
 533        len = 0;
 534        for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
 535                len++;
 536
 537        buf[0] = cpu_to_le32(len);
 538        rc = put_entry(buf, sizeof(u32), 1, fp);
 539        if (rc)
 540                return rc;
 541
 542        if (len == 0)
 543                return 0;
 544
 545        for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
 546                rc = avtab_write_item(p, cur_list->node, fp);
 547                if (rc)
 548                        return rc;
 549        }
 550
 551        return 0;
 552}
 553
 554static int cond_write_node(struct policydb *p, struct cond_node *node,
 555                    struct policy_file *fp)
 556{
 557        struct cond_expr *cur_expr;
 558        __le32 buf[2];
 559        int rc;
 560        u32 len = 0;
 561
 562        buf[0] = cpu_to_le32(node->cur_state);
 563        rc = put_entry(buf, sizeof(u32), 1, fp);
 564        if (rc)
 565                return rc;
 566
 567        for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
 568                len++;
 569
 570        buf[0] = cpu_to_le32(len);
 571        rc = put_entry(buf, sizeof(u32), 1, fp);
 572        if (rc)
 573                return rc;
 574
 575        for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
 576                buf[0] = cpu_to_le32(cur_expr->expr_type);
 577                buf[1] = cpu_to_le32(cur_expr->bool);
 578                rc = put_entry(buf, sizeof(u32), 2, fp);
 579                if (rc)
 580                        return rc;
 581        }
 582
 583        rc = cond_write_av_list(p, node->true_list, fp);
 584        if (rc)
 585                return rc;
 586        rc = cond_write_av_list(p, node->false_list, fp);
 587        if (rc)
 588                return rc;
 589
 590        return 0;
 591}
 592
 593int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
 594{
 595        struct cond_node *cur;
 596        u32 len;
 597        __le32 buf[1];
 598        int rc;
 599
 600        len = 0;
 601        for (cur = list; cur != NULL; cur = cur->next)
 602                len++;
 603        buf[0] = cpu_to_le32(len);
 604        rc = put_entry(buf, sizeof(u32), 1, fp);
 605        if (rc)
 606                return rc;
 607
 608        for (cur = list; cur != NULL; cur = cur->next) {
 609                rc = cond_write_node(p, cur, fp);
 610                if (rc)
 611                        return rc;
 612        }
 613
 614        return 0;
 615}
 616
 617void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
 618                struct extended_perms_decision *xpermd)
 619{
 620        struct avtab_node *node;
 621
 622        if (!ctab || !key || !xpermd)
 623                return;
 624
 625        for (node = avtab_search_node(ctab, key); node;
 626                        node = avtab_search_node_next(node, key->specified)) {
 627                if (node->key.specified & AVTAB_ENABLED)
 628                        services_compute_xperms_decision(xpermd, node);
 629        }
 630        return;
 631
 632}
 633/* Determine whether additional permissions are granted by the conditional
 634 * av table, and if so, add them to the result
 635 */
 636void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
 637                struct av_decision *avd, struct extended_perms *xperms)
 638{
 639        struct avtab_node *node;
 640
 641        if (!ctab || !key || !avd)
 642                return;
 643
 644        for (node = avtab_search_node(ctab, key); node;
 645                                node = avtab_search_node_next(node, key->specified)) {
 646                if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) ==
 647                    (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED)))
 648                        avd->allowed |= node->datum.u.data;
 649                if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) ==
 650                    (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED)))
 651                        /* Since a '0' in an auditdeny mask represents a
 652                         * permission we do NOT want to audit (dontaudit), we use
 653                         * the '&' operand to ensure that all '0's in the mask
 654                         * are retained (much unlike the allow and auditallow cases).
 655                         */
 656                        avd->auditdeny &= node->datum.u.data;
 657                if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
 658                    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
 659                        avd->auditallow |= node->datum.u.data;
 660                if (xperms && (node->key.specified & AVTAB_ENABLED) &&
 661                                (node->key.specified & AVTAB_XPERMS))
 662                        services_compute_xperms_drivers(xperms, node);
 663        }
 664        return;
 665}
 666