Home | History | Annotate | Download | only in src
      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_operations_t *ops;
     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_OP) {
    105 		ops = calloc(1, sizeof(avtab_operations_t));
    106 		if (ops == NULL) {
    107 			free(newnode);
    108 			return NULL;
    109 		}
    110 		if (datum->ops) /* else caller populates ops*/
    111 			*ops = *(datum->ops);
    112 
    113 		newnode->datum.ops = ops;
    114 	} else {
    115 		newnode->datum = *datum;
    116 	}
    117 
    118 	if (prev) {
    119 		newnode->next = prev->next;
    120 		prev->next = newnode;
    121 	} else {
    122 		newnode->next = h->htable[hvalue];
    123 		h->htable[hvalue] = newnode;
    124 	}
    125 
    126 	h->nel++;
    127 	return newnode;
    128 }
    129 
    130 int avtab_insert(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
    131 {
    132 	int hvalue;
    133 	avtab_ptr_t prev, cur, newnode;
    134 	uint16_t specified =
    135 	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
    136 
    137 	if (!h || !h->htable)
    138 		return SEPOL_ENOMEM;
    139 
    140 	hvalue = avtab_hash(key, h->mask);
    141 	for (prev = NULL, cur = h->htable[hvalue];
    142 	     cur; prev = cur, cur = cur->next) {
    143 		if (key->source_type == cur->key.source_type &&
    144 		    key->target_type == cur->key.target_type &&
    145 		    key->target_class == cur->key.target_class &&
    146 		    (specified & cur->key.specified)) {
    147 			if (specified & AVTAB_OPNUM)
    148 				break;
    149 			return SEPOL_EEXIST;
    150 		}
    151 		if (key->source_type < cur->key.source_type)
    152 			break;
    153 		if (key->source_type == cur->key.source_type &&
    154 		    key->target_type < cur->key.target_type)
    155 			break;
    156 		if (key->source_type == cur->key.source_type &&
    157 		    key->target_type == cur->key.target_type &&
    158 		    key->target_class < cur->key.target_class)
    159 			break;
    160 	}
    161 
    162 	newnode = avtab_insert_node(h, hvalue, prev, key, datum);
    163 	if (!newnode)
    164 		return SEPOL_ENOMEM;
    165 
    166 	return 0;
    167 }
    168 
    169 /* Unlike avtab_insert(), this function allow multiple insertions of the same
    170  * key/specified mask into the table, as needed by the conditional avtab.
    171  * It also returns a pointer to the node inserted.
    172  */
    173 avtab_ptr_t
    174 avtab_insert_nonunique(avtab_t * h, avtab_key_t * key, avtab_datum_t * datum)
    175 {
    176 	int hvalue;
    177 	avtab_ptr_t prev, cur, newnode;
    178 	uint16_t specified =
    179 	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
    180 
    181 	if (!h || !h->htable)
    182 		return NULL;
    183 	hvalue = avtab_hash(key, h->mask);
    184 	for (prev = NULL, cur = h->htable[hvalue];
    185 	     cur; prev = cur, cur = cur->next) {
    186 		if (key->source_type == cur->key.source_type &&
    187 		    key->target_type == cur->key.target_type &&
    188 		    key->target_class == cur->key.target_class &&
    189 		    (specified & cur->key.specified))
    190 			break;
    191 		if (key->source_type < cur->key.source_type)
    192 			break;
    193 		if (key->source_type == cur->key.source_type &&
    194 		    key->target_type < cur->key.target_type)
    195 			break;
    196 		if (key->source_type == cur->key.source_type &&
    197 		    key->target_type == cur->key.target_type &&
    198 		    key->target_class < cur->key.target_class)
    199 			break;
    200 	}
    201 	newnode = avtab_insert_node(h, hvalue, prev, key, datum);
    202 
    203 	return newnode;
    204 }
    205 
    206 avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * key)
    207 {
    208 	int hvalue;
    209 	avtab_ptr_t cur;
    210 	uint16_t specified =
    211 	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
    212 
    213 	if (!h || !h->htable)
    214 		return NULL;
    215 
    216 	hvalue = avtab_hash(key, h->mask);
    217 	for (cur = h->htable[hvalue]; cur; cur = cur->next) {
    218 		if (key->source_type == cur->key.source_type &&
    219 		    key->target_type == cur->key.target_type &&
    220 		    key->target_class == cur->key.target_class &&
    221 		    (specified & cur->key.specified))
    222 			return &cur->datum;
    223 
    224 		if (key->source_type < cur->key.source_type)
    225 			break;
    226 		if (key->source_type == cur->key.source_type &&
    227 		    key->target_type < cur->key.target_type)
    228 			break;
    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 			break;
    233 	}
    234 
    235 	return NULL;
    236 }
    237 
    238 /* This search function returns a node pointer, and can be used in
    239  * conjunction with avtab_search_next_node()
    240  */
    241 avtab_ptr_t avtab_search_node(avtab_t * h, avtab_key_t * key)
    242 {
    243 	int hvalue;
    244 	avtab_ptr_t cur;
    245 	uint16_t specified =
    246 	    key->specified & ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
    247 
    248 	if (!h || !h->htable)
    249 		return NULL;
    250 
    251 	hvalue = avtab_hash(key, h->mask);
    252 	for (cur = h->htable[hvalue]; cur; cur = cur->next) {
    253 		if (key->source_type == cur->key.source_type &&
    254 		    key->target_type == cur->key.target_type &&
    255 		    key->target_class == cur->key.target_class &&
    256 		    (specified & cur->key.specified))
    257 			return cur;
    258 
    259 		if (key->source_type < cur->key.source_type)
    260 			break;
    261 		if (key->source_type == cur->key.source_type &&
    262 		    key->target_type < cur->key.target_type)
    263 			break;
    264 		if (key->source_type == cur->key.source_type &&
    265 		    key->target_type == cur->key.target_type &&
    266 		    key->target_class < cur->key.target_class)
    267 			break;
    268 	}
    269 	return NULL;
    270 }
    271 
    272 avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified)
    273 {
    274 	avtab_ptr_t cur;
    275 
    276 	if (!node)
    277 		return NULL;
    278 
    279 	specified &= ~(AVTAB_ENABLED | AVTAB_ENABLED_OLD);
    280 	for (cur = node->next; cur; cur = cur->next) {
    281 		if (node->key.source_type == cur->key.source_type &&
    282 		    node->key.target_type == cur->key.target_type &&
    283 		    node->key.target_class == cur->key.target_class &&
    284 		    (specified & cur->key.specified))
    285 			return cur;
    286 
    287 		if (node->key.source_type < cur->key.source_type)
    288 			break;
    289 		if (node->key.source_type == cur->key.source_type &&
    290 		    node->key.target_type < cur->key.target_type)
    291 			break;
    292 		if (node->key.source_type == cur->key.source_type &&
    293 		    node->key.target_type == cur->key.target_type &&
    294 		    node->key.target_class < cur->key.target_class)
    295 			break;
    296 	}
    297 	return NULL;
    298 }
    299 
    300 void avtab_destroy(avtab_t * h)
    301 {
    302 	unsigned int i;
    303 	avtab_ptr_t cur, temp;
    304 
    305 	if (!h || !h->htable)
    306 		return;
    307 
    308 	for (i = 0; i < h->nslot; i++) {
    309 		cur = h->htable[i];
    310 		while (cur != NULL) {
    311 			temp = cur;
    312 			cur = cur->next;
    313 			free(temp);
    314 		}
    315 		h->htable[i] = NULL;
    316 	}
    317 	free(h->htable);
    318 	h->htable = NULL;
    319 	h->nslot = 0;
    320 	h->mask = 0;
    321 }
    322 
    323 int avtab_map(avtab_t * h,
    324 	      int (*apply) (avtab_key_t * k,
    325 			    avtab_datum_t * d, void *args), void *args)
    326 {
    327 	unsigned int i;
    328 	int ret;
    329 	avtab_ptr_t cur;
    330 
    331 	if (!h)
    332 		return 0;
    333 
    334 	for (i = 0; i < h->nslot; i++) {
    335 		cur = h->htable[i];
    336 		while (cur != NULL) {
    337 			ret = apply(&cur->key, &cur->datum, args);
    338 			if (ret)
    339 				return ret;
    340 			cur = cur->next;
    341 		}
    342 	}
    343 	return 0;
    344 }
    345 
    346 int avtab_init(avtab_t * h)
    347 {
    348 	h->htable = NULL;
    349 	h->nel = 0;
    350 	return 0;
    351 }
    352 
    353 int avtab_alloc(avtab_t *h, uint32_t nrules)
    354 {
    355 	uint32_t mask = 0;
    356 	uint32_t shift = 0;
    357 	uint32_t work = nrules;
    358 	uint32_t nslot = 0;
    359 
    360 	if (nrules == 0)
    361 		goto out;
    362 
    363 	while (work) {
    364 		work  = work >> 1;
    365 		shift++;
    366 	}
    367 	if (shift > 2)
    368 		shift = shift - 2;
    369 	nslot = 1 << shift;
    370 	if (nslot > MAX_AVTAB_HASH_BUCKETS)
    371 		nslot = MAX_AVTAB_HASH_BUCKETS;
    372 	mask = nslot - 1;
    373 
    374 	h->htable = calloc(nslot, sizeof(avtab_ptr_t));
    375 	if (!h->htable)
    376 		return -1;
    377 out:
    378 	h->nel = 0;
    379 	h->nslot = nslot;
    380 	h->mask = mask;
    381 	return 0;
    382 }
    383 
    384 void avtab_hash_eval(avtab_t * h, char *tag)
    385 {
    386 	unsigned int i, chain_len, slots_used, max_chain_len;
    387 	avtab_ptr_t cur;
    388 
    389 	slots_used = 0;
    390 	max_chain_len = 0;
    391 	for (i = 0; i < h->nslot; i++) {
    392 		cur = h->htable[i];
    393 		if (cur) {
    394 			slots_used++;
    395 			chain_len = 0;
    396 			while (cur) {
    397 				chain_len++;
    398 				cur = cur->next;
    399 			}
    400 
    401 			if (chain_len > max_chain_len)
    402 				max_chain_len = chain_len;
    403 		}
    404 	}
    405 
    406 	printf
    407 	    ("%s:  %d entries and %d/%d buckets used, longest chain length %d\n",
    408 	     tag, h->nel, slots_used, h->nslot, max_chain_len);
    409 }
    410 
    411 /* Ordering of datums in the original avtab format in the policy file. */
    412 static uint16_t spec_order[] = {
    413 	AVTAB_ALLOWED,
    414 	AVTAB_AUDITDENY,
    415 	AVTAB_AUDITALLOW,
    416 	AVTAB_TRANSITION,
    417 	AVTAB_CHANGE,
    418 	AVTAB_MEMBER,
    419 	AVTAB_OPNUM_ALLOWED,
    420 	AVTAB_OPNUM_AUDITALLOW,
    421 	AVTAB_OPNUM_DONTAUDIT,
    422 	AVTAB_OPTYPE_ALLOWED,
    423 	AVTAB_OPTYPE_AUDITALLOW,
    424 	AVTAB_OPTYPE_DONTAUDIT
    425 };
    426 
    427 int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
    428 		    int (*insertf) (avtab_t * a, avtab_key_t * k,
    429 				    avtab_datum_t * d, void *p), void *p)
    430 {
    431 	uint8_t buf8;
    432 	uint16_t buf16[4], enabled;
    433 	uint32_t buf32[8], items, items2, val;
    434 	avtab_key_t key;
    435 	avtab_datum_t datum;
    436 	avtab_operations_t ops;
    437 	unsigned set;
    438 	unsigned int i;
    439 	int rc;
    440 
    441 	memset(&key, 0, sizeof(avtab_key_t));
    442 	memset(&datum, 0, sizeof(avtab_datum_t));
    443 	memset(&ops, 0, sizeof(avtab_operations_t));
    444 
    445 	if (vers < POLICYDB_VERSION_AVTAB) {
    446 		rc = next_entry(buf32, fp, sizeof(uint32_t));
    447 		if (rc < 0) {
    448 			ERR(fp->handle, "truncated entry");
    449 			return -1;
    450 		}
    451 		items2 = le32_to_cpu(buf32[0]);
    452 
    453 		if (items2 < 5 || items2 > ARRAY_SIZE(buf32)) {
    454 			ERR(fp->handle, "invalid item count");
    455 			return -1;
    456 		}
    457 
    458 		rc = next_entry(buf32, fp, sizeof(uint32_t) * items2);
    459 		if (rc < 0) {
    460 			ERR(fp->handle, "truncated entry");
    461 			return -1;
    462 		}
    463 
    464 		items = 0;
    465 		val = le32_to_cpu(buf32[items++]);
    466 		key.source_type = (uint16_t) val;
    467 		if (key.source_type != val) {
    468 			ERR(fp->handle, "truncated source type");
    469 			return -1;
    470 		}
    471 		val = le32_to_cpu(buf32[items++]);
    472 		key.target_type = (uint16_t) val;
    473 		if (key.target_type != val) {
    474 			ERR(fp->handle, "truncated target type");
    475 			return -1;
    476 		}
    477 		val = le32_to_cpu(buf32[items++]);
    478 		key.target_class = (uint16_t) val;
    479 		if (key.target_class != val) {
    480 			ERR(fp->handle, "truncated target class");
    481 			return -1;
    482 		}
    483 
    484 		val = le32_to_cpu(buf32[items++]);
    485 		enabled = (val & AVTAB_ENABLED_OLD) ? AVTAB_ENABLED : 0;
    486 
    487 		if (!(val & (AVTAB_AV | AVTAB_TYPE))) {
    488 			ERR(fp->handle, "null entry");
    489 			return -1;
    490 		}
    491 		if ((val & AVTAB_AV) && (val & AVTAB_TYPE)) {
    492 			ERR(fp->handle, "entry has both access "
    493 			    "vectors and types");
    494 			return -1;
    495 		}
    496 
    497 		for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
    498 			if (val & spec_order[i]) {
    499 				key.specified = spec_order[i] | enabled;
    500 				datum.data = le32_to_cpu(buf32[items++]);
    501 				rc = insertf(a, &key, &datum, p);
    502 				if (rc)
    503 					return rc;
    504 			}
    505 		}
    506 
    507 		if (items != items2) {
    508 			ERR(fp->handle, "entry only had %d items, "
    509 			    "expected %d", items2, items);
    510 			return -1;
    511 		}
    512 		return 0;
    513 	}
    514 
    515 	rc = next_entry(buf16, fp, sizeof(uint16_t) * 4);
    516 	if (rc < 0) {
    517 		ERR(fp->handle, "truncated entry");
    518 		return -1;
    519 	}
    520 	items = 0;
    521 	key.source_type = le16_to_cpu(buf16[items++]);
    522 	key.target_type = le16_to_cpu(buf16[items++]);
    523 	key.target_class = le16_to_cpu(buf16[items++]);
    524 	key.specified = le16_to_cpu(buf16[items++]);
    525 
    526 	set = 0;
    527 	for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
    528 		if (key.specified & spec_order[i])
    529 			set++;
    530 	}
    531 	if (!set || set > 1) {
    532 		ERR(fp->handle, "more than one specifier");
    533 		return -1;
    534 	}
    535 
    536 	if ((vers < POLICYDB_VERSION_IOCTL_OPERATIONS) &&
    537 			(key.specified & AVTAB_OP)) {
    538 		ERR(fp->handle, "policy version %u does not support ioctl "
    539 				"operation rules and one was specified\n", vers);
    540 		return -1;
    541 	} else if (key.specified & AVTAB_OP) {
    542 		rc = next_entry(&buf8, fp, sizeof(uint8_t));
    543 		if (rc < 0) {
    544 			ERR(fp->handle, "truncated entry");
    545 			return -1;
    546 		}
    547 		ops.type = buf8;
    548 		rc = next_entry(buf32, fp, sizeof(uint32_t)*8);
    549 		if (rc < 0) {
    550 			ERR(fp->handle, "truncated entry");
    551 			return -1;
    552 		}
    553 		for (i = 0; i < ARRAY_SIZE(ops.perms); i++)
    554 			ops.perms[i] = le32_to_cpu(buf32[i]);
    555 		datum.ops = &ops;
    556 	} else {
    557 		rc = next_entry(buf32, fp, sizeof(uint32_t));
    558 		if (rc < 0) {
    559 			ERR(fp->handle, "truncated entry");
    560 			return -1;
    561 		}
    562 		datum.data = le32_to_cpu(*buf32);
    563 	}
    564 	return insertf(a, &key, &datum, p);
    565 }
    566 
    567 static int avtab_insertf(avtab_t * a, avtab_key_t * k, avtab_datum_t * d,
    568 			 void *p __attribute__ ((unused)))
    569 {
    570 	return avtab_insert(a, k, d);
    571 }
    572 
    573 int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers)
    574 {
    575 	unsigned int i;
    576 	int rc;
    577 	uint32_t buf[1];
    578 	uint32_t nel;
    579 
    580 	rc = next_entry(buf, fp, sizeof(uint32_t));
    581 	if (rc < 0) {
    582 		ERR(fp->handle, "truncated table");
    583 		goto bad;
    584 	}
    585 	nel = le32_to_cpu(buf[0]);
    586 	if (!nel) {
    587 		ERR(fp->handle, "table is empty");
    588 		goto bad;
    589 	}
    590 
    591 	rc = avtab_alloc(a, nel);
    592 	if (rc) {
    593 		ERR(fp->handle, "out of memory");
    594 		goto bad;
    595 	}
    596 
    597 	for (i = 0; i < nel; i++) {
    598 		rc = avtab_read_item(fp, vers, a, avtab_insertf, NULL);
    599 		if (rc) {
    600 			if (rc == SEPOL_ENOMEM)
    601 				ERR(fp->handle, "out of memory");
    602 			if (rc == SEPOL_EEXIST)
    603 				ERR(fp->handle, "duplicate entry");
    604 			ERR(fp->handle, "failed on entry %d of %u", i, nel);
    605 			goto bad;
    606 		}
    607 	}
    608 
    609 	return 0;
    610 
    611       bad:
    612 	avtab_destroy(a);
    613 	return -1;
    614 }
    615