blob: 9b3d444c940effb51bb7e05424fa5570ceef6bb0 [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{
17 fprintf(stderr, "%s [-e|--equiv] [-d|--diff] -P <policy file>\n", arg0);
18 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
176static void display_allow(policydb_t *policydb, struct avtab_node *n, int idx,
177 uint32_t perms)
178{
179 printf(" allow %s %s:%s { %s };\n",
180 policydb->p_type_val_to_name[n->key.source_type
181 ? n->key.source_type - 1 : idx],
182 n->key.target_type == n->key.source_type ? "self" :
183 policydb->p_type_val_to_name[n->key.target_type
184 ? n->key.target_type - 1 : idx],
185 policydb->p_class_val_to_name[n->key.target_class - 1],
186 sepol_av_to_string
187 (policydb, n->key.target_class, perms));
188}
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)
216 display_allow(policydb, l1, idx1, perms1);
217 if (perms2)
218 display_allow(policydb, c, idx2, perms2);
219 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)
314 display_allow(policydb, l1, i, l1->datum.data);
315 if (l2)
316 display_allow(policydb, l2, j, l2->datum.data);
317 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
337int main(int argc, char **argv)
338{
339 char *policy = NULL;
340 struct policy_file pf;
341 policydb_t policydb;
342 char ch;
343 char equiv = 0, diff = 0;
344
345 struct option long_options[] = {
346 {"equiv", no_argument, NULL, 'e'},
347 {"diff", no_argument, NULL, 'd'},
348 {"policy", required_argument, NULL, 'P'},
349 {NULL, 0, NULL, 0}
350 };
351
352 while ((ch = getopt_long(argc, argv, "edP:", long_options, NULL)) != -1) {
353 switch (ch) {
354 case 'e':
355 equiv = 1;
356 break;
357 case 'd':
358 diff = 1;
359 break;
360 case 'P':
361 policy = optarg;
362 break;
363 default:
364 usage(argv[0]);
365 }
366 }
367
368 if (!policy || (!equiv && !diff))
369 usage(argv[0]);
370
371 if (load_policy(policy, &policydb, &pf))
372 exit(1);
373
374 analyze_types(&policydb, equiv, diff);
375
376 policydb_destroy(&policydb);
377
378 return 0;
379}