root/security/selinux/ss/avtab.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. avtab_hash
  2. avtab_insert_node
  3. avtab_insert
  4. avtab_insert_nonunique
  5. avtab_search
  6. avtab_search_node
  7. avtab_search_node_next
  8. avtab_destroy
  9. avtab_init
  10. avtab_alloc
  11. avtab_hash_eval
  12. avtab_read_item
  13. avtab_insertf
  14. avtab_read
  15. avtab_write_item
  16. avtab_write
  17. avtab_cache_init

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

/* [<][>][^][v][top][bottom][index][help] */