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