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