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