/* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> * * Copyright (C) 2003 Tresys Technology, LLC * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 2. */ /* * displaypol.c * * Test program to the contents of a binary policy in text * form. This program currently only displays the * avtab (including conditional avtab) rules. * * displaypol binary_pol_file */ #include <sepol/policydb/policydb.h> #include <sepol/policydb/avtab.h> #include <sepol/policydb/services.h> #include <sepol/policydb/conditional.h> #include <sepol/policydb/util.h> #include <sepol/policydb/polcaps.h> #include <getopt.h> #include <assert.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/mman.h> #include <errno.h> #include <stdio.h> #include <fcntl.h> static policydb_t policydb; void usage(const char *progname) { printf("usage: %s binary_pol_file\n\n", progname); exit(1); } int render_access_mask(uint32_t mask, avtab_key_t * key, policydb_t * p, FILE * fp) { char *perm; fprintf(fp, "{"); perm = sepol_av_to_string(p, key->target_class, mask); if (perm) fprintf(fp, "%s ", perm); fprintf(fp, "}"); return 0; } #define operation_perm_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f))) #define next_bit_in_range(i, p) \ ((i + 1 < sizeof(p)*8) && operation_perm_test((i + 1), p)) int render_operations(avtab_operations_t *ops, avtab_key_t * key, FILE * fp) { uint16_t value; uint16_t low_bit; uint16_t low_value; unsigned int bit; unsigned int in_range = 0; fprintf(fp, "{ "); for (bit = 0; bit < sizeof(ops->perms)*8; bit++) { if (!operation_perm_test(bit, ops->perms)) continue; if (in_range && next_bit_in_range(bit, ops->perms)) { /* continue until high value found */ continue; } else if (next_bit_in_range(bit, ops->perms)) { /* low value */ low_bit = bit; in_range = 1; continue; } if (key->specified & AVTAB_OPNUM) { value = ops->type<<8 | bit; low_value = ops->type<<8 | low_bit; if (in_range) fprintf(fp, "0x%hx-0x%hx ", low_value, value); else fprintf(fp, "0x%hx ", value); } else if (key->specified & AVTAB_OPTYPE) { value = bit << 8; low_value = low_bit << 8; if (in_range) fprintf(fp, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff)); else fprintf(fp, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff)); } if (in_range) in_range = 0; } fprintf(fp, "}"); return 0; } int render_type(uint32_t type, policydb_t * p, FILE * fp) { fprintf(fp, "%s", p->p_type_val_to_name[type - 1]); return 0; } int render_key(avtab_key_t * key, policydb_t * p, FILE * fp) { char *stype, *ttype, *tclass; stype = p->p_type_val_to_name[key->source_type - 1]; ttype = p->p_type_val_to_name[key->target_type - 1]; tclass = p->p_class_val_to_name[key->target_class - 1]; if (stype && ttype) fprintf(fp, "%s %s : %s ", stype, ttype, tclass); else if (stype) fprintf(fp, "%s %u : %s ", stype, key->target_type, tclass); else if (ttype) fprintf(fp, "%u %s : %s ", key->source_type, ttype, tclass); else fprintf(fp, "%u %u : %s ", key->source_type, key->target_type, tclass); return 0; } /* 'what' values for this function */ #define RENDER_UNCONDITIONAL 0x0001 /* render all regardless of enabled state */ #define RENDER_ENABLED 0x0002 #define RENDER_DISABLED 0x0004 #define RENDER_CONDITIONAL (RENDER_ENABLED|RENDER_DISABLED) int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t what, policydb_t * p, FILE * fp) { if (!(what & RENDER_UNCONDITIONAL)) { if (what != RENDER_CONDITIONAL && (((what & RENDER_ENABLED) && !(key-> specified & AVTAB_ENABLED)) || ((what & RENDER_DISABLED) && (key-> specified & AVTAB_ENABLED)))) { return 0; /* doesn't match selection criteria */ } } if (!(what & RENDER_UNCONDITIONAL)) { if (key->specified & AVTAB_ENABLED) fprintf(fp, "[enabled] "); else if (!(key->specified & AVTAB_ENABLED)) fprintf(fp, "[disabled] "); } if (key->specified & AVTAB_AV) { if (key->specified & AVTAB_ALLOWED) { fprintf(fp, "allow "); render_key(key, p, fp); render_access_mask(datum->data, key, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_AUDITALLOW) { fprintf(fp, "auditallow "); render_key(key, p, fp); render_access_mask(datum->data, key, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_AUDITDENY) { fprintf(fp, "dontaudit "); render_key(key, p, fp); /* We inverse the mask for dontaudit since the mask is internally stored * as a auditdeny mask */ render_access_mask(~datum->data, key, p, fp); fprintf(fp, ";\n"); } } else if (key->specified & AVTAB_TYPE) { if (key->specified & AVTAB_TRANSITION) { fprintf(fp, "type_transition "); render_key(key, p, fp); render_type(datum->data, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_MEMBER) { fprintf(fp, "type_member "); render_key(key, p, fp); render_type(datum->data, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_CHANGE) { fprintf(fp, "type_change "); render_key(key, p, fp); render_type(datum->data, p, fp); fprintf(fp, ";\n"); } } else if (key->specified & AVTAB_OP) { if (key->specified & (AVTAB_OPNUM_ALLOWED|AVTAB_OPTYPE_ALLOWED)) fprintf(fp, "allow "); else if (key->specified & (AVTAB_OPNUM_AUDITALLOW|AVTAB_OPTYPE_AUDITALLOW)) fprintf(fp, "auditallow "); else if (key->specified & (AVTAB_OPNUM_DONTAUDIT|AVTAB_OPTYPE_DONTAUDIT)) fprintf(fp, "dontaudit "); render_key(key, p, fp); render_operations(datum->ops, key, fp); fprintf(fp, ";\n"); } else { fprintf(fp, " ERROR: no valid rule type specified\n"); return -1; } return 0; } int display_avtab(avtab_t * a, uint32_t what, policydb_t * p, FILE * fp) { unsigned int i; avtab_ptr_t cur; /* hmm...should have used avtab_map. */ for (i = 0; i < a->nslot; i++) { for (cur = a->htable[i]; cur; cur = cur->next) { render_av_rule(&cur->key, &cur->datum, what, p, fp); } } fprintf(fp, "\n"); return 0; } int display_bools(policydb_t * p, FILE * fp) { unsigned int i; for (i = 0; i < p->p_bools.nprim; i++) { fprintf(fp, "%s : %d\n", p->p_bool_val_to_name[i], p->bool_val_to_struct[i]->state); } return 0; } void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp) { cond_expr_t *cur; for (cur = exp; cur != NULL; cur = cur->next) { switch (cur->expr_type) { case COND_BOOL: fprintf(fp, "%s ", p->p_bool_val_to_name[cur->bool - 1]); break; case COND_NOT: fprintf(fp, "! "); break; case COND_OR: fprintf(fp, "|| "); break; case COND_AND: fprintf(fp, "&& "); break; case COND_XOR: fprintf(fp, "^ "); break; case COND_EQ: fprintf(fp, "== "); break; case COND_NEQ: fprintf(fp, "!= "); break; default: fprintf(fp, "error!"); break; } } } int display_cond_expressions(policydb_t * p, FILE * fp) { cond_node_t *cur; cond_av_list_t *av_cur; for (cur = p->cond_list; cur != NULL; cur = cur->next) { fprintf(fp, "expression: "); display_expr(p, cur->expr, fp); fprintf(fp, "current state: %d\n", cur->cur_state); fprintf(fp, "True list:\n"); for (av_cur = cur->true_list; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } fprintf(fp, "False list:\n"); for (av_cur = cur->false_list; av_cur != NULL; av_cur = av_cur->next) { fprintf(fp, "\t"); render_av_rule(&av_cur->node->key, &av_cur->node->datum, RENDER_CONDITIONAL, p, fp); } } return 0; } int display_handle_unknown(policydb_t * p, FILE * out_fp) { if (p->handle_unknown == ALLOW_UNKNOWN) fprintf(out_fp, "Allow unknown classes and permisions\n"); else if (p->handle_unknown == DENY_UNKNOWN) fprintf(out_fp, "Deny unknown classes and permisions\n"); else if (p->handle_unknown == REJECT_UNKNOWN) fprintf(out_fp, "Reject unknown classes and permisions\n"); return 0; } int change_bool(char *name, int state, policydb_t * p, FILE * fp) { cond_bool_datum_t *bool; bool = hashtab_search(p->p_bools.table, name); if (bool == NULL) { fprintf(fp, "Could not find bool %s\n", name); return -1; } bool->state = state; evaluate_conds(p); return 0; } static void display_policycaps(policydb_t * p, FILE * fp) { ebitmap_node_t *node; const char *capname; char buf[64]; unsigned int i; fprintf(fp, "policy capabilities:\n"); ebitmap_for_each_bit(&p->policycaps, node, i) { if (ebitmap_node_get_bit(node, i)) { capname = sepol_polcap_getname(i); if (capname == NULL) { snprintf(buf, sizeof(buf), "unknown (%d)", i); capname = buf; } fprintf(fp, "\t%s\n", capname); } } } static void display_id(policydb_t *p, FILE *fp, uint32_t symbol_type, uint32_t symbol_value, const char *prefix) { const char *id = p->sym_val_to_name[symbol_type][symbol_value]; fprintf(fp, " %s%s", prefix, id); } static void display_permissive(policydb_t *p, FILE *fp) { ebitmap_node_t *node; unsigned int i; fprintf(fp, "permissive sids:\n"); ebitmap_for_each_bit(&p->permissive_map, node, i) { if (ebitmap_node_get_bit(node, i)) { fprintf(fp, "\t"); display_id(p, fp, SYM_TYPES, i - 1, ""); fprintf(fp, "\n"); } } } static void display_role_trans(policydb_t *p, FILE *fp) { role_trans_t *rt; fprintf(fp, "role_trans rules:\n"); for (rt = p->role_tr; rt; rt = rt->next) { display_id(p, fp, SYM_ROLES, rt->role - 1, ""); display_id(p, fp, SYM_TYPES, rt->type - 1, ""); display_id(p, fp, SYM_CLASSES, rt->tclass - 1, ":"); display_id(p, fp, SYM_ROLES, rt->new_role - 1, ""); fprintf(fp, "\n"); } } static void display_filename_trans(policydb_t *p, FILE *fp) { filename_trans_t *ft; fprintf(fp, "filename_trans rules:\n"); for (ft = p->filename_trans; ft; ft = ft->next) { display_id(p, fp, SYM_TYPES, ft->stype - 1, ""); display_id(p, fp, SYM_TYPES, ft->ttype - 1, ""); display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":"); display_id(p, fp, SYM_TYPES, ft->otype - 1, ""); fprintf(fp, " %s\n", ft->name); } } int menu(void) { printf("\nSelect a command:\n"); printf("1) display unconditional AVTAB\n"); printf("2) display conditional AVTAB (entirely)\n"); printf("3) display conditional AVTAG (only ENABLED rules)\n"); printf("4) display conditional AVTAB (only DISABLED rules)\n"); printf("5) display conditional bools\n"); printf("6) display conditional expressions\n"); printf("7) change a boolean value\n"); printf("8) display role transitions\n"); printf("\n"); printf("c) display policy capabilities\n"); printf("p) display the list of permissive types\n"); printf("u) display unknown handling setting\n"); printf("F) display filename_trans rules\n"); printf("\n"); printf("f) set output file\n"); printf("m) display menu\n"); printf("q) quit\n"); return 0; } int main(int argc, char **argv) { FILE *out_fp = stdout; char ans[81], OutfileName[121]; int fd, ret; struct stat sb; void *map; char *name; int state; struct policy_file pf; if (argc != 2) usage(argv[0]); fd = open(argv[1], O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open '%s': %s\n", argv[1], strerror(errno)); exit(1); } if (fstat(fd, &sb) < 0) { fprintf(stderr, "Can't stat '%s': %s\n", argv[1], strerror(errno)); exit(1); } map = mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); if (map == MAP_FAILED) { fprintf(stderr, "Can't map '%s': %s\n", argv[1], strerror(errno)); exit(1); } /* read the binary policy */ fprintf(out_fp, "Reading policy...\n"); policy_file_init(&pf); pf.type = PF_USE_MEMORY; pf.data = map; pf.len = sb.st_size; if (policydb_init(&policydb)) { fprintf(stderr, "%s: Out of memory!\n", argv[0]); exit(1); } ret = policydb_read(&policydb, &pf, 1); if (ret) { fprintf(stderr, "%s: error(s) encountered while parsing configuration\n", argv[0]); exit(1); } fprintf(stdout, "binary policy file loaded\n\n"); close(fd); menu(); for (;;) { printf("\nCommand (\'m\' for menu): "); if (fgets(ans, sizeof(ans), stdin) == NULL) { fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, strerror(errno)); continue; } switch (ans[0]) { case '1': display_avtab(&policydb.te_avtab, RENDER_UNCONDITIONAL, &policydb, out_fp); break; case '2': display_avtab(&policydb.te_cond_avtab, RENDER_CONDITIONAL, &policydb, out_fp); break; case '3': display_avtab(&policydb.te_cond_avtab, RENDER_ENABLED, &policydb, out_fp); break; case '4': display_avtab(&policydb.te_cond_avtab, RENDER_DISABLED, &policydb, out_fp); break; case '5': display_bools(&policydb, out_fp); break; case '6': display_cond_expressions(&policydb, out_fp); break; case '7': printf("name? "); if (fgets(ans, sizeof(ans), stdin) == NULL) { fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, strerror(errno)); break; } ans[strlen(ans) - 1] = 0; name = malloc((strlen(ans) + 1) * sizeof(char)); if (name == NULL) { fprintf(stderr, "couldn't malloc string.\n"); break; } strcpy(name, ans); printf("state? "); if (fgets(ans, sizeof(ans), stdin) == NULL) { fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, strerror(errno)); break; } ans[strlen(ans) - 1] = 0; if (atoi(ans)) state = 1; else state = 0; change_bool(name, state, &policydb, out_fp); free(name); break; case '8': display_role_trans(&policydb, out_fp); break; case 'c': display_policycaps(&policydb, out_fp); break; case 'p': display_permissive(&policydb, out_fp); break; case 'u': case 'U': display_handle_unknown(&policydb, out_fp); break; case 'f': printf ("\nFilename for output (<CR> for screen output): "); if (fgets(OutfileName, sizeof(OutfileName), stdin) == NULL) { fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, strerror(errno)); break; } OutfileName[strlen(OutfileName) - 1] = '\0'; /* fix_string (remove LF) */ if (strlen(OutfileName) == 0) out_fp = stdout; else if ((out_fp = fopen(OutfileName, "w")) == NULL) { fprintf(stderr, "Cannot open output file %s\n", OutfileName); out_fp = stdout; } if (out_fp != stdout) printf("\nOutput to file: %s\n", OutfileName); break; case 'F': display_filename_trans(&policydb, out_fp); break; case 'q': policydb_destroy(&policydb); exit(0); break; case 'm': menu(); break; default: printf("\nInvalid choice\n"); menu(); break; } } } /* FLASK */