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 static inline int avtab_hash(struct avtab_key *keyp, uint16_t mask) 53 { 54 return ((keyp->target_class + (keyp->target_type << 2) + 55 (keyp->source_type << 9)) & mask); 56 } 57 58 static avtab_ptr_t 59 avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key, 60 avtab_datum_t * datum) 61 { 62 avtab_ptr_t newnode; 63 newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node)); 64 if (newnode == NULL) 65 return NULL; 66 memset(newnode, 0, sizeof(struct avtab_node)); 67 newnode->key = *key; 68 newnode->datum = *datum; 69 if (prev) { 70 newnode->next = prev->next; 71 prev->next = newnode; 72 } else { 73 newnode->next = h->htable[hvalue]; 74 h->htable[hvalue] = newnode; 75 } 76 77 h->nel++; 78 return newnode; 79 } 80 81 int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum) 82 { 83 int hvalue; 84 avtab_ptr_t prev, cur, newnode; 85 uint16_t specified = 86 key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); 87 88 if (!h || !h->htable) 89 return SEPOL_ENOMEM; 90 91 hvalue = avtab_hash(key, h->mask); 92 for (prev = NULL, cur = h->htable[hvalue]; 93 cur; prev = cur, cur = cur->next) { 94 if (key->source_type == cur->key.source_type && 95 key->target_type == cur->key.target_type && 96 key->target_class == cur->key.target_class && 97 (specified & cur->key.specified)) 98 return SEPOL_EEXIST; 99 if (key->source_type < cur->key.source_type) 100 break; 101 if (key->source_type == cur->key.source_type && 102 key->target_type < cur->key.target_type) 103 break; 104 if (key->source_type == cur->key.source_type && 105 key->target_type == cur->key.target_type && 106 key->target_class < cur->key.target_class) 107 break; 108 } 109 110 newnode = avtab_insert_node(h, hvalue, prev, key, datum); 111 if (!newnode) 112 return SEPOL_ENOMEM; 113 114 return 0; 115 } 116 117 /* Unlike avtab_insert(), this function allow multiple insertions of the same 118 * key/specified mask into the table, as needed by the conditional avtab. 119 * It also returns a pointer to the node inserted. 120 */ 121 avtab_ptr_t 122 avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum) 123 { 124 int hvalue; 125 avtab_ptr_t prev, cur, newnode; 126 uint16_t specified = 127 key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); 128 129 if (!h || !h->htable) 130 return NULL; 131 hvalue = avtab_hash(key, h->mask); 132 for (prev = NULL, cur = h->htable[hvalue]; 133 cur; prev = cur, cur = cur->next) { 134 if (key->source_type == cur->key.source_type && 135 key->target_type == cur->key.target_type && 136 key->target_class == cur->key.target_class && 137 (specified & cur->key.specified)) 138 break; 139 if (key->source_type < cur->key.source_type) 140 break; 141 if (key->source_type == cur->key.source_type && 142 key->target_type < cur->key.target_type) 143 break; 144 if (key->source_type == cur->key.source_type && 145 key->target_type == cur->key.target_type && 146 key->target_class < cur->key.target_class) 147 break; 148 } 149 newnode = avtab_insert_node(h, hvalue, prev, key, datum); 150 151 return newnode; 152 } 153 154 avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * key) 155 { 156 int hvalue; 157 avtab_ptr_t cur; 158 uint16_t specified = 159 key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); 160 161 if (!h || !h->htable) 162 return NULL; 163 164 hvalue = avtab_hash(key, h->mask); 165 for (cur = h->htable[hvalue]; cur; cur = cur->next) { 166 if (key->source_type == cur->key.source_type && 167 key->target_type == cur->key.target_type && 168 key->target_class == cur->key.target_class && 169 (specified & cur->key.specified)) 170 return &cur->datum; 171 172 if (key->source_type < cur->key.source_type) 173 break; 174 if (key->source_type == cur->key.source_type && 175 key->target_type < cur->key.target_type) 176 break; 177 if (key->source_type == cur->key.source_type && 178 key->target_type == cur->key.target_type && 179 key->target_class < cur->key.target_class) 180 break; 181 } 182 183 return NULL; 184 } 185 186 /* This search function returns a node pointer, and can be used in 187 * conjunction with avtab_search_next_node() 188 */ 189 avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key) 190 { 191 int hvalue; 192 avtab_ptr_t cur; 193 uint16_t specified = 194 key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); 195 196 if (!h || !h->htable) 197 return NULL; 198 199 hvalue = avtab_hash(key, h->mask); 200 for (cur = h->htable[hvalue]; cur; cur = cur->next) { 201 if (key->source_type == cur->key.source_type && 202 key->target_type == cur->key.target_type && 203 key->target_class == cur->key.target_class && 204 (specified & cur->key.specified)) 205 return cur; 206 207 if (key->source_type < cur->key.source_type) 208 break; 209 if (key->source_type == cur->key.source_type && 210 key->target_type < cur->key.target_type) 211 break; 212 if (key->source_type == cur->key.source_type && 213 key->target_type == cur->key.target_type && 214 key->target_class < cur->key.target_class) 215 break; 216 } 217 return NULL; 218 } 219 220 avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified) 221 { 222 avtab_ptr_t cur; 223 224 if (!node) 225 return NULL; 226 227 specified &= ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD); 228 for (cur = node->next; cur; cur = cur->next) { 229 if (node->key.source_type == cur->key.source_type && 230 node->key.target_type == cur->key.target_type && 231 node->key.target_class == cur->key.target_class && 232 (specified & cur->key.specified)) 233 return cur; 234 235 if (node->key.source_type < cur->key.source_type) 236 break; 237 if (node->key.source_type == cur->key.source_type && 238 node->key.target_type < cur->key.target_type) 239 break; 240 if (node->key.source_type == cur->key.source_type && 241 node->key.target_type == cur->key.target_type && 242 node->key.target_class < cur->key.target_class) 243 break; 244 } 245 return NULL; 246 } 247 248 void avtab_destroy(avtab_t * h) 249 { 250 unsigned int i; 251 avtab_ptr_t cur, temp; 252 253 if (!h || !h->htable) 254 return; 255 256 for (i = 0; i < h->nslot; i++) { 257 cur = h->htable[i]; 258 while (cur != NULL) { 259 temp = cur; 260 cur = cur->next; 261 free(temp); 262 } 263 h->htable[i] = NULL; 264 } 265 free(h->htable); 266 h->htable = NULL; 267 h->nslot = 0; 268 h->mask = 0; 269 } 270 271 int avtab_map(avtab_t * h, 272 int (*apply) (avtab_key_t * k, 273 avtab_datum_t * d, void *args), void *args) 274 { 275 unsigned int i; 276 int ret; 277 avtab_ptr_t cur; 278 279 if (!h) 280 return 0; 281 282 for (i = 0; i < h->nslot; i++) { 283 cur = h->htable[i]; 284 while (cur != NULL) { 285 ret = apply(&cur->key, &cur->datum, args); 286 if (ret) 287 return ret; 288 cur = cur->next; 289 } 290 } 291 return 0; 292 } 293 294 int avtab_init(avtab_t * h) 295 { 296 h->htable = NULL; 297 h->nel = 0; 298 return 0; 299 } 300 301 int avtab_alloc(avtab_t *h, uint32_t nrules) 302 { 303 uint16_t mask = 0; 304 uint32_t shift = 0; 305 uint32_t work = nrules; 306 uint32_t nslot = 0; 307 308 if (nrules == 0) 309 goto out; 310 311 while (work) { 312 work = work >> 1; 313 shift++; 314 } 315 if (shift > 2) 316 shift = shift - 2; 317 nslot = 1 << shift; 318 if (nslot > MAX_AVTAB_SIZE) 319 nslot = MAX_AVTAB_SIZE; 320 mask = nslot - 1; 321 322 h->htable = calloc(nslot, sizeof(avtab_ptr_t)); 323 if (!h->htable) 324 return -1; 325 out: 326 h->nel = 0; 327 h->nslot = nslot; 328 h->mask = mask; 329 return 0; 330 } 331 332 void avtab_hash_eval(avtab_t * h, char *tag) 333 { 334 unsigned int i, chain_len, slots_used, max_chain_len; 335 avtab_ptr_t cur; 336 337 slots_used = 0; 338 max_chain_len = 0; 339 for (i = 0; i < h->nslot; i++) { 340 cur = h->htable[i]; 341 if (cur) { 342 slots_used++; 343 chain_len = 0; 344 while (cur) { 345 chain_len++; 346 cur = cur->next; 347 } 348 349 if (chain_len > max_chain_len) 350 max_chain_len = chain_len; 351 } 352 } 353 354 printf 355 ("%s: %d entries and %d/%d buckets used, longest chain length %d\n", 356 tag, h->nel, slots_used, h->nslot, max_chain_len); 357 } 358 359 /* Ordering of datums in the original avtab format in the policy file. */ 360 static uint16_t spec_order[] = { 361 AVTAB_ALLOWED, 362 AVTAB_AUDITDENY, 363 AVTAB_AUDITALLOW, 364 AVTAB_TRANSITION, 365 AVTAB_CHANGE, 366 AVTAB_MEMBER 367 }; 368 369 int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, 370 int (*insertf) (avtab_t * a, avtab_key_t * k, 371 avtab_datum_t * d, void *p), void *p) 372 { 373 uint16_t buf16[4], enabled; 374 uint32_t buf32[7], items, items2, val; 375 avtab_key_t key; 376 avtab_datum_t datum; 377 unsigned set; 378 unsigned int i; 379 int rc; 380 381 memset(&key, 0, sizeof(avtab_key_t)); 382 memset(&datum, 0, sizeof(avtab_datum_t)); 383 384 if (vers < POLICYDB_VERSION_AVTAB) { 385 rc = next_entry(buf32, fp, sizeof(uint32_t)); 386 if (rc < 0) { 387 ERR(fp->handle, "truncated entry"); 388 return -1; 389 } 390 items2 = le32_to_cpu(buf32[0]); 391 392 if (items2 < 5 || items2 > ARRAY_SIZE(buf32)) { 393 ERR(fp->handle, "invalid item count"); 394 return -1; 395 } 396 397 rc = next_entry(buf32, fp, sizeof(uint32_t) * items2); 398 if (rc < 0) { 399 ERR(fp->handle, "truncated entry"); 400 return -1; 401 } 402 403 items = 0; 404 val = le32_to_cpu(buf32[items++]); 405 key.source_type = (uint16_t) val; 406 if (key.source_type != val) { 407 ERR(fp->handle, "truncated source type"); 408 return -1; 409 } 410 val = le32_to_cpu(buf32[items++]); 411 key.target_type = (uint16_t) val; 412 if (key.target_type != val) { 413 ERR(fp->handle, "truncated target type"); 414 return -1; 415 } 416 val = le32_to_cpu(buf32[items++]); 417 key.target_class = (uint16_t) val; 418 if (key.target_class != val) { 419 ERR(fp->handle, "truncated target class"); 420 return -1; 421 } 422 423 val = le32_to_cpu(buf32[items++]); 424 enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0; 425 426 if (!(val & (AVTAB_AV | AVTAB_TYPE))) { 427 ERR(fp->handle, "null entry"); 428 return -1; 429 } 430 if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) { 431 ERR(fp->handle, "entry has both access " 432 "vectors and types"); 433 return -1; 434 } 435 436 for (i = 0; i < ARRAY_SIZE(spec_order); i++) { 437 if (val & spec_order[i]) { 438 key.specified = spec_order[i] | enabled; 439 datum.data = le32_to_cpu(buf32[items++]); 440 rc = insertf(a, &key, &datum, p); 441 if (rc) 442 return rc; 443 } 444 } 445 446 if (items != items2) { 447 ERR(fp->handle, "entry only had %d items, " 448 "expected %d", items2, items); 449 return -1; 450 } 451 return 0; 452 } 453 454 rc = next_entry(buf16, fp, sizeof(uint16_t) * 4); 455 if (rc < 0) { 456 ERR(fp->handle, "truncated entry"); 457 return -1; 458 } 459 items = 0; 460 key.source_type = le16_to_cpu(buf16[items++]); 461 key.target_type = le16_to_cpu(buf16[items++]); 462 key.target_class = le16_to_cpu(buf16[items++]); 463 key.specified = le16_to_cpu(buf16[items++]); 464 465 set = 0; 466 for (i = 0; i < ARRAY_SIZE(spec_order); i++) { 467 if (key.specified & spec_order[i]) 468 set++; 469 } 470 if (!set || set > 1) { 471 ERR(fp->handle, "more than one specifier"); 472 return -1; 473 } 474 475 rc = next_entry(buf32, fp, sizeof(uint32_t)); 476 if (rc < 0) { 477 ERR(fp->handle, "truncated entry"); 478 return -1; 479 } 480 datum.data = le32_to_cpu(*buf32); 481 return insertf(a, &key, &datum, p); 482 } 483 484 static int avtab_insertf(avtab_t * a, avtab_key_t * k, avtab_datum_t * d, 485 void *p __attribute__ ((unused))) 486 { 487 return avtab_insert(a, k, d); 488 } 489 490 int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers) 491 { 492 unsigned int i; 493 int rc; 494 uint32_t buf[1]; 495 uint32_t nel; 496 497 rc = next_entry(buf, fp, sizeof(uint32_t)); 498 if (rc < 0) { 499 ERR(fp->handle, "truncated table"); 500 goto bad; 501 } 502 nel = le32_to_cpu(buf[0]); 503 if (!nel) { 504 ERR(fp->handle, "table is empty"); 505 goto bad; 506 } 507 508 rc = avtab_alloc(a, nel); 509 if (rc) { 510 ERR(fp->handle, "out of memory"); 511 goto bad; 512 } 513 514 for (i = 0; i < nel; i++) { 515 rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL); 516 if (rc) { 517 if (rc == SEPOL_ENOMEM) 518 ERR(fp->handle, "out of memory"); 519 if (rc == SEPOL_EEXIST) 520 ERR(fp->handle, "duplicate entry"); 521 ERR(fp->handle, "failed on entry %d of %u", i, nel); 522 goto bad; 523 } 524 } 525 526 return 0; 527 528 bad: 529 avtab_destroy(a); 530 return -1; 531 } 532