• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #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>
14 #include <stdbool.h>
15 
usage(char * arg0)16 void usage(char *arg0)
17 {
18     fprintf(stderr, "%s [-e|--equiv] [-d|--diff] [-D|--dups] [-p|--permissive] -P <policy file>\n", arg0);
19     exit(1);
20 }
21 
load_policy(char * filename,policydb_t * policydb,struct policy_file * pf)22 int load_policy(char *filename, policydb_t * policydb, struct policy_file *pf)
23 {
24     int fd;
25     struct stat sb;
26     void *map;
27     int ret;
28 
29     fd = open(filename, O_RDONLY);
30     if (fd < 0) {
31         fprintf(stderr, "Can't open '%s':  %s\n", filename, strerror(errno));
32         return 1;
33     }
34     if (fstat(fd, &sb) < 0) {
35         fprintf(stderr, "Can't stat '%s':  %s\n", filename, strerror(errno));
36         close(fd);
37         return 1;
38     }
39     map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
40     if (map == MAP_FAILED) {
41         fprintf(stderr, "Can't mmap '%s':  %s\n", filename, strerror(errno));
42         close(fd);
43         return 1;
44     }
45 
46     policy_file_init(pf);
47     pf->type = PF_USE_MEMORY;
48     pf->data = map;
49     pf->len = sb.st_size;
50     if (policydb_init(policydb)) {
51         fprintf(stderr, "Could not initialize policydb!\n");
52         close(fd);
53         munmap(map, sb.st_size);
54         return 1;
55     }
56     ret = policydb_read(policydb, pf, 0);
57     if (ret) {
58         fprintf(stderr, "error(s) encountered while parsing configuration\n");
59         close(fd);
60         munmap(map, sb.st_size);
61         return 1;
62     }
63 
64     return 0;
65 }
66 
insert_type_rule(avtab_key_t * k,avtab_datum_t * d,struct avtab_node * type_rules)67 static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
68                             struct avtab_node *type_rules)
69 {
70     struct avtab_node *p, *c, *n;
71 
72     for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
73         /*
74          * Find the insertion point, keeping the list
75          * ordered by source type, then target type, then
76          * target class.
77          */
78         if (k->source_type < c->key.source_type)
79             break;
80         if (k->source_type == c->key.source_type &&
81             k->target_type < c->key.target_type)
82             break;
83         if (k->source_type == c->key.source_type &&
84             k->target_type == c->key.target_type &&
85             k->target_class <= c->key.target_class)
86             break;
87     }
88 
89     if (c &&
90         k->source_type == c->key.source_type &&
91         k->target_type == c->key.target_type &&
92         k->target_class == c->key.target_class) {
93         c->datum.data |= d->data;
94         return 0;
95     }
96 
97     /* Insert the rule */
98     n = malloc(sizeof(struct avtab_node));
99     if (!n) {
100         fprintf(stderr, "out of memory\n");
101         exit(1);
102     }
103 
104     n->key = *k;
105     n->datum = *d;
106     n->next = p->next;
107     p->next = n;
108     return 0;
109 }
110 
create_type_rules_helper(avtab_key_t * k,avtab_datum_t * d,void * args)111 static int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d,
112                                     void *args)
113 {
114     struct avtab_node *type_rules = args;
115     avtab_key_t key;
116 
117     /*
118      * Insert the rule into the list for
119      * the source type.  The source type value
120      * is cleared as we want to compare against other type
121      * rules with different source types.
122      */
123     key = *k;
124     key.source_type = 0;
125     if (k->source_type == k->target_type) {
126         /* Clear target type as well; this is a self rule. */
127         key.target_type = 0;
128     }
129     if (insert_type_rule(&key, d, &type_rules[k->source_type - 1]))
130         return -1;
131 
132     if (k->source_type == k->target_type)
133         return 0;
134 
135     /*
136      * If the target type differs, then we also
137      * insert the rule into the list for the target
138      * type.  We clear the target type value so that
139      * we can compare against other type rules with
140      * different target types.
141      */
142     key = *k;
143     key.target_type = 0;
144     if (insert_type_rule(&key, d, &type_rules[k->target_type - 1]))
145         return -1;
146 
147     return 0;
148 }
149 
create_type_rules(avtab_key_t * k,avtab_datum_t * d,void * args)150 static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
151 {
152     if (k->specified & AVTAB_ALLOWED)
153         return create_type_rules_helper(k, d, args);
154     return 0;
155 }
156 
create_type_rules_cond(avtab_key_t * k,avtab_datum_t * d,void * args)157 static int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d,
158                                   void *args)
159 {
160     if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) ==
161         (AVTAB_ALLOWED|AVTAB_ENABLED))
162         return create_type_rules_helper(k, d, args);
163     return 0;
164 }
165 
free_type_rules(struct avtab_node * l)166 static void free_type_rules(struct avtab_node *l)
167 {
168     struct avtab_node *tmp;
169 
170     while (l) {
171         tmp = l;
172         l = l->next;
173         free(tmp);
174     }
175 }
176 
display_allow(policydb_t * policydb,avtab_key_t * key,int idx,uint32_t perms)177 static void display_allow(policydb_t *policydb, avtab_key_t *key, int idx,
178                           uint32_t perms)
179 {
180     printf("    allow %s %s:%s { %s };\n",
181            policydb->p_type_val_to_name[key->source_type
182                                         ? key->source_type - 1 : idx],
183            key->target_type == key->source_type ? "self" :
184            policydb->p_type_val_to_name[key->target_type
185                                         ? key->target_type - 1 : idx],
186            policydb->p_class_val_to_name[key->target_class - 1],
187            sepol_av_to_string
188            (policydb, key->target_class, perms));
189 }
190 
find_match(policydb_t * policydb,struct avtab_node * l1,int idx1,struct avtab_node * l2,int idx2)191 static int find_match(policydb_t *policydb, struct avtab_node *l1,
192                       int idx1, struct avtab_node *l2, int idx2)
193 {
194     struct avtab_node *c;
195     uint32_t perms1, perms2;
196 
197     for (c = l2; c; c = c->next) {
198         if (l1->key.source_type < c->key.source_type)
199             break;
200         if (l1->key.source_type == c->key.source_type &&
201             l1->key.target_type < c->key.target_type)
202             break;
203         if (l1->key.source_type == c->key.source_type &&
204             l1->key.target_type == c->key.target_type &&
205             l1->key.target_class <= c->key.target_class)
206             break;
207     }
208 
209     if (c &&
210         l1->key.source_type == c->key.source_type &&
211         l1->key.target_type == c->key.target_type &&
212         l1->key.target_class == c->key.target_class) {
213         perms1 = l1->datum.data & ~c->datum.data;
214         perms2 = c->datum.data & ~l1->datum.data;
215         if (perms1 || perms2) {
216             if (perms1)
217                 display_allow(policydb, &l1->key, idx1, perms1);
218             if (perms2)
219                 display_allow(policydb, &c->key, idx2, perms2);
220             printf("\n");
221             return 1;
222         }
223     }
224 
225     return 0;
226 }
227 
analyze_types(policydb_t * policydb,char equiv,char diff)228 static int analyze_types(policydb_t * policydb, char equiv, char diff)
229 {
230     avtab_t exp_avtab, exp_cond_avtab;
231     struct avtab_node *type_rules, *l1, *l2;
232     struct type_datum *type;
233     size_t i, j;
234 
235     /*
236      * Create a list of access vector rules for each type
237      * from the access vector table.
238      */
239     type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim);
240     if (!type_rules) {
241         fprintf(stderr, "out of memory\n");
242         exit(1);
243     }
244     memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim);
245 
246     if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) {
247         fputs("out of memory\n", stderr);
248         return -1;
249     }
250 
251     if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) {
252         fputs("out of memory\n", stderr);
253         avtab_destroy(&exp_avtab);
254         return -1;
255     }
256 
257     if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) {
258         fputs("out of memory\n", stderr);
259         avtab_destroy(&exp_avtab);
260         return -1;
261     }
262 
263     if (avtab_map(&exp_avtab, create_type_rules, type_rules))
264         exit(1);
265 
266     if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules))
267         exit(1);
268 
269     avtab_destroy(&exp_avtab);
270     avtab_destroy(&exp_cond_avtab);
271 
272     /*
273      * Compare the type lists and identify similar types.
274      */
275     for (i = 0; i < policydb->p_types.nprim - 1; i++) {
276         if (!type_rules[i].next)
277             continue;
278         type = policydb->type_val_to_struct[i];
279         if (type->flavor) {
280             free_type_rules(type_rules[i].next);
281             type_rules[i].next = NULL;
282             continue;
283         }
284         for (j = i + 1; j < policydb->p_types.nprim; j++) {
285             type = policydb->type_val_to_struct[j];
286             if (type->flavor) {
287                 free_type_rules(type_rules[j].next);
288                 type_rules[j].next = NULL;
289                 continue;
290             }
291             for (l1 = type_rules[i].next, l2 = type_rules[j].next;
292                  l1 && l2; l1 = l1->next, l2 = l2->next) {
293                 if (l1->key.source_type != l2->key.source_type)
294                     break;
295                 if (l1->key.target_type != l2->key.target_type)
296                     break;
297                 if (l1->key.target_class != l2->key.target_class
298                     || l1->datum.data != l2->datum.data)
299                     break;
300             }
301             if (l1 || l2) {
302                 if (diff) {
303                     printf
304                         ("Types %s and %s differ, starting with:\n",
305                          policydb->p_type_val_to_name[i],
306                          policydb->p_type_val_to_name[j]);
307 
308                     if (l1 && l2) {
309                         if (find_match(policydb, l1, i, l2, j))
310                             continue;
311                         if (find_match(policydb, l2, j, l1, i))
312                             continue;
313                     }
314                     if (l1)
315                         display_allow(policydb, &l1->key, i, l1->datum.data);
316                     if (l2)
317                         display_allow(policydb, &l2->key, j, l2->datum.data);
318                     printf("\n");
319                 }
320                 continue;
321             }
322             free_type_rules(type_rules[j].next);
323             type_rules[j].next = NULL;
324             if (equiv) {
325                 printf("Types %s and %s are equivalent.\n",
326                        policydb->p_type_val_to_name[i],
327                        policydb->p_type_val_to_name[j]);
328             }
329         }
330         free_type_rules(type_rules[i].next);
331         type_rules[i].next = NULL;
332     }
333 
334     free(type_rules);
335     return 0;
336 }
337 
find_dups_helper(avtab_key_t * k,avtab_datum_t * d,void * args)338 static int find_dups_helper(avtab_key_t * k, avtab_datum_t * d,
339                             void *args)
340 {
341     policydb_t *policydb = args;
342     ebitmap_t *sattr, *tattr;
343     ebitmap_node_t *snode, *tnode;
344     unsigned int i, j;
345     avtab_key_t avkey;
346     avtab_ptr_t node;
347     struct type_datum *stype, *ttype, *stype2, *ttype2;
348     bool attrib1, attrib2;
349 
350     if (!(k->specified & AVTAB_ALLOWED))
351         return 0;
352 
353     if (k->source_type == k->target_type)
354         return 0; /* self rule */
355 
356     avkey.target_class = k->target_class;
357     avkey.specified = k->specified;
358 
359     sattr = &policydb->type_attr_map[k->source_type - 1];
360     tattr = &policydb->type_attr_map[k->target_type - 1];
361     stype = policydb->type_val_to_struct[k->source_type - 1];
362     ttype = policydb->type_val_to_struct[k->target_type - 1];
363     attrib1 = stype->flavor || ttype->flavor;
364     ebitmap_for_each_bit(sattr, snode, i) {
365         if (!ebitmap_node_get_bit(snode, i))
366             continue;
367         ebitmap_for_each_bit(tattr, tnode, j) {
368             if (!ebitmap_node_get_bit(tnode, j))
369                 continue;
370             avkey.source_type = i + 1;
371             avkey.target_type = j + 1;
372             if (avkey.source_type == k->source_type &&
373                 avkey.target_type == k->target_type)
374                 continue;
375             if (avkey.source_type == avkey.target_type)
376                 continue; /* self rule */
377             stype2 = policydb->type_val_to_struct[avkey.source_type - 1];
378             ttype2 = policydb->type_val_to_struct[avkey.target_type - 1];
379             attrib2 = stype2->flavor || ttype2->flavor;
380             if (attrib1 && attrib2)
381                 continue; /* overlapping attribute-based rules */
382             for (node = avtab_search_node(&policydb->te_avtab, &avkey);
383                  node != NULL;
384                  node = avtab_search_node_next(node, avkey.specified)) {
385                 uint32_t perms = node->datum.data & d->data;
386                 if ((attrib1 && perms == node->datum.data) ||
387                     (attrib2 && perms == d->data)) {
388                     /*
389                      * The attribute-based rule is a superset of the
390                      * non-attribute-based rule.  This is a dup.
391                      */
392                     printf("Duplicate allow rule found:\n");
393                     display_allow(policydb, k, i, d->data);
394                     display_allow(policydb, &node->key, i, node->datum.data);
395                     printf("\n");
396                 }
397             }
398         }
399     }
400 
401     return 0;
402 }
403 
find_dups(policydb_t * policydb)404 static int find_dups(policydb_t * policydb)
405 {
406     if (avtab_map(&policydb->te_avtab, find_dups_helper, policydb))
407         return -1;
408     return 0;
409 }
410 
list_permissive(policydb_t * policydb)411 static int list_permissive(policydb_t * policydb)
412 {
413     struct ebitmap_node *n;
414     unsigned int bit;
415 
416     /*
417      * iterate over all domains and check if domain is in permissive
418      */
419     ebitmap_for_each_bit(&policydb->permissive_map, n, bit)
420     {
421         if (ebitmap_node_get_bit(n, bit)) {
422             printf("%s\n", policydb->p_type_val_to_name[bit -1]);
423         }
424     }
425     return 0;
426 }
427 
main(int argc,char ** argv)428 int main(int argc, char **argv)
429 {
430     char *policy = NULL;
431     struct policy_file pf;
432     policydb_t policydb;
433     char ch;
434     char equiv = 0, diff = 0, dups = 0, permissive = 0;
435 
436     struct option long_options[] = {
437         {"equiv", no_argument, NULL, 'e'},
438         {"diff", no_argument, NULL, 'd'},
439         {"dups", no_argument, NULL, 'D'},
440         {"permissive", no_argument, NULL, 'p'},
441         {"policy", required_argument, NULL, 'P'},
442         {NULL, 0, NULL, 0}
443     };
444 
445     while ((ch = getopt_long(argc, argv, "edDpP:", long_options, NULL)) != -1) {
446         switch (ch) {
447         case 'e':
448             equiv = 1;
449             break;
450         case 'd':
451             diff = 1;
452             break;
453         case 'D':
454             dups = 1;
455             break;
456         case 'p':
457             permissive = 1;
458             break;
459         case 'P':
460             policy = optarg;
461             break;
462         default:
463             usage(argv[0]);
464         }
465     }
466 
467     if (!policy || (!equiv && !diff && !dups && !permissive))
468         usage(argv[0]);
469 
470     if (load_policy(policy, &policydb, &pf))
471         exit(1);
472 
473     if (equiv || diff)
474         analyze_types(&policydb, equiv, diff);
475 
476     if (dups)
477         find_dups(&policydb);
478 
479     if (permissive)
480         list_permissive(&policydb);
481 
482     policydb_destroy(&policydb);
483 
484     return 0;
485 }
486