blob: afebd69708afc6057ce5c84588a14212b140d50c [file] [log] [blame]
Stephen Smalley7b2bee92013-10-31 09:22:26 -04001#include <getopt.h>
2#include <unistd.h>
3#include <stddef.h>
4#include <stdlib.h>
5#include <sys/mman.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <stdio.h>
10#include <sepol/policydb/policydb.h>
11#include <sepol/policydb/services.h>
12#include <sepol/policydb/expand.h>
13#include <sepol/policydb/util.h>
Stephen Smalley43b9cfd2014-06-17 14:32:46 -040014#include <stdbool.h>
Nick Kralevich74bbf702014-10-14 20:35:12 -070015#include <ctype.h>
Stephen Smalley7b2bee92013-10-31 09:22:26 -040016
Stephen Smalley59906bf2014-10-07 13:46:59 -040017static int debug;
18static int warn;
19
Stephen Smalley7b2bee92013-10-31 09:22:26 -040020void usage(char *arg0)
21{
Stephen Smalley59906bf2014-10-07 13:46:59 -040022 fprintf(stderr, "%s [-w|--warn] [-z|--debug] [-e|--equiv] [-d|--diff] [-D|--dups] [-p|--permissive] [-n|--neverallow <neverallow file>] -P <policy file>\n", arg0);
Stephen Smalley7b2bee92013-10-31 09:22:26 -040023 exit(1);
24}
25
26int load_policy(char *filename, policydb_t * policydb, struct policy_file *pf)
27{
28 int fd;
29 struct stat sb;
30 void *map;
31 int ret;
32
33 fd = open(filename, O_RDONLY);
34 if (fd < 0) {
35 fprintf(stderr, "Can't open '%s': %s\n", filename, strerror(errno));
36 return 1;
37 }
38 if (fstat(fd, &sb) < 0) {
39 fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno));
40 close(fd);
41 return 1;
42 }
43 map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
44 if (map == MAP_FAILED) {
45 fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno));
46 close(fd);
47 return 1;
48 }
49
50 policy_file_init(pf);
51 pf->type = PF_USE_MEMORY;
52 pf->data = map;
53 pf->len = sb.st_size;
54 if (policydb_init(policydb)) {
55 fprintf(stderr, "Could not initialize policydb!\n");
56 close(fd);
57 munmap(map, sb.st_size);
58 return 1;
59 }
60 ret = policydb_read(policydb, pf, 0);
61 if (ret) {
62 fprintf(stderr, "error(s) encountered while parsing configuration\n");
63 close(fd);
64 munmap(map, sb.st_size);
65 return 1;
66 }
67
68 return 0;
69}
70
71static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
72 struct avtab_node *type_rules)
73{
74 struct avtab_node *p, *c, *n;
75
76 for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
77 /*
78 * Find the insertion point, keeping the list
79 * ordered by source type, then target type, then
80 * target class.
81 */
82 if (k->source_type < c->key.source_type)
83 break;
84 if (k->source_type == c->key.source_type &&
85 k->target_type < c->key.target_type)
86 break;
87 if (k->source_type == c->key.source_type &&
88 k->target_type == c->key.target_type &&
89 k->target_class <= c->key.target_class)
90 break;
91 }
92
93 if (c &&
94 k->source_type == c->key.source_type &&
95 k->target_type == c->key.target_type &&
96 k->target_class == c->key.target_class) {
97 c->datum.data |= d->data;
98 return 0;
99 }
100
101 /* Insert the rule */
102 n = malloc(sizeof(struct avtab_node));
103 if (!n) {
104 fprintf(stderr, "out of memory\n");
105 exit(1);
106 }
107
108 n->key = *k;
109 n->datum = *d;
110 n->next = p->next;
111 p->next = n;
112 return 0;
113}
114
115static int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d,
116 void *args)
117{
118 struct avtab_node *type_rules = args;
119 avtab_key_t key;
120
121 /*
122 * Insert the rule into the list for
123 * the source type. The source type value
124 * is cleared as we want to compare against other type
125 * rules with different source types.
126 */
127 key = *k;
128 key.source_type = 0;
129 if (k->source_type == k->target_type) {
130 /* Clear target type as well; this is a self rule. */
131 key.target_type = 0;
132 }
133 if (insert_type_rule(&key, d, &type_rules[k->source_type - 1]))
134 return -1;
135
136 if (k->source_type == k->target_type)
137 return 0;
138
139 /*
140 * If the target type differs, then we also
141 * insert the rule into the list for the target
142 * type. We clear the target type value so that
143 * we can compare against other type rules with
144 * different target types.
145 */
146 key = *k;
147 key.target_type = 0;
148 if (insert_type_rule(&key, d, &type_rules[k->target_type - 1]))
149 return -1;
150
151 return 0;
152}
153
154static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
155{
156 if (k->specified & AVTAB_ALLOWED)
157 return create_type_rules_helper(k, d, args);
158 return 0;
159}
160
161static int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d,
162 void *args)
163{
164 if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) ==
165 (AVTAB_ALLOWED|AVTAB_ENABLED))
166 return create_type_rules_helper(k, d, args);
167 return 0;
168}
169
170static void free_type_rules(struct avtab_node *l)
171{
172 struct avtab_node *tmp;
173
174 while (l) {
175 tmp = l;
176 l = l->next;
177 free(tmp);
178 }
179}
180
Stephen Smalleybec54f42013-11-17 18:17:29 -0500181static void display_allow(policydb_t *policydb, avtab_key_t *key, int idx,
182 uint32_t perms)
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400183{
184 printf(" allow %s %s:%s { %s };\n",
Stephen Smalleybec54f42013-11-17 18:17:29 -0500185 policydb->p_type_val_to_name[key->source_type
186 ? key->source_type - 1 : idx],
187 key->target_type == key->source_type ? "self" :
188 policydb->p_type_val_to_name[key->target_type
189 ? key->target_type - 1 : idx],
190 policydb->p_class_val_to_name[key->target_class - 1],
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400191 sepol_av_to_string
Stephen Smalleybec54f42013-11-17 18:17:29 -0500192 (policydb, key->target_class, perms));
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400193}
194
195static int find_match(policydb_t *policydb, struct avtab_node *l1,
196 int idx1, struct avtab_node *l2, int idx2)
197{
198 struct avtab_node *c;
199 uint32_t perms1, perms2;
200
201 for (c = l2; c; c = c->next) {
202 if (l1->key.source_type < c->key.source_type)
203 break;
204 if (l1->key.source_type == c->key.source_type &&
205 l1->key.target_type < c->key.target_type)
206 break;
207 if (l1->key.source_type == c->key.source_type &&
208 l1->key.target_type == c->key.target_type &&
209 l1->key.target_class <= c->key.target_class)
210 break;
211 }
212
213 if (c &&
214 l1->key.source_type == c->key.source_type &&
215 l1->key.target_type == c->key.target_type &&
216 l1->key.target_class == c->key.target_class) {
217 perms1 = l1->datum.data & ~c->datum.data;
218 perms2 = c->datum.data & ~l1->datum.data;
219 if (perms1 || perms2) {
220 if (perms1)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500221 display_allow(policydb, &l1->key, idx1, perms1);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400222 if (perms2)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500223 display_allow(policydb, &c->key, idx2, perms2);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400224 printf("\n");
225 return 1;
226 }
227 }
228
229 return 0;
230}
231
232static int analyze_types(policydb_t * policydb, char equiv, char diff)
233{
234 avtab_t exp_avtab, exp_cond_avtab;
235 struct avtab_node *type_rules, *l1, *l2;
236 struct type_datum *type;
237 size_t i, j;
238
239 /*
240 * Create a list of access vector rules for each type
241 * from the access vector table.
242 */
243 type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim);
244 if (!type_rules) {
245 fprintf(stderr, "out of memory\n");
246 exit(1);
247 }
248 memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim);
249
250 if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) {
251 fputs("out of memory\n", stderr);
252 return -1;
253 }
254
255 if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) {
256 fputs("out of memory\n", stderr);
257 avtab_destroy(&exp_avtab);
258 return -1;
259 }
260
261 if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) {
262 fputs("out of memory\n", stderr);
263 avtab_destroy(&exp_avtab);
264 return -1;
265 }
266
267 if (avtab_map(&exp_avtab, create_type_rules, type_rules))
268 exit(1);
269
270 if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules))
271 exit(1);
272
273 avtab_destroy(&exp_avtab);
274 avtab_destroy(&exp_cond_avtab);
275
276 /*
277 * Compare the type lists and identify similar types.
278 */
279 for (i = 0; i < policydb->p_types.nprim - 1; i++) {
280 if (!type_rules[i].next)
281 continue;
282 type = policydb->type_val_to_struct[i];
283 if (type->flavor) {
284 free_type_rules(type_rules[i].next);
285 type_rules[i].next = NULL;
286 continue;
287 }
288 for (j = i + 1; j < policydb->p_types.nprim; j++) {
289 type = policydb->type_val_to_struct[j];
290 if (type->flavor) {
291 free_type_rules(type_rules[j].next);
292 type_rules[j].next = NULL;
293 continue;
294 }
295 for (l1 = type_rules[i].next, l2 = type_rules[j].next;
296 l1 && l2; l1 = l1->next, l2 = l2->next) {
297 if (l1->key.source_type != l2->key.source_type)
298 break;
299 if (l1->key.target_type != l2->key.target_type)
300 break;
301 if (l1->key.target_class != l2->key.target_class
302 || l1->datum.data != l2->datum.data)
303 break;
304 }
305 if (l1 || l2) {
306 if (diff) {
307 printf
308 ("Types %s and %s differ, starting with:\n",
309 policydb->p_type_val_to_name[i],
310 policydb->p_type_val_to_name[j]);
311
312 if (l1 && l2) {
313 if (find_match(policydb, l1, i, l2, j))
314 continue;
315 if (find_match(policydb, l2, j, l1, i))
316 continue;
317 }
318 if (l1)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500319 display_allow(policydb, &l1->key, i, l1->datum.data);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400320 if (l2)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500321 display_allow(policydb, &l2->key, j, l2->datum.data);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400322 printf("\n");
323 }
324 continue;
325 }
326 free_type_rules(type_rules[j].next);
327 type_rules[j].next = NULL;
328 if (equiv) {
329 printf("Types %s and %s are equivalent.\n",
330 policydb->p_type_val_to_name[i],
331 policydb->p_type_val_to_name[j]);
332 }
333 }
334 free_type_rules(type_rules[i].next);
335 type_rules[i].next = NULL;
336 }
337
338 free(type_rules);
339 return 0;
340}
341
Stephen Smalleybec54f42013-11-17 18:17:29 -0500342static int find_dups_helper(avtab_key_t * k, avtab_datum_t * d,
343 void *args)
344{
345 policydb_t *policydb = args;
346 ebitmap_t *sattr, *tattr;
347 ebitmap_node_t *snode, *tnode;
348 unsigned int i, j;
349 avtab_key_t avkey;
350 avtab_ptr_t node;
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400351 struct type_datum *stype, *ttype, *stype2, *ttype2;
352 bool attrib1, attrib2;
Stephen Smalleybec54f42013-11-17 18:17:29 -0500353
354 if (!(k->specified & AVTAB_ALLOWED))
355 return 0;
356
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400357 if (k->source_type == k->target_type)
358 return 0; /* self rule */
359
Stephen Smalleybec54f42013-11-17 18:17:29 -0500360 avkey.target_class = k->target_class;
361 avkey.specified = k->specified;
362
363 sattr = &policydb->type_attr_map[k->source_type - 1];
364 tattr = &policydb->type_attr_map[k->target_type - 1];
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400365 stype = policydb->type_val_to_struct[k->source_type - 1];
366 ttype = policydb->type_val_to_struct[k->target_type - 1];
367 attrib1 = stype->flavor || ttype->flavor;
Stephen Smalleybec54f42013-11-17 18:17:29 -0500368 ebitmap_for_each_bit(sattr, snode, i) {
369 if (!ebitmap_node_get_bit(snode, i))
370 continue;
371 ebitmap_for_each_bit(tattr, tnode, j) {
372 if (!ebitmap_node_get_bit(tnode, j))
373 continue;
374 avkey.source_type = i + 1;
375 avkey.target_type = j + 1;
376 if (avkey.source_type == k->source_type &&
377 avkey.target_type == k->target_type)
378 continue;
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400379 if (avkey.source_type == avkey.target_type)
380 continue; /* self rule */
381 stype2 = policydb->type_val_to_struct[avkey.source_type - 1];
382 ttype2 = policydb->type_val_to_struct[avkey.target_type - 1];
383 attrib2 = stype2->flavor || ttype2->flavor;
384 if (attrib1 && attrib2)
385 continue; /* overlapping attribute-based rules */
Stephen Smalleybec54f42013-11-17 18:17:29 -0500386 for (node = avtab_search_node(&policydb->te_avtab, &avkey);
387 node != NULL;
388 node = avtab_search_node_next(node, avkey.specified)) {
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400389 uint32_t perms = node->datum.data & d->data;
390 if ((attrib1 && perms == node->datum.data) ||
391 (attrib2 && perms == d->data)) {
392 /*
393 * The attribute-based rule is a superset of the
394 * non-attribute-based rule. This is a dup.
395 */
Stephen Smalleybec54f42013-11-17 18:17:29 -0500396 printf("Duplicate allow rule found:\n");
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400397 display_allow(policydb, k, i, d->data);
398 display_allow(policydb, &node->key, i, node->datum.data);
Stephen Smalleybec54f42013-11-17 18:17:29 -0500399 printf("\n");
400 }
401 }
402 }
403 }
404
405 return 0;
406}
407
408static int find_dups(policydb_t * policydb)
409{
410 if (avtab_map(&policydb->te_avtab, find_dups_helper, policydb))
411 return -1;
412 return 0;
413}
414
dcashman9793ea72014-03-25 16:27:56 -0700415static int list_permissive(policydb_t * policydb)
416{
417 struct ebitmap_node *n;
418 unsigned int bit;
419
420 /*
421 * iterate over all domains and check if domain is in permissive
422 */
423 ebitmap_for_each_bit(&policydb->permissive_map, n, bit)
424 {
425 if (ebitmap_node_get_bit(n, bit)) {
426 printf("%s\n", policydb->p_type_val_to_name[bit -1]);
427 }
428 }
429 return 0;
430}
431
Stephen Smalley59906bf2014-10-07 13:46:59 -0400432static int read_typeset(policydb_t *policydb, char **ptr, char *end,
433 type_set_t *typeset, uint32_t *flags)
434{
435 const char *keyword = "self";
436 size_t keyword_size = strlen(keyword), len;
437 char *p = *ptr;
438 unsigned openparens = 0;
439 char *start, *id;
440 type_datum_t *type;
441 struct ebitmap_node *n;
442 unsigned int bit;
443 bool negate = false;
444 int rc;
445
446 do {
447 while (p < end && isspace(*p))
448 p++;
449
450 if (p == end)
451 goto err;
452
453 if (*p == '~') {
454 if (debug)
455 printf(" ~");
456 typeset->flags = TYPE_COMP;
457 p++;
458 while (p < end && isspace(*p))
459 p++;
460 if (p == end)
461 goto err;
462 }
463
464 if (*p == '{') {
465 if (debug && !openparens)
466 printf(" {");
467 openparens++;
468 p++;
469 continue;
470 }
471
472 if (*p == '}') {
473 if (debug && openparens == 1)
474 printf(" }");
475 if (openparens == 0)
476 goto err;
477 openparens--;
478 p++;
479 continue;
480 }
481
482 if (*p == '*') {
483 if (debug)
484 printf(" *");
485 typeset->flags = TYPE_STAR;
486 p++;
487 continue;
488 }
489
490 if (*p == '-') {
491 if (debug)
492 printf(" -");
493 negate = true;
494 p++;
495 continue;
496 }
497
498 if (*p == '#') {
499 while (p < end && *p != '\n')
500 p++;
501 continue;
502 }
503
504 start = p;
505 while (p < end && !isspace(*p) && *p != ':' && *p != ';' && *p != '{' && *p != '}' && *p != '#')
506 p++;
507
508 if (p == start)
509 goto err;
510
511 len = p - start;
512 if (len == keyword_size && !strncmp(start, keyword, keyword_size)) {
513 if (debug)
514 printf(" self");
515 *flags |= RULE_SELF;
516 continue;
517 }
518
519 id = calloc(1, len + 1);
520 if (!id)
521 goto err;
522 memcpy(id, start, len);
523 if (debug)
524 printf(" %s", id);
525 type = hashtab_search(policydb->p_types.table, id);
526 if (!type) {
527 if (warn)
528 fprintf(stderr, "Warning! Type or attribute %s used in neverallow undefined in policy being checked.\n", id);
529 negate = false;
530 continue;
531 }
532 free(id);
533
534 if (type->flavor == TYPE_ATTRIB) {
535 if (negate)
536 rc = ebitmap_union(&typeset->negset, &policydb->attr_type_map[type->s.value - 1]);
537 else
538 rc = ebitmap_union(&typeset->types, &policydb->attr_type_map[type->s.value - 1]);
539 } else if (negate) {
540 rc = ebitmap_set_bit(&typeset->negset, type->s.value - 1, 1);
541 } else {
542 rc = ebitmap_set_bit(&typeset->types, type->s.value - 1, 1);
543 }
544
545 negate = false;
546
547 if (rc)
548 goto err;
549
550 } while (p < end && openparens);
551
552 if (p == end)
553 goto err;
554
555 if (typeset->flags & TYPE_STAR) {
556 for (bit = 0; bit < policydb->p_types.nprim; bit++) {
557 if (ebitmap_get_bit(&typeset->negset, bit))
558 continue;
559 if (policydb->type_val_to_struct[bit] &&
560 policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB)
561 continue;
562 if (ebitmap_set_bit(&typeset->types, bit, 1))
563 goto err;
564 }
565 }
566
567 ebitmap_for_each_bit(&typeset->negset, n, bit) {
568 if (!ebitmap_node_get_bit(n, bit))
569 continue;
570 if (ebitmap_set_bit(&typeset->types, bit, 0))
571 goto err;
572 }
573
574 if (typeset->flags & TYPE_COMP) {
575 for (bit = 0; bit < policydb->p_types.nprim; bit++) {
576 if (policydb->type_val_to_struct[bit] &&
577 policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB)
578 continue;
579 if (ebitmap_get_bit(&typeset->types, bit))
580 ebitmap_set_bit(&typeset->types, bit, 0);
581 else {
582 if (ebitmap_set_bit(&typeset->types, bit, 1))
583 goto err;
584 }
585 }
586 }
587
588 if (warn && ebitmap_length(&typeset->types) == 0 && !(*flags))
589 fprintf(stderr, "Warning! Empty type set\n");
590
591 *ptr = p;
592 return 0;
593err:
594 return -1;
595}
596
597static int read_classperms(policydb_t *policydb, char **ptr, char *end,
598 class_perm_node_t **perms)
599{
600 char *p = *ptr;
601 unsigned openparens = 0;
602 char *id, *start;
603 class_datum_t *cls = NULL;
604 perm_datum_t *perm = NULL;
605 class_perm_node_t *classperms = NULL, *node = NULL;
606 bool complement = false;
607
608 while (p < end && isspace(*p))
609 p++;
610
611 if (p == end || *p != ':')
612 goto err;
613 p++;
614
615 if (debug)
616 printf(" :");
617
618 do {
619 while (p < end && isspace(*p))
620 p++;
621
622 if (p == end)
623 goto err;
624
625 if (*p == '{') {
626 if (debug && !openparens)
627 printf(" {");
628 openparens++;
629 p++;
630 continue;
631 }
632
633 if (*p == '}') {
634 if (debug && openparens == 1)
635 printf(" }");
636 if (openparens == 0)
637 goto err;
638 openparens--;
639 p++;
640 continue;
641 }
642
643 if (*p == '#') {
644 while (p < end && *p != '\n')
645 p++;
646 continue;
647 }
648
649 start = p;
650 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#')
651 p++;
652
653 if (p == start)
654 goto err;
655
656 id = calloc(1, p - start + 1);
657 if (!id)
658 goto err;
659 memcpy(id, start, p - start);
660 if (debug)
661 printf(" %s", id);
662 cls = hashtab_search(policydb->p_classes.table, id);
663 if (!cls) {
664 if (warn)
665 fprintf(stderr, "Warning! Class %s used in neverallow undefined in policy being checked.\n", id);
666 continue;
667 }
668
669 node = calloc(1, sizeof *node);
670 if (!node)
671 goto err;
672 node->class = cls->s.value;
673 node->next = classperms;
674 classperms = node;
675 free(id);
676 } while (p < end && openparens);
677
678 if (p == end)
679 goto err;
680
681 if (warn && !classperms)
682 fprintf(stderr, "Warning! Empty class set\n");
683
684 do {
685 while (p < end && isspace(*p))
686 p++;
687
688 if (p == end)
689 goto err;
690
691 if (*p == '~') {
692 if (debug)
693 printf(" ~");
694 complement = true;
695 p++;
696 while (p < end && isspace(*p))
697 p++;
698 if (p == end)
699 goto err;
700 }
701
702 if (*p == '{') {
703 if (debug && !openparens)
704 printf(" {");
705 openparens++;
706 p++;
707 continue;
708 }
709
710 if (*p == '}') {
711 if (debug && openparens == 1)
712 printf(" }");
713 if (openparens == 0)
714 goto err;
715 openparens--;
716 p++;
717 continue;
718 }
719
720 if (*p == '#') {
721 while (p < end && *p != '\n')
722 p++;
723 continue;
724 }
725
726 start = p;
727 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#')
728 p++;
729
730 if (p == start)
731 goto err;
732
733 id = calloc(1, p - start + 1);
734 if (!id)
735 goto err;
736 memcpy(id, start, p - start);
737 if (debug)
738 printf(" %s", id);
739
740 if (!strcmp(id, "*")) {
741 for (node = classperms; node; node = node->next)
742 node->data = ~0;
743 continue;
744 }
745
746 for (node = classperms; node; node = node->next) {
747 cls = policydb->class_val_to_struct[node->class-1];
748 perm = hashtab_search(cls->permissions.table, id);
749 if (cls->comdatum && !perm)
750 perm = hashtab_search(cls->comdatum->permissions.table, id);
751 if (!perm) {
752 if (warn)
753 fprintf(stderr, "Warning! Permission %s used in neverallow undefined in class %s in policy being checked.\n", id, policydb->p_class_val_to_name[node->class-1]);
754 continue;
755 }
756 node->data |= 1U << (perm->s.value - 1);
757 }
758 free(id);
759 } while (p < end && openparens);
760
761 if (p == end)
762 goto err;
763
764 if (complement) {
765 for (node = classperms; node; node = node->next)
766 node->data = ~node->data;
767 }
768
769 if (warn) {
770 for (node = classperms; node; node = node->next)
771 if (!node->data)
772 fprintf(stderr, "Warning! Empty permission set\n");
773 }
774
775 *perms = classperms;
776 *ptr = p;
777 return 0;
778err:
779 return -1;
780}
781
782static int check_neverallows(policydb_t *policydb, const char *filename)
783{
784 const char *keyword = "neverallow";
785 size_t keyword_size = strlen(keyword), len;
786 struct avrule *neverallows = NULL, *avrule;
787 int fd;
788 struct stat sb;
789 char *text, *end, *start;
790 char *p;
791
792 fd = open(filename, O_RDONLY);
793 if (fd < 0) {
794 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno));
795 return -1;
796 }
797 if (fstat(fd, &sb) < 0) {
798 fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno));
799 close(fd);
800 return -1;
801 }
802 text = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
803 end = text + sb.st_size;
804 if (text == MAP_FAILED) {
805 fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno));
806 close(fd);
807 return -1;
808 }
809 close(fd);
810
811 p = text;
812 while (p < end) {
813 while (p < end && isspace(*p))
814 p++;
815
816 if (*p == '#') {
817 while (p < end && *p != '\n')
818 p++;
819 continue;
820 }
821
822 start = p;
823 while (p < end && !isspace(*p))
824 p++;
825
826 len = p - start;
827 if (len != keyword_size || strncmp(start, keyword, keyword_size))
828 continue;
829
830 if (debug)
831 printf("neverallow");
832
833 avrule = calloc(1, sizeof *avrule);
834 if (!avrule)
835 goto err;
836
837 avrule->specified = AVRULE_NEVERALLOW;
838
839 if (read_typeset(policydb, &p, end, &avrule->stypes, &avrule->flags))
840 goto err;
841
842 if (read_typeset(policydb, &p, end, &avrule->ttypes, &avrule->flags))
843 goto err;
844
845 if (read_classperms(policydb, &p, end, &avrule->perms))
846 goto err;
847
848 while (p < end && *p != ';')
849 p++;
850
851 if (p == end || *p != ';')
852 goto err;
853
854 if (debug)
855 printf(";\n");
856
857 avrule->next = neverallows;
858 neverallows = avrule;
859 }
860
861 return check_assertions(NULL, policydb, neverallows);
862err:
863 if (errno == ENOMEM) {
864 fprintf(stderr, "Out of memory while parsing %s\n", filename);
865 } else
866 fprintf(stderr, "Error while parsing %s\n", filename);
867 return -1;
868}
869
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400870int main(int argc, char **argv)
871{
Stephen Smalley59906bf2014-10-07 13:46:59 -0400872 char *policy = NULL, *neverallows = NULL;
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400873 struct policy_file pf;
874 policydb_t policydb;
875 char ch;
dcashman9793ea72014-03-25 16:27:56 -0700876 char equiv = 0, diff = 0, dups = 0, permissive = 0;
Stephen Smalley59906bf2014-10-07 13:46:59 -0400877 int rc = 0;
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400878
879 struct option long_options[] = {
880 {"equiv", no_argument, NULL, 'e'},
Stephen Smalley59906bf2014-10-07 13:46:59 -0400881 {"debug", no_argument, NULL, 'z'},
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400882 {"diff", no_argument, NULL, 'd'},
Stephen Smalleybec54f42013-11-17 18:17:29 -0500883 {"dups", no_argument, NULL, 'D'},
Stephen Smalley59906bf2014-10-07 13:46:59 -0400884 {"neverallow", required_argument, NULL, 'n'},
dcashman9793ea72014-03-25 16:27:56 -0700885 {"permissive", no_argument, NULL, 'p'},
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400886 {"policy", required_argument, NULL, 'P'},
Stephen Smalley59906bf2014-10-07 13:46:59 -0400887 {"warn", no_argument, NULL, 'w'},
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400888 {NULL, 0, NULL, 0}
889 };
890
Stephen Smalley59906bf2014-10-07 13:46:59 -0400891 while ((ch = getopt_long(argc, argv, "edDpn:P:wz", long_options, NULL)) != -1) {
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400892 switch (ch) {
893 case 'e':
894 equiv = 1;
895 break;
896 case 'd':
897 diff = 1;
898 break;
Stephen Smalleybec54f42013-11-17 18:17:29 -0500899 case 'D':
900 dups = 1;
901 break;
Stephen Smalley59906bf2014-10-07 13:46:59 -0400902 case 'n':
903 neverallows = optarg;
904 break;
dcashman9793ea72014-03-25 16:27:56 -0700905 case 'p':
906 permissive = 1;
907 break;
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400908 case 'P':
909 policy = optarg;
910 break;
Stephen Smalley59906bf2014-10-07 13:46:59 -0400911 case 'w':
912 warn = 1;
913 break;
914 case 'z':
915 debug = 1;
916 break;
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400917 default:
918 usage(argv[0]);
919 }
920 }
921
Stephen Smalley59906bf2014-10-07 13:46:59 -0400922 if (!policy || (!equiv && !diff && !dups && !permissive && !neverallows))
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400923 usage(argv[0]);
924
925 if (load_policy(policy, &policydb, &pf))
926 exit(1);
927
Stephen Smalleybec54f42013-11-17 18:17:29 -0500928 if (equiv || diff)
929 analyze_types(&policydb, equiv, diff);
930
931 if (dups)
932 find_dups(&policydb);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400933
dcashman9793ea72014-03-25 16:27:56 -0700934 if (permissive)
935 list_permissive(&policydb);
936
Stephen Smalley59906bf2014-10-07 13:46:59 -0400937 if (neverallows)
938 rc |= check_neverallows(&policydb, neverallows);
939
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400940 policydb_destroy(&policydb);
941
Stephen Smalley59906bf2014-10-07 13:46:59 -0400942 return rc;
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400943}