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