1 
2 /* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
3  *
4  * Copyright (C) 2003 Tresys Technology, LLC
5  *	This program is free software; you can redistribute it and/or modify
6  *  	it under the terms of the GNU General Public License as published by
7  *	the Free Software Foundation, version 2.
8  */
9 
10 /*
11  * displaypol.c
12  *
13  * Test program to the contents of a binary policy in text
14  * form.  This program currently only displays the
15  * avtab (including conditional avtab) rules.
16  *
17  * 	displaypol binary_pol_file
18  */
19 
20 #include <sepol/policydb/policydb.h>
21 #include <sepol/policydb/avtab.h>
22 #include <sepol/policydb/services.h>
23 #include <sepol/policydb/conditional.h>
24 #include <sepol/policydb/util.h>
25 #include <sepol/policydb/polcaps.h>
26 #include <getopt.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 
37 static policydb_t policydb;
38 
usage(const char * progname)39 static __attribute__((__noreturn__)) void usage(const char *progname)
40 {
41 	printf("usage:  %s binary_pol_file\n\n", progname);
42 	exit(1);
43 }
44 
render_access_mask(uint32_t mask,avtab_key_t * key,policydb_t * p,FILE * fp)45 int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p,
46 		       FILE * fp)
47 {
48 	char *perm;
49 	fprintf(fp, "{");
50 	perm = sepol_av_to_string(p, key->target_class, mask);
51 	if (perm)
52 		fprintf(fp, "%s ", perm);
53 	fprintf(fp, "}");
54 	return 0;
55 }
56 
render_type(uint32_t type,policydb_t * p,FILE * fp)57 int render_type(uint32_t type, policydb_t * p, FILE * fp)
58 {
59 	fprintf(fp, "%s", p->p_type_val_to_name[type - 1]);
60 	return 0;
61 }
62 
render_key(avtab_key_t * key,policydb_t * p,FILE * fp)63 int render_key(avtab_key_t * key, policydb_t * p, FILE * fp)
64 {
65 	char *stype, *ttype, *tclass;
66 	stype = p->p_type_val_to_name[key->source_type - 1];
67 	ttype = p->p_type_val_to_name[key->target_type - 1];
68 	tclass = p->p_class_val_to_name[key->target_class - 1];
69 	if (stype && ttype)
70 		fprintf(fp, "%s %s : %s ", stype, ttype, tclass);
71 	else if (stype)
72 		fprintf(fp, "%s %u : %s ", stype, key->target_type, tclass);
73 	else if (ttype)
74 		fprintf(fp, "%u %s : %s ", key->source_type, ttype, tclass);
75 	else
76 		fprintf(fp, "%u %u : %s ", key->source_type, key->target_type,
77 			tclass);
78 	return 0;
79 }
80 
81 /* 'what' values for this function */
82 #define	RENDER_UNCONDITIONAL	0x0001	/* render all regardless of enabled state */
83 #define RENDER_ENABLED		0x0002
84 #define RENDER_DISABLED		0x0004
85 #define RENDER_CONDITIONAL	(RENDER_ENABLED|RENDER_DISABLED)
86 
render_av_rule(avtab_key_t * key,avtab_datum_t * datum,uint32_t what,policydb_t * p,FILE * fp)87 int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what,
88 		   policydb_t * p, FILE * fp)
89 {
90 	if (!(what & RENDER_UNCONDITIONAL)) {
91 		if (what != RENDER_CONDITIONAL && (((what & RENDER_ENABLED)
92 						    && !(key->
93 							 specified &
94 							 AVTAB_ENABLED))
95 						   || ((what & RENDER_DISABLED)
96 						       && (key->
97 							   specified &
98 							   AVTAB_ENABLED)))) {
99 			return 0;	/* doesn't match selection criteria */
100 		}
101 	}
102 
103 	if (!(what & RENDER_UNCONDITIONAL)) {
104 		if (key->specified & AVTAB_ENABLED)
105 			fprintf(fp, "[enabled] ");
106 		else if (!(key->specified & AVTAB_ENABLED))
107 			fprintf(fp, "[disabled] ");
108 	}
109 
110 	if (key->specified & AVTAB_AV) {
111 		if (key->specified & AVTAB_ALLOWED) {
112 			fprintf(fp, "allow ");
113 			render_key(key, p, fp);
114 			render_access_mask(datum->data, key, p, fp);
115 			fprintf(fp, ";\n");
116 		}
117 		if (key->specified & AVTAB_AUDITALLOW) {
118 			fprintf(fp, "auditallow ");
119 			render_key(key, p, fp);
120 			render_access_mask(datum->data, key, p, fp);
121 			fprintf(fp, ";\n");
122 		}
123 		if (key->specified & AVTAB_AUDITDENY) {
124 			fprintf(fp, "dontaudit ");
125 			render_key(key, p, fp);
126 			/* We inverse the mask for dontaudit since the mask is internally stored
127 			 * as a auditdeny mask */
128 			render_access_mask(~datum->data, key, p, fp);
129 			fprintf(fp, ";\n");
130 		}
131 	} else if (key->specified & AVTAB_TYPE) {
132 		if (key->specified & AVTAB_TRANSITION) {
133 			fprintf(fp, "type_transition ");
134 			render_key(key, p, fp);
135 			render_type(datum->data, p, fp);
136 			fprintf(fp, ";\n");
137 		}
138 		if (key->specified & AVTAB_MEMBER) {
139 			fprintf(fp, "type_member ");
140 			render_key(key, p, fp);
141 			render_type(datum->data, p, fp);
142 			fprintf(fp, ";\n");
143 		}
144 		if (key->specified & AVTAB_CHANGE) {
145 			fprintf(fp, "type_change ");
146 			render_key(key, p, fp);
147 			render_type(datum->data, p, fp);
148 			fprintf(fp, ";\n");
149 		}
150 	} else if (key->specified & AVTAB_XPERMS) {
151 		if (key->specified & AVTAB_XPERMS_ALLOWED)
152 			fprintf(fp, "allowxperm ");
153 		else if (key->specified & AVTAB_XPERMS_AUDITALLOW)
154 			fprintf(fp, "auditallowxperm ");
155 		else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
156 			fprintf(fp, "dontauditxperm ");
157 		render_key(key, p, fp);
158 		fprintf(fp, "%s;\n", sepol_extended_perms_to_string(datum->xperms));
159 	} else {
160 		fprintf(fp, "     ERROR: no valid rule type specified\n");
161 		return -1;
162 	}
163 	return 0;
164 }
165 
display_avtab(avtab_t * a,uint32_t what,policydb_t * p,FILE * fp)166 int display_avtab(avtab_t * a, uint32_t what, policydb_t * p, FILE * fp)
167 {
168 	unsigned int i;
169 	avtab_ptr_t cur;
170 
171 	/* hmm...should have used avtab_map. */
172 	for (i = 0; i < a->nslot; i++) {
173 		for (cur = a->htable[i]; cur; cur = cur->next) {
174 			render_av_rule(&cur->key, &cur->datum, what, p, fp);
175 		}
176 	}
177 	fprintf(fp, "\n");
178 	return 0;
179 }
180 
display_bools(policydb_t * p,FILE * fp)181 int display_bools(policydb_t * p, FILE * fp)
182 {
183 	unsigned int i;
184 
185 	for (i = 0; i < p->p_bools.nprim; i++) {
186 		fprintf(fp, "%s : %d\n", p->p_bool_val_to_name[i],
187 			p->bool_val_to_struct[i]->state);
188 	}
189 	return 0;
190 }
191 
display_expr(policydb_t * p,cond_expr_t * exp,FILE * fp)192 void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp)
193 {
194 
195 	cond_expr_t *cur;
196 	for (cur = exp; cur != NULL; cur = cur->next) {
197 		switch (cur->expr_type) {
198 		case COND_BOOL:
199 			fprintf(fp, "%s ",
200 				p->p_bool_val_to_name[cur->bool - 1]);
201 			break;
202 		case COND_NOT:
203 			fprintf(fp, "! ");
204 			break;
205 		case COND_OR:
206 			fprintf(fp, "|| ");
207 			break;
208 		case COND_AND:
209 			fprintf(fp, "&& ");
210 			break;
211 		case COND_XOR:
212 			fprintf(fp, "^ ");
213 			break;
214 		case COND_EQ:
215 			fprintf(fp, "== ");
216 			break;
217 		case COND_NEQ:
218 			fprintf(fp, "!= ");
219 			break;
220 		default:
221 			fprintf(fp, "error!");
222 			break;
223 		}
224 	}
225 }
226 
display_cond_expressions(policydb_t * p,FILE * fp)227 int display_cond_expressions(policydb_t * p, FILE * fp)
228 {
229 	cond_node_t *cur;
230 	cond_av_list_t *av_cur;
231 
232 	for (cur = p->cond_list; cur != NULL; cur = cur->next) {
233 		fprintf(fp, "expression: ");
234 		display_expr(p, cur->expr, fp);
235 		fprintf(fp, "current state: %d\n", cur->cur_state);
236 		fprintf(fp, "True list:\n");
237 		for (av_cur = cur->true_list; av_cur != NULL; av_cur = av_cur->next) {
238 			fprintf(fp, "\t");
239 			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
240 				       RENDER_CONDITIONAL, p, fp);
241 		}
242 		fprintf(fp, "False list:\n");
243 		for (av_cur = cur->false_list; av_cur != NULL; av_cur = av_cur->next) {
244 			fprintf(fp, "\t");
245 			render_av_rule(&av_cur->node->key, &av_cur->node->datum,
246 				       RENDER_CONDITIONAL, p, fp);
247 		}
248 	}
249 	return 0;
250 }
251 
display_handle_unknown(policydb_t * p,FILE * out_fp)252 int display_handle_unknown(policydb_t * p, FILE * out_fp)
253 {
254 	if (p->handle_unknown == ALLOW_UNKNOWN)
255 		fprintf(out_fp, "Allow unknown classes and permissions\n");
256 	else if (p->handle_unknown == DENY_UNKNOWN)
257 		fprintf(out_fp, "Deny unknown classes and permissions\n");
258 	else if (p->handle_unknown == REJECT_UNKNOWN)
259 		fprintf(out_fp, "Reject unknown classes and permissions\n");
260 	return 0;
261 }
262 
change_bool(char * name,int state,policydb_t * p,FILE * fp)263 int change_bool(char *name, int state, policydb_t * p, FILE * fp)
264 {
265 	cond_bool_datum_t *bool;
266 
267 	bool = hashtab_search(p->p_bools.table, name);
268 	if (bool == NULL) {
269 		fprintf(fp, "Could not find bool %s\n", name);
270 		return -1;
271 	}
272 	bool->state = state;
273 	evaluate_conds(p);
274 	return 0;
275 }
276 
display_policycaps(policydb_t * p,FILE * fp)277 static void display_policycaps(policydb_t * p, FILE * fp)
278 {
279 	ebitmap_node_t *node;
280 	const char *capname;
281 	char buf[64];
282 	unsigned int i;
283 
284 	fprintf(fp, "policy capabilities:\n");
285 	ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
286 		capname = sepol_polcap_getname(i);
287 		if (capname == NULL) {
288 			snprintf(buf, sizeof(buf), "unknown (%d)", i);
289 			capname = buf;
290 		}
291 		fprintf(fp, "\t%s\n", capname);
292 	}
293 }
294 
display_id(policydb_t * p,FILE * fp,uint32_t symbol_type,uint32_t symbol_value,const char * prefix)295 static void display_id(policydb_t *p, FILE *fp, uint32_t symbol_type,
296 		       uint32_t symbol_value, const char *prefix)
297 {
298 	const char *id = p->sym_val_to_name[symbol_type][symbol_value];
299 	fprintf(fp, " %s%s", prefix, id);
300 }
301 
display_permissive(policydb_t * p,FILE * fp)302 static void display_permissive(policydb_t *p, FILE *fp)
303 {
304 	ebitmap_node_t *node;
305 	unsigned int i;
306 
307 	fprintf(fp, "permissive sids:\n");
308 	ebitmap_for_each_positive_bit(&p->permissive_map, node, i) {
309 		fprintf(fp, "\t");
310 		display_id(p, fp, SYM_TYPES, i - 1, "");
311 		fprintf(fp, "\n");
312 	}
313 }
314 
display_role_trans(policydb_t * p,FILE * fp)315 static void display_role_trans(policydb_t *p, FILE *fp)
316 {
317 	role_trans_t *rt;
318 
319 	fprintf(fp, "role_trans rules:\n");
320 	for (rt = p->role_tr; rt; rt = rt->next) {
321 		display_id(p, fp, SYM_ROLES, rt->role - 1, "");
322 		display_id(p, fp, SYM_TYPES, rt->type - 1, "");
323 		display_id(p, fp, SYM_CLASSES, rt->tclass - 1, ":");
324 		display_id(p, fp, SYM_ROLES, rt->new_role - 1, "");
325 		fprintf(fp, "\n");
326 	}
327 }
328 
329 struct filenametr_display_args {
330 	policydb_t *p;
331 	FILE *fp;
332 };
333 
filenametr_display(hashtab_key_t key,hashtab_datum_t datum,void * ptr)334 static int filenametr_display(hashtab_key_t key,
335 			      hashtab_datum_t datum,
336 			      void *ptr)
337 {
338 	struct filename_trans *ft = (struct filename_trans *)key;
339 	struct filename_trans_datum *ftdatum = datum;
340 	struct filenametr_display_args *args = ptr;
341 	policydb_t *p = args->p;
342 	FILE *fp = args->fp;
343 
344 	display_id(p, fp, SYM_TYPES, ft->stype - 1, "");
345 	display_id(p, fp, SYM_TYPES, ft->ttype - 1, "");
346 	display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":");
347 	display_id(p, fp, SYM_TYPES, ftdatum->otype - 1, "");
348 	fprintf(fp, " %s\n", ft->name);
349 	return 0;
350 }
351 
352 
display_filename_trans(policydb_t * p,FILE * fp)353 static void display_filename_trans(policydb_t *p, FILE *fp)
354 {
355 	struct filenametr_display_args args;
356 
357 	fprintf(fp, "filename_trans rules:\n");
358 	args.p = p;
359 	args.fp = fp;
360 	hashtab_map(p->filename_trans, filenametr_display, &args);
361 }
362 
menu(void)363 int menu(void)
364 {
365 	printf("\nSelect a command:\n");
366 	printf("1)  display unconditional AVTAB\n");
367 	printf("2)  display conditional AVTAB (entirely)\n");
368 	printf("3)  display conditional AVTAB (only ENABLED rules)\n");
369 	printf("4)  display conditional AVTAB (only DISABLED rules)\n");
370 	printf("5)  display conditional bools\n");
371 	printf("6)  display conditional expressions\n");
372 	printf("7)  change a boolean value\n");
373 	printf("8)  display role transitions\n");
374 	printf("\n");
375 	printf("c)  display policy capabilities\n");
376 	printf("p)  display the list of permissive types\n");
377 	printf("u)  display unknown handling setting\n");
378 	printf("F)  display filename_trans rules\n");
379 	printf("\n");
380 	printf("f)  set output file\n");
381 	printf("m)  display menu\n");
382 	printf("q)  quit\n");
383 	return 0;
384 }
385 
main(int argc,char ** argv)386 int main(int argc, char **argv)
387 {
388 	FILE *out_fp = stdout;
389 	char ans[81], OutfileName[121];
390 	int fd, ret;
391 	struct stat sb;
392 	void *map;
393 	char *name;
394 	int state;
395 	struct policy_file pf;
396 
397 	if (argc != 2)
398 		usage(argv[0]);
399 
400 	fd = open(argv[1], O_RDONLY);
401 	if (fd < 0) {
402 		fprintf(stderr, "Can't open '%s':  %s\n",
403 			argv[1], strerror(errno));
404 		exit(1);
405 	}
406 	if (fstat(fd, &sb) < 0) {
407 		fprintf(stderr, "Can't stat '%s':  %s\n",
408 			argv[1], strerror(errno));
409 		exit(1);
410 	}
411 	map =
412 	    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
413 	if (map == MAP_FAILED) {
414 		fprintf(stderr, "Can't map '%s':  %s\n",
415 			argv[1], strerror(errno));
416 		exit(1);
417 	}
418 
419 	/* read the binary policy */
420 	fprintf(out_fp, "Reading policy...\n");
421 	policy_file_init(&pf);
422 	pf.type = PF_USE_MEMORY;
423 	pf.data = map;
424 	pf.len = sb.st_size;
425 	if (policydb_init(&policydb)) {
426 		fprintf(stderr, "%s:  Out of memory!\n", argv[0]);
427 		exit(1);
428 	}
429 	ret = policydb_read(&policydb, &pf, 1);
430 	if (ret) {
431 		fprintf(stderr,
432 			"%s:  error(s) encountered while parsing configuration\n",
433 			argv[0]);
434 		exit(1);
435 	}
436 
437 	fprintf(stdout, "binary policy file loaded\n\n");
438 	close(fd);
439 
440 	menu();
441 	for (;;) {
442 		printf("\nCommand (\'m\' for menu):  ");
443 		if (fgets(ans, sizeof(ans), stdin) == NULL) {
444 			fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
445 					strerror(errno));
446 			continue;
447 		}
448 		switch (ans[0]) {
449 
450 		case '1':
451 			display_avtab(&policydb.te_avtab, RENDER_UNCONDITIONAL,
452 				      &policydb, out_fp);
453 			break;
454 		case '2':
455 			display_avtab(&policydb.te_cond_avtab,
456 				      RENDER_CONDITIONAL, &policydb, out_fp);
457 			break;
458 		case '3':
459 			display_avtab(&policydb.te_cond_avtab, RENDER_ENABLED,
460 				      &policydb, out_fp);
461 			break;
462 		case '4':
463 			display_avtab(&policydb.te_cond_avtab, RENDER_DISABLED,
464 				      &policydb, out_fp);
465 			break;
466 		case '5':
467 			display_bools(&policydb, out_fp);
468 			break;
469 		case '6':
470 			display_cond_expressions(&policydb, out_fp);
471 			break;
472 		case '7':
473 			printf("name? ");
474 			if (fgets(ans, sizeof(ans), stdin) == NULL) {
475 				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
476 						strerror(errno));
477 				break;
478 			}
479 			ans[strlen(ans) - 1] = 0;
480 
481 			name = malloc((strlen(ans) + 1) * sizeof(char));
482 			if (name == NULL) {
483 				fprintf(stderr, "couldn't malloc string.\n");
484 				break;
485 			}
486 			strcpy(name, ans);
487 
488 			printf("state? ");
489 			if (fgets(ans, sizeof(ans), stdin) == NULL) {
490 				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
491 						strerror(errno));
492 				break;
493 			}
494 			ans[strlen(ans) - 1] = 0;
495 
496 			if (atoi(ans))
497 				state = 1;
498 			else
499 				state = 0;
500 
501 			change_bool(name, state, &policydb, out_fp);
502 			free(name);
503 			break;
504 		case '8':
505 			display_role_trans(&policydb, out_fp);
506 			break;
507 		case 'c':
508 			display_policycaps(&policydb, out_fp);
509 			break;
510 		case 'p':
511 			display_permissive(&policydb, out_fp);
512 			break;
513 		case 'u':
514 		case 'U':
515 			display_handle_unknown(&policydb, out_fp);
516 			break;
517 		case 'f':
518 			printf
519 			    ("\nFilename for output (<CR> for screen output): ");
520 			if (fgets(OutfileName, sizeof(OutfileName), stdin) == NULL) {
521 				fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
522 						strerror(errno));
523 				break;
524 			}
525 			OutfileName[strlen(OutfileName) - 1] = '\0';	/* fix_string (remove LF) */
526 			if (strlen(OutfileName) == 0)
527 				out_fp = stdout;
528 			else if ((out_fp = fopen(OutfileName, "w")) == NULL) {
529 				fprintf(stderr, "Cannot open output file %s\n",
530 					OutfileName);
531 				out_fp = stdout;
532 			}
533 			if (out_fp != stdout)
534 				printf("\nOutput to file: %s\n", OutfileName);
535 			break;
536 		case 'F':
537 			display_filename_trans(&policydb, out_fp);
538 			break;
539 		case 'q':
540 			policydb_destroy(&policydb);
541 			exit(0);
542 			break;
543 		case 'm':
544 			menu();
545 			break;
546 		default:
547 			printf("\nInvalid choice\n");
548 			menu();
549 			break;
550 
551 		}
552 	}
553 }
554 
555 /* FLASK */
556