blob: c9dab8121f9ed595cf873e46a5b34793ec1e9788 [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
16void usage(char *arg0)
17{
dcashman9793ea72014-03-25 16:27:56 -070018 fprintf(stderr, "%s [-e|--equiv] [-d|--diff] [-D|--dups] [-p|--permissive] -P <policy file>\n", arg0);
Stephen Smalley7b2bee92013-10-31 09:22:26 -040019 exit(1);
20}
21
22int 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
67static 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
111static 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
150static 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
157static 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
166static 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
Stephen Smalleybec54f42013-11-17 18:17:29 -0500177static void display_allow(policydb_t *policydb, avtab_key_t *key, int idx,
178 uint32_t perms)
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400179{
180 printf(" allow %s %s:%s { %s };\n",
Stephen Smalleybec54f42013-11-17 18:17:29 -0500181 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],
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400187 sepol_av_to_string
Stephen Smalleybec54f42013-11-17 18:17:29 -0500188 (policydb, key->target_class, perms));
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400189}
190
191static 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)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500217 display_allow(policydb, &l1->key, idx1, perms1);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400218 if (perms2)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500219 display_allow(policydb, &c->key, idx2, perms2);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400220 printf("\n");
221 return 1;
222 }
223 }
224
225 return 0;
226}
227
228static 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)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500315 display_allow(policydb, &l1->key, i, l1->datum.data);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400316 if (l2)
Stephen Smalleybec54f42013-11-17 18:17:29 -0500317 display_allow(policydb, &l2->key, j, l2->datum.data);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400318 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
Stephen Smalleybec54f42013-11-17 18:17:29 -0500338static 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;
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400347 struct type_datum *stype, *ttype, *stype2, *ttype2;
348 bool attrib1, attrib2;
Stephen Smalleybec54f42013-11-17 18:17:29 -0500349
350 if (!(k->specified & AVTAB_ALLOWED))
351 return 0;
352
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400353 if (k->source_type == k->target_type)
354 return 0; /* self rule */
355
Stephen Smalleybec54f42013-11-17 18:17:29 -0500356 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];
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400361 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;
Stephen Smalleybec54f42013-11-17 18:17:29 -0500364 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;
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400375 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 */
Stephen Smalleybec54f42013-11-17 18:17:29 -0500382 for (node = avtab_search_node(&policydb->te_avtab, &avkey);
383 node != NULL;
384 node = avtab_search_node_next(node, avkey.specified)) {
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400385 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 */
Stephen Smalleybec54f42013-11-17 18:17:29 -0500392 printf("Duplicate allow rule found:\n");
Stephen Smalley43b9cfd2014-06-17 14:32:46 -0400393 display_allow(policydb, k, i, d->data);
394 display_allow(policydb, &node->key, i, node->datum.data);
Stephen Smalleybec54f42013-11-17 18:17:29 -0500395 printf("\n");
396 }
397 }
398 }
399 }
400
401 return 0;
402}
403
404static 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
dcashman9793ea72014-03-25 16:27:56 -0700411static 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
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400428int main(int argc, char **argv)
429{
430 char *policy = NULL;
431 struct policy_file pf;
432 policydb_t policydb;
433 char ch;
dcashman9793ea72014-03-25 16:27:56 -0700434 char equiv = 0, diff = 0, dups = 0, permissive = 0;
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400435
436 struct option long_options[] = {
437 {"equiv", no_argument, NULL, 'e'},
438 {"diff", no_argument, NULL, 'd'},
Stephen Smalleybec54f42013-11-17 18:17:29 -0500439 {"dups", no_argument, NULL, 'D'},
dcashman9793ea72014-03-25 16:27:56 -0700440 {"permissive", no_argument, NULL, 'p'},
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400441 {"policy", required_argument, NULL, 'P'},
442 {NULL, 0, NULL, 0}
443 };
444
dcashman9793ea72014-03-25 16:27:56 -0700445 while ((ch = getopt_long(argc, argv, "edDpP:", long_options, NULL)) != -1) {
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400446 switch (ch) {
447 case 'e':
448 equiv = 1;
449 break;
450 case 'd':
451 diff = 1;
452 break;
Stephen Smalleybec54f42013-11-17 18:17:29 -0500453 case 'D':
454 dups = 1;
455 break;
dcashman9793ea72014-03-25 16:27:56 -0700456 case 'p':
457 permissive = 1;
458 break;
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400459 case 'P':
460 policy = optarg;
461 break;
462 default:
463 usage(argv[0]);
464 }
465 }
466
dcashman9793ea72014-03-25 16:27:56 -0700467 if (!policy || (!equiv && !diff && !dups && !permissive))
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400468 usage(argv[0]);
469
470 if (load_policy(policy, &policydb, &pf))
471 exit(1);
472
Stephen Smalleybec54f42013-11-17 18:17:29 -0500473 if (equiv || diff)
474 analyze_types(&policydb, equiv, diff);
475
476 if (dups)
477 find_dups(&policydb);
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400478
dcashman9793ea72014-03-25 16:27:56 -0700479 if (permissive)
480 list_permissive(&policydb);
481
Stephen Smalley7b2bee92013-10-31 09:22:26 -0400482 policydb_destroy(&policydb);
483
484 return 0;
485}