600 lines
15 KiB
C
600 lines
15 KiB
C
|
|
/* 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 xperms_test(x, p) (1 & (p[x >> 5] >> (x & 0x1f)))
|
|
#define next_bit_in_range(i, p) \
|
|
((i + 1 < sizeof(p)*8) && xperms_test((i + 1), p))
|
|
|
|
int render_ioctl(avtab_extended_perms_t * xperms, 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(xperms->perms)*8; bit++) {
|
|
if (!xperms_test(bit, xperms->perms))
|
|
continue;
|
|
|
|
if (in_range && next_bit_in_range(bit, xperms->perms)) {
|
|
/* continue until high value found */
|
|
continue;
|
|
} else if (next_bit_in_range(bit, xperms->perms)) {
|
|
/* low value */
|
|
low_bit = bit;
|
|
in_range = 1;
|
|
continue;
|
|
}
|
|
|
|
if (xperms->specified & AVTAB_XPERMS_IOCTLFUNCTION) {
|
|
value = xperms->driver<<8 | bit;
|
|
low_value = xperms->driver<<8 | low_bit;
|
|
if (in_range)
|
|
fprintf(fp, "0x%hx-0x%hx ", low_value, value);
|
|
else
|
|
fprintf(fp, "0x%hx ", value);
|
|
} else if (xperms->specified & AVTAB_XPERMS_IOCTLDRIVER) {
|
|
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_xperms(avtab_extended_perms_t * xperms, FILE * fp)
|
|
{
|
|
if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) ||
|
|
(xperms->specified == AVTAB_XPERMS_IOCTLDRIVER))
|
|
render_ioctl(xperms, 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_XPERMS) {
|
|
if (key->specified & AVTAB_XPERMS_ALLOWED)
|
|
fprintf(fp, "allowxperm ");
|
|
else if (key->specified & AVTAB_XPERMS_AUDITALLOW)
|
|
fprintf(fp, "auditallowxperm ");
|
|
else if (key->specified & AVTAB_XPERMS_DONTAUDIT)
|
|
fprintf(fp, "dontauditxperm ");
|
|
render_key(key, p, fp);
|
|
render_xperms(datum->xperms, 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 */
|