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