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