linux/security/selinux/ss/avtab.c
<<
>>
Prefs
   1/*
   2 * Implementation of the access vector table type.
   3 *
   4 * Author : Stephen Smalley, <sds@epoch.ncsc.mil>
   5 */
   6
   7/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
   8 *
   9 *      Added conditional policy language extensions
  10 *
  11 * Copyright (C) 2003 Tresys Technology, LLC
  12 *      This program is free software; you can redistribute it and/or modify
  13 *      it under the terms of the GNU General Public License as published by
  14 *      the Free Software Foundation, version 2.
  15 *
  16 * Updated: Yuichi Nakamura <ynakam@hitachisoft.jp>
  17 *      Tuned number of hash slots for avtab to reduce memory usage
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/slab.h>
  22#include <linux/errno.h>
  23#include "avtab.h"
  24#include "policydb.h"
  25
  26static struct kmem_cache *avtab_node_cachep;
  27static struct kmem_cache *avtab_xperms_cachep;
  28
  29static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
  30{
  31        return ((keyp->target_class + (keyp->target_type << 2) +
  32                 (keyp->source_type << 9)) & mask);
  33}
  34
  35static struct avtab_node*
  36avtab_insert_node(struct avtab *h, int hvalue,
  37                  struct avtab_node *prev, struct avtab_node *cur,
  38                  struct avtab_key *key, struct avtab_datum *datum)
  39{
  40        struct avtab_node *newnode;
  41        struct avtab_extended_perms *xperms;
  42        newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL);
  43        if (newnode == NULL)
  44                return NULL;
  45        newnode->key = *key;
  46
  47        if (key->specified & AVTAB_XPERMS) {
  48                xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL);
  49                if (xperms == NULL) {
  50                        kmem_cache_free(avtab_node_cachep, newnode);
  51                        return NULL;
  52                }
  53                *xperms = *(datum->u.xperms);
  54                newnode->datum.u.xperms = xperms;
  55        } else {
  56                newnode->datum.u.data = datum->u.data;
  57        }
  58
  59        if (prev) {
  60                newnode->next = prev->next;
  61                prev->next = newnode;
  62        } else {
  63                newnode->next = h->htable[hvalue];
  64                h->htable[hvalue] = newnode;
  65        }
  66
  67        h->nel++;
  68        return newnode;
  69}
  70
  71static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
  72{
  73        int hvalue;
  74        struct avtab_node *prev, *cur, *newnode;
  75        u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
  76
  77        if (!h || !h->htable)
  78                return -EINVAL;
  79
  80        hvalue = avtab_hash(key, h->mask);
  81        for (prev = NULL, cur = h->htable[hvalue];
  82             cur;
  83             prev = cur, cur = cur->next) {
  84                if (key->source_type == cur->key.source_type &&
  85                    key->target_type == cur->key.target_type &&
  86                    key->target_class == cur->key.target_class &&
  87                    (specified & cur->key.specified)) {
  88                        /* extended perms may not be unique */
  89                        if (specified & AVTAB_XPERMS)
  90                                break;
  91                        return -EEXIST;
  92                }
  93                if (key->source_type < cur->key.source_type)
  94                        break;
  95                if (key->source_type == cur->key.source_type &&
  96                    key->target_type < cur->key.target_type)
  97                        break;
  98                if (key->source_type == cur->key.source_type &&
  99                    key->target_type == cur->key.target_type &&
 100                    key->target_class < cur->key.target_class)
 101                        break;
 102        }
 103
 104        newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
 105        if (!newnode)
 106                return -ENOMEM;
 107
 108        return 0;
 109}
 110
 111/* Unlike avtab_insert(), this function allow multiple insertions of the same
 112 * key/specified mask into the table, as needed by the conditional avtab.
 113 * It also returns a pointer to the node inserted.
 114 */
 115struct avtab_node *
 116avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datum *datum)
 117{
 118        int hvalue;
 119        struct avtab_node *prev, *cur;
 120        u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 121
 122        if (!h || !h->htable)
 123                return NULL;
 124        hvalue = avtab_hash(key, h->mask);
 125        for (prev = NULL, cur = h->htable[hvalue];
 126             cur;
 127             prev = cur, cur = cur->next) {
 128                if (key->source_type == cur->key.source_type &&
 129                    key->target_type == cur->key.target_type &&
 130                    key->target_class == cur->key.target_class &&
 131                    (specified & cur->key.specified))
 132                        break;
 133                if (key->source_type < cur->key.source_type)
 134                        break;
 135                if (key->source_type == cur->key.source_type &&
 136                    key->target_type < cur->key.target_type)
 137                        break;
 138                if (key->source_type == cur->key.source_type &&
 139                    key->target_type == cur->key.target_type &&
 140                    key->target_class < cur->key.target_class)
 141                        break;
 142        }
 143        return avtab_insert_node(h, hvalue, prev, cur, key, datum);
 144}
 145
 146struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
 147{
 148        int hvalue;
 149        struct avtab_node *cur;
 150        u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 151
 152        if (!h || !h->htable)
 153                return NULL;
 154
 155        hvalue = avtab_hash(key, h->mask);
 156        for (cur = h->htable[hvalue]; cur; cur = cur->next) {
 157                if (key->source_type == cur->key.source_type &&
 158                    key->target_type == cur->key.target_type &&
 159                    key->target_class == cur->key.target_class &&
 160                    (specified & cur->key.specified))
 161                        return &cur->datum;
 162
 163                if (key->source_type < cur->key.source_type)
 164                        break;
 165                if (key->source_type == cur->key.source_type &&
 166                    key->target_type < cur->key.target_type)
 167                        break;
 168                if (key->source_type == cur->key.source_type &&
 169                    key->target_type == cur->key.target_type &&
 170                    key->target_class < cur->key.target_class)
 171                        break;
 172        }
 173
 174        return NULL;
 175}
 176
 177/* This search function returns a node pointer, and can be used in
 178 * conjunction with avtab_search_next_node()
 179 */
 180struct avtab_node*
 181avtab_search_node(struct avtab *h, struct avtab_key *key)
 182{
 183        int hvalue;
 184        struct avtab_node *cur;
 185        u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 186
 187        if (!h || !h->htable)
 188                return NULL;
 189
 190        hvalue = avtab_hash(key, h->mask);
 191        for (cur = h->htable[hvalue]; cur; cur = cur->next) {
 192                if (key->source_type == cur->key.source_type &&
 193                    key->target_type == cur->key.target_type &&
 194                    key->target_class == cur->key.target_class &&
 195                    (specified & cur->key.specified))
 196                        return cur;
 197
 198                if (key->source_type < cur->key.source_type)
 199                        break;
 200                if (key->source_type == cur->key.source_type &&
 201                    key->target_type < cur->key.target_type)
 202                        break;
 203                if (key->source_type == cur->key.source_type &&
 204                    key->target_type == cur->key.target_type &&
 205                    key->target_class < cur->key.target_class)
 206                        break;
 207        }
 208        return NULL;
 209}
 210
 211struct avtab_node*
 212avtab_search_node_next(struct avtab_node *node, int specified)
 213{
 214        struct avtab_node *cur;
 215
 216        if (!node)
 217                return NULL;
 218
 219        specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
 220        for (cur = node->next; cur; cur = cur->next) {
 221                if (node->key.source_type == cur->key.source_type &&
 222                    node->key.target_type == cur->key.target_type &&
 223                    node->key.target_class == cur->key.target_class &&
 224                    (specified & cur->key.specified))
 225                        return cur;
 226
 227                if (node->key.source_type < cur->key.source_type)
 228                        break;
 229                if (node->key.source_type == cur->key.source_type &&
 230                    node->key.target_type < cur->key.target_type)
 231                        break;
 232                if (node->key.source_type == cur->key.source_type &&
 233                    node->key.target_type == cur->key.target_type &&
 234                    node->key.target_class < cur->key.target_class)
 235                        break;
 236        }
 237        return NULL;
 238}
 239
 240void avtab_destroy(struct avtab *h)
 241{
 242        int i;
 243        struct avtab_node *cur, *temp;
 244
 245        if (!h || !h->htable)
 246                return;
 247
 248        for (i = 0; i < h->nslot; i++) {
 249                cur = h->htable[i];
 250                while (cur) {
 251                        temp = cur;
 252                        cur = cur->next;
 253                        if (temp->key.specified & AVTAB_XPERMS)
 254                                kmem_cache_free(avtab_xperms_cachep,
 255                                                temp->datum.u.xperms);
 256                        kmem_cache_free(avtab_node_cachep, temp);
 257                }
 258                h->htable[i] = NULL;
 259        }
 260        kfree(h->htable);
 261        h->htable = NULL;
 262        h->nslot = 0;
 263        h->mask = 0;
 264}
 265
 266int avtab_init(struct avtab *h)
 267{
 268        h->htable = NULL;
 269        h->nel = 0;
 270        return 0;
 271}
 272
 273int avtab_alloc(struct avtab *h, u32 nrules)
 274{
 275        u16 mask = 0;
 276        u32 shift = 0;
 277        u32 work = nrules;
 278        u32 nslot = 0;
 279
 280        if (nrules == 0)
 281                goto avtab_alloc_out;
 282
 283        while (work) {
 284                work  = work >> 1;
 285                shift++;
 286        }
 287        if (shift > 2)
 288                shift = shift - 2;
 289        nslot = 1 << shift;
 290        if (nslot > MAX_AVTAB_HASH_BUCKETS)
 291                nslot = MAX_AVTAB_HASH_BUCKETS;
 292        mask = nslot - 1;
 293
 294        h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
 295        if (!h->htable)
 296                return -ENOMEM;
 297
 298 avtab_alloc_out:
 299        h->nel = 0;
 300        h->nslot = nslot;
 301        h->mask = mask;
 302        printk(KERN_DEBUG "SELinux: %d avtab hash slots, %d rules.\n",
 303               h->nslot, nrules);
 304        return 0;
 305}
 306
 307void avtab_hash_eval(struct avtab *h, char *tag)
 308{
 309        int i, chain_len, slots_used, max_chain_len;
 310        unsigned long long chain2_len_sum;
 311        struct avtab_node *cur;
 312
 313        slots_used = 0;
 314        max_chain_len = 0;
 315        chain2_len_sum = 0;
 316        for (i = 0; i < h->nslot; i++) {
 317                cur = h->htable[i];
 318                if (cur) {
 319                        slots_used++;
 320                        chain_len = 0;
 321                        while (cur) {
 322                                chain_len++;
 323                                cur = cur->next;
 324                        }
 325
 326                        if (chain_len > max_chain_len)
 327                                max_chain_len = chain_len;
 328                        chain2_len_sum += chain_len * chain_len;
 329                }
 330        }
 331
 332        printk(KERN_DEBUG "SELinux: %s:  %d entries and %d/%d buckets used, "
 333               "longest chain length %d sum of chain length^2 %llu\n",
 334               tag, h->nel, slots_used, h->nslot, max_chain_len,
 335               chain2_len_sum);
 336}
 337
 338static uint16_t spec_order[] = {
 339        AVTAB_ALLOWED,
 340        AVTAB_AUDITDENY,
 341        AVTAB_AUDITALLOW,
 342        AVTAB_TRANSITION,
 343        AVTAB_CHANGE,
 344        AVTAB_MEMBER,
 345        AVTAB_XPERMS_ALLOWED,
 346        AVTAB_XPERMS_AUDITALLOW,
 347        AVTAB_XPERMS_DONTAUDIT
 348};
 349
 350int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
 351                    int (*insertf)(struct avtab *a, struct avtab_key *k,
 352                                   struct avtab_datum *d, void *p),
 353                    void *p)
 354{
 355        __le16 buf16[4];
 356        u16 enabled;
 357        u32 items, items2, val, vers = pol->policyvers;
 358        struct avtab_key key;
 359        struct avtab_datum datum;
 360        struct avtab_extended_perms xperms;
 361        __le32 buf32[ARRAY_SIZE(xperms.perms.p)];
 362        int i, rc;
 363        unsigned set;
 364
 365        memset(&key, 0, sizeof(struct avtab_key));
 366        memset(&datum, 0, sizeof(struct avtab_datum));
 367
 368        if (vers < POLICYDB_VERSION_AVTAB) {
 369                rc = next_entry(buf32, fp, sizeof(u32));
 370                if (rc) {
 371                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
 372                        return rc;
 373                }
 374                items2 = le32_to_cpu(buf32[0]);
 375                if (items2 > ARRAY_SIZE(buf32)) {
 376                        printk(KERN_ERR "SELinux: avtab: entry overflow\n");
 377                        return -EINVAL;
 378
 379                }
 380                rc = next_entry(buf32, fp, sizeof(u32)*items2);
 381                if (rc) {
 382                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
 383                        return rc;
 384                }
 385                items = 0;
 386
 387                val = le32_to_cpu(buf32[items++]);
 388                key.source_type = (u16)val;
 389                if (key.source_type != val) {
 390                        printk(KERN_ERR "SELinux: avtab: truncated source type\n");
 391                        return -EINVAL;
 392                }
 393                val = le32_to_cpu(buf32[items++]);
 394                key.target_type = (u16)val;
 395                if (key.target_type != val) {
 396                        printk(KERN_ERR "SELinux: avtab: truncated target type\n");
 397                        return -EINVAL;
 398                }
 399                val = le32_to_cpu(buf32[items++]);
 400                key.target_class = (u16)val;
 401                if (key.target_class != val) {
 402                        printk(KERN_ERR "SELinux: avtab: truncated target class\n");
 403                        return -EINVAL;
 404                }
 405
 406                val = le32_to_cpu(buf32[items++]);
 407                enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
 408
 409                if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
 410                        printk(KERN_ERR "SELinux: avtab: null entry\n");
 411                        return -EINVAL;
 412                }
 413                if ((val & AVTAB_AV) &&
 414                    (val & AVTAB_TYPE)) {
 415                        printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n");
 416                        return -EINVAL;
 417                }
 418                if (val & AVTAB_XPERMS) {
 419                        printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n");
 420                        return -EINVAL;
 421                }
 422
 423                for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
 424                        if (val & spec_order[i]) {
 425                                key.specified = spec_order[i] | enabled;
 426                                datum.u.data = le32_to_cpu(buf32[items++]);
 427                                rc = insertf(a, &key, &datum, p);
 428                                if (rc)
 429                                        return rc;
 430                        }
 431                }
 432
 433                if (items != items2) {
 434                        printk(KERN_ERR "SELinux: avtab: entry only had %d items, expected %d\n", items2, items);
 435                        return -EINVAL;
 436                }
 437                return 0;
 438        }
 439
 440        rc = next_entry(buf16, fp, sizeof(u16)*4);
 441        if (rc) {
 442                printk(KERN_ERR "SELinux: avtab: truncated entry\n");
 443                return rc;
 444        }
 445
 446        items = 0;
 447        key.source_type = le16_to_cpu(buf16[items++]);
 448        key.target_type = le16_to_cpu(buf16[items++]);
 449        key.target_class = le16_to_cpu(buf16[items++]);
 450        key.specified = le16_to_cpu(buf16[items++]);
 451
 452        if (!policydb_type_isvalid(pol, key.source_type) ||
 453            !policydb_type_isvalid(pol, key.target_type) ||
 454            !policydb_class_isvalid(pol, key.target_class)) {
 455                printk(KERN_ERR "SELinux: avtab: invalid type or class\n");
 456                return -EINVAL;
 457        }
 458
 459        set = 0;
 460        for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
 461                if (key.specified & spec_order[i])
 462                        set++;
 463        }
 464        if (!set || set > 1) {
 465                printk(KERN_ERR "SELinux:  avtab:  more than one specifier\n");
 466                return -EINVAL;
 467        }
 468
 469        if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) &&
 470                        (key.specified & AVTAB_XPERMS)) {
 471                printk(KERN_ERR "SELinux:  avtab:  policy version %u does not "
 472                                "support extended permissions rules and one "
 473                                "was specified\n", vers);
 474                return -EINVAL;
 475        } else if (key.specified & AVTAB_XPERMS) {
 476                memset(&xperms, 0, sizeof(struct avtab_extended_perms));
 477                rc = next_entry(&xperms.specified, fp, sizeof(u8));
 478                if (rc) {
 479                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
 480                        return rc;
 481                }
 482                rc = next_entry(&xperms.driver, fp, sizeof(u8));
 483                if (rc) {
 484                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
 485                        return rc;
 486                }
 487                rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p));
 488                if (rc) {
 489                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
 490                        return rc;
 491                }
 492                for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++)
 493                        xperms.perms.p[i] = le32_to_cpu(buf32[i]);
 494                datum.u.xperms = &xperms;
 495        } else {
 496                rc = next_entry(buf32, fp, sizeof(u32));
 497                if (rc) {
 498                        printk(KERN_ERR "SELinux: avtab: truncated entry\n");
 499                        return rc;
 500                }
 501                datum.u.data = le32_to_cpu(*buf32);
 502        }
 503        if ((key.specified & AVTAB_TYPE) &&
 504            !policydb_type_isvalid(pol, datum.u.data)) {
 505                printk(KERN_ERR "SELinux: avtab: invalid type\n");
 506                return -EINVAL;
 507        }
 508        return insertf(a, &key, &datum, p);
 509}
 510
 511static int avtab_insertf(struct avtab *a, struct avtab_key *k,
 512                         struct avtab_datum *d, void *p)
 513{
 514        return avtab_insert(a, k, d);
 515}
 516
 517int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
 518{
 519        int rc;
 520        __le32 buf[1];
 521        u32 nel, i;
 522
 523
 524        rc = next_entry(buf, fp, sizeof(u32));
 525        if (rc < 0) {
 526                printk(KERN_ERR "SELinux: avtab: truncated table\n");
 527                goto bad;
 528        }
 529        nel = le32_to_cpu(buf[0]);
 530        if (!nel) {
 531                printk(KERN_ERR "SELinux: avtab: table is empty\n");
 532                rc = -EINVAL;
 533                goto bad;
 534        }
 535
 536        rc = avtab_alloc(a, nel);
 537        if (rc)
 538                goto bad;
 539
 540        for (i = 0; i < nel; i++) {
 541                rc = avtab_read_item(a, fp, pol, avtab_insertf, NULL);
 542                if (rc) {
 543                        if (rc == -ENOMEM)
 544                                printk(KERN_ERR "SELinux: avtab: out of memory\n");
 545                        else if (rc == -EEXIST)
 546                                printk(KERN_ERR "SELinux: avtab: duplicate entry\n");
 547
 548                        goto bad;
 549                }
 550        }
 551
 552        rc = 0;
 553out:
 554        return rc;
 555
 556bad:
 557        avtab_destroy(a);
 558        goto out;
 559}
 560
 561int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
 562{
 563        __le16 buf16[4];
 564        __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)];
 565        int rc;
 566        unsigned int i;
 567
 568        buf16[0] = cpu_to_le16(cur->key.source_type);
 569        buf16[1] = cpu_to_le16(cur->key.target_type);
 570        buf16[2] = cpu_to_le16(cur->key.target_class);
 571        buf16[3] = cpu_to_le16(cur->key.specified);
 572        rc = put_entry(buf16, sizeof(u16), 4, fp);
 573        if (rc)
 574                return rc;
 575
 576        if (cur->key.specified & AVTAB_XPERMS) {
 577                rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp);
 578                if (rc)
 579                        return rc;
 580                rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp);
 581                if (rc)
 582                        return rc;
 583                for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++)
 584                        buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]);
 585                rc = put_entry(buf32, sizeof(u32),
 586                                ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp);
 587        } else {
 588                buf32[0] = cpu_to_le32(cur->datum.u.data);
 589                rc = put_entry(buf32, sizeof(u32), 1, fp);
 590        }
 591        if (rc)
 592                return rc;
 593        return 0;
 594}
 595
 596int avtab_write(struct policydb *p, struct avtab *a, void *fp)
 597{
 598        unsigned int i;
 599        int rc = 0;
 600        struct avtab_node *cur;
 601        __le32 buf[1];
 602
 603        buf[0] = cpu_to_le32(a->nel);
 604        rc = put_entry(buf, sizeof(u32), 1, fp);
 605        if (rc)
 606                return rc;
 607
 608        for (i = 0; i < a->nslot; i++) {
 609                for (cur = a->htable[i]; cur; cur = cur->next) {
 610                        rc = avtab_write_item(p, cur, fp);
 611                        if (rc)
 612                                return rc;
 613                }
 614        }
 615
 616        return rc;
 617}
 618void avtab_cache_init(void)
 619{
 620        avtab_node_cachep = kmem_cache_create("avtab_node",
 621                                              sizeof(struct avtab_node),
 622                                              0, SLAB_PANIC, NULL);
 623        avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms",
 624                                                sizeof(struct avtab_extended_perms),
 625                                                0, SLAB_PANIC, NULL);
 626}
 627
 628void avtab_cache_destroy(void)
 629{
 630        kmem_cache_destroy(avtab_node_cachep);
 631        kmem_cache_destroy(avtab_xperms_cachep);
 632}
 633