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 */
avtab_hash(struct avtab_key * keyp,uint32_t mask)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
avtab_insert_node(avtab_t * h,int hvalue,avtab_ptr_t prev,avtab_key_t * key,avtab_datum_t * datum)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
avtab_insert(avtab_t * h,avtab_key_t * key,avtab_datum_t * datum)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
avtab_insert_nonunique(avtab_t * h,avtab_key_t * key,avtab_datum_t * datum)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
avtab_search(avtab_t * h,avtab_key_t * key)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 */
avtab_search_node(avtab_t * h,avtab_key_t * key)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
avtab_search_node_next(avtab_ptr_t node,int specified)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
avtab_destroy(avtab_t * h)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
avtab_map(avtab_t * h,int (* apply)(avtab_key_t * k,avtab_datum_t * d,void * args),void * args)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
avtab_init(avtab_t * h)355 int avtab_init(avtab_t * h)
356 {
357 h->htable = NULL;
358 h->nel = 0;
359 return 0;
360 }
361
avtab_alloc(avtab_t * h,uint32_t nrules)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
avtab_hash_eval(avtab_t * h,char * tag)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
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)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
avtab_insertf(avtab_t * a,avtab_key_t * k,avtab_datum_t * d,void * p)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
avtab_read(avtab_t * a,struct policy_file * fp,uint32_t vers)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