1115 lines
27 KiB
C
1115 lines
27 KiB
C
/* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
|
|
*
|
|
* Copyright (C) 2003,2004,2005 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.
|
|
*/
|
|
|
|
/*
|
|
* dismod.c
|
|
*
|
|
* Test program to the contents of a binary policy in text
|
|
* form.
|
|
*
|
|
* dismod binary_mod_file
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
#include <assert.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mman.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sepol/policydb/policydb.h>
|
|
#include <sepol/policydb/services.h>
|
|
#include <sepol/policydb/conditional.h>
|
|
#include <sepol/policydb/link.h>
|
|
#include <sepol/policydb/module.h>
|
|
#include <sepol/policydb/util.h>
|
|
#include <sepol/policydb/polcaps.h>
|
|
|
|
#include <byteswap.h>
|
|
#include <endian.h>
|
|
|
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
#define le32_to_cpu(x) (x)
|
|
#else
|
|
#define le32_to_cpu(x) bswap_32(x)
|
|
#endif
|
|
|
|
#define DISPLAY_AVBLOCK_COND_AVTAB 0
|
|
#define DISPLAY_AVBLOCK_UNCOND_AVTAB 1
|
|
#define DISPLAY_AVBLOCK_ROLE_TYPE_NODE 2 /* unused? */
|
|
#define DISPLAY_AVBLOCK_ROLE_TRANS 3
|
|
#define DISPLAY_AVBLOCK_ROLE_ALLOW 4
|
|
#define DISPLAY_AVBLOCK_REQUIRES 5
|
|
#define DISPLAY_AVBLOCK_DECLARES 6
|
|
#define DISPLAY_AVBLOCK_FILENAME_TRANS 7
|
|
|
|
static policydb_t policydb;
|
|
|
|
static const char *const symbol_labels[9] = {
|
|
"commons",
|
|
"classes", "roles ", "types ", "users ", "bools ",
|
|
"levels ", "cats ", "attribs"
|
|
};
|
|
|
|
static struct command {
|
|
enum {
|
|
EOL = 0,
|
|
HEADER = 1,
|
|
CMD = 1 << 1,
|
|
NOOPT = 1 << 2,
|
|
} meta;
|
|
char cmd;
|
|
const char *desc;
|
|
} commands[] = {
|
|
{HEADER, 0, "\nSelect a command:"},
|
|
{CMD, '1', "display unconditional AVTAB" },
|
|
{CMD, '2', "display conditional AVTAB" },
|
|
{CMD, '3', "display users" },
|
|
{CMD, '4', "display bools" },
|
|
{CMD, '5', "display roles" },
|
|
{CMD, '6', "display types, attributes, and aliases" },
|
|
{CMD, '7', "display role transitions" },
|
|
{CMD, '8', "display role allows" },
|
|
{CMD, '9', "Display policycon" },
|
|
{CMD, '0', "Display initial SIDs" },
|
|
{HEADER, 0, ""},
|
|
{CMD, 'a', "Display avrule requirements"},
|
|
{CMD, 'b', "Display avrule declarations"},
|
|
{CMD, 'c', "Display policy capabilities"},
|
|
{CMD|NOOPT, 'l', "Link in a module"},
|
|
{CMD, 'u', "Display the unknown handling setting"},
|
|
{CMD, 'F', "Display filename_trans rules"},
|
|
{CMD, 'v', "display the version of policy and/or module"},
|
|
{HEADER, 0, ""},
|
|
{CMD|NOOPT, 'f', "set output file"},
|
|
{CMD|NOOPT, 'm', "display menu"},
|
|
{CMD|NOOPT, 'q', "quit"},
|
|
{EOL, 0, "" },
|
|
};
|
|
|
|
static __attribute__((__noreturn__)) void usage(const char *progname)
|
|
{
|
|
puts("Usage:");
|
|
printf(" %s [OPTIONS] binary_pol_file\n\n", progname);
|
|
puts("Options:");
|
|
puts(" -h, --help print this help message");
|
|
puts(" -a, --actions ACTIONS run non-interactively");
|
|
puts("");
|
|
puts("Actions:");
|
|
for (unsigned int i = 0; commands[i].meta != EOL; i++) {
|
|
if (commands[i].meta == HEADER
|
|
|| commands[i].meta & NOOPT)
|
|
continue;
|
|
printf(" %c %s\n", commands[i].cmd, commands[i].desc);
|
|
}
|
|
puts("");
|
|
exit(1);
|
|
}
|
|
|
|
static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p,
|
|
FILE * fp)
|
|
{
|
|
char *perm = sepol_av_to_string(p, class, mask);
|
|
fprintf(fp, "{");
|
|
fprintf(fp, "%s ", perm ?: "<format-failure>");
|
|
fprintf(fp, "}");
|
|
free(perm);
|
|
}
|
|
|
|
static void render_access_bitmap(ebitmap_t * map, uint32_t class,
|
|
policydb_t * p, FILE * fp)
|
|
{
|
|
unsigned int i;
|
|
char *perm;
|
|
fprintf(fp, " {");
|
|
for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) {
|
|
if (ebitmap_get_bit(map, i)) {
|
|
perm = sepol_av_to_string(p, class, UINT32_C(1) << i);
|
|
fprintf(fp, "%s", perm ?: "<format-failure>");
|
|
free(perm);
|
|
}
|
|
}
|
|
fprintf(fp, " }");
|
|
}
|
|
|
|
static void display_id(policydb_t * p, FILE * fp, uint32_t symbol_type,
|
|
uint32_t symbol_value, const char *prefix)
|
|
{
|
|
char *id = p->sym_val_to_name[symbol_type][symbol_value];
|
|
scope_datum_t *scope =
|
|
(scope_datum_t *) hashtab_search(p->scope[symbol_type].table, id);
|
|
assert(scope != NULL);
|
|
if (scope->scope == SCOPE_REQ) {
|
|
fprintf(fp, " [%s%s]", prefix, id);
|
|
} else {
|
|
fprintf(fp, " %s%s", prefix, id);
|
|
}
|
|
}
|
|
|
|
static int display_type_set(type_set_t * set, uint32_t flags, policydb_t * policy,
|
|
FILE * fp)
|
|
{
|
|
unsigned int i, num_types;
|
|
|
|
if (set->flags & TYPE_STAR) {
|
|
fprintf(fp, " *");
|
|
return 0;
|
|
} else if (set->flags & TYPE_COMP) {
|
|
fprintf(fp, " ~");
|
|
} else {
|
|
fprintf(fp, " ");
|
|
}
|
|
|
|
num_types = 0;
|
|
if (flags & (RULE_SELF | RULE_NOTSELF)) {
|
|
num_types++;
|
|
}
|
|
|
|
for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types);
|
|
i++) {
|
|
if (!ebitmap_get_bit(&set->types, i))
|
|
continue;
|
|
num_types++;
|
|
if (num_types > 1)
|
|
break;
|
|
}
|
|
|
|
if (num_types <= 1) {
|
|
for (i = ebitmap_startbit(&set->negset);
|
|
i < ebitmap_length(&set->negset); i++) {
|
|
if (!ebitmap_get_bit(&set->negset, i))
|
|
continue;
|
|
num_types++;
|
|
if (num_types > 1)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (num_types > 1)
|
|
fprintf(fp, "{");
|
|
|
|
for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types);
|
|
i++) {
|
|
if (!ebitmap_get_bit(&set->types, i))
|
|
continue;
|
|
display_id(policy, fp, SYM_TYPES, i, "");
|
|
}
|
|
|
|
for (i = ebitmap_startbit(&set->negset);
|
|
i < ebitmap_length(&set->negset); i++) {
|
|
if (!ebitmap_get_bit(&set->negset, i))
|
|
continue;
|
|
display_id(policy, fp, SYM_TYPES, i, "-");
|
|
}
|
|
|
|
if (flags & RULE_SELF) {
|
|
fprintf(fp, " self");
|
|
}
|
|
|
|
if (flags & RULE_NOTSELF) {
|
|
if (set->flags & TYPE_COMP)
|
|
fprintf(fp, " self");
|
|
else
|
|
fprintf(fp, " -self");
|
|
}
|
|
|
|
if (num_types > 1)
|
|
fprintf(fp, " }");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int display_mod_role_set(role_set_t * roles, policydb_t * p, FILE * fp)
|
|
{
|
|
unsigned int i, num = 0;
|
|
|
|
if (roles->flags & ROLE_STAR) {
|
|
fprintf(fp, " * ");
|
|
return 0;
|
|
} else if (roles->flags & ROLE_COMP) {
|
|
fprintf(fp, " ~");
|
|
}
|
|
|
|
for (i = ebitmap_startbit(&roles->roles);
|
|
i < ebitmap_length(&roles->roles); i++) {
|
|
if (!ebitmap_get_bit(&roles->roles, i))
|
|
continue;
|
|
num++;
|
|
if (num > 1) {
|
|
fprintf(fp, "{");
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = ebitmap_startbit(&roles->roles);
|
|
i < ebitmap_length(&roles->roles); i++) {
|
|
if (ebitmap_get_bit(&roles->roles, i))
|
|
display_id(p, fp, SYM_ROLES, i, "");
|
|
}
|
|
|
|
if (num > 1)
|
|
fprintf(fp, " }");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static int display_avrule(avrule_t * avrule, policydb_t * policy,
|
|
FILE * fp)
|
|
{
|
|
class_perm_node_t *cur;
|
|
int num_classes;
|
|
|
|
if (avrule == NULL) {
|
|
fprintf(fp, " <empty>\n");
|
|
return 0;
|
|
}
|
|
if (avrule->specified & AVRULE_AV) {
|
|
if (avrule->specified & AVRULE_ALLOWED) {
|
|
fprintf(fp, " allow");
|
|
}
|
|
if (avrule->specified & AVRULE_AUDITALLOW) {
|
|
fprintf(fp, " auditallow ");
|
|
}
|
|
if (avrule->specified & AVRULE_DONTAUDIT) {
|
|
fprintf(fp, " dontaudit");
|
|
}
|
|
if (avrule->specified & AVRULE_NEVERALLOW) {
|
|
fprintf(fp, " neverallow");
|
|
}
|
|
} else if (avrule->specified & AVRULE_TYPE) {
|
|
if (avrule->specified & AVRULE_TRANSITION) {
|
|
fprintf(fp, " type_transition");
|
|
}
|
|
if (avrule->specified & AVRULE_MEMBER) {
|
|
fprintf(fp, " type_member");
|
|
}
|
|
if (avrule->specified & AVRULE_CHANGE) {
|
|
fprintf(fp, " type_change");
|
|
}
|
|
} else if (avrule->specified & AVRULE_XPERMS) {
|
|
if (avrule->specified & AVRULE_XPERMS_ALLOWED)
|
|
fprintf(fp, " allowxperm");
|
|
else if (avrule->specified & AVRULE_XPERMS_AUDITALLOW)
|
|
fprintf(fp, " auditallowxperm");
|
|
else if (avrule->specified & AVRULE_XPERMS_DONTAUDIT)
|
|
fprintf(fp, " dontauditxperm");
|
|
else if (avrule->specified & AVRULE_XPERMS_NEVERALLOW)
|
|
fprintf(fp, " neverallowxperm");
|
|
} else {
|
|
fprintf(fp, " ERROR: no valid rule type specified\n");
|
|
return -1;
|
|
}
|
|
|
|
if (display_type_set(&avrule->stypes, 0, policy, fp))
|
|
return -1;
|
|
|
|
if (display_type_set(&avrule->ttypes, avrule->flags, policy, fp))
|
|
return -1;
|
|
|
|
fprintf(fp, " :");
|
|
cur = avrule->perms;
|
|
num_classes = 0;
|
|
while (cur) {
|
|
num_classes++;
|
|
if (num_classes > 1)
|
|
break;
|
|
cur = cur->next;
|
|
}
|
|
|
|
if (num_classes > 1)
|
|
fprintf(fp, " {");
|
|
|
|
cur = avrule->perms;
|
|
while (cur) {
|
|
display_id(policy, fp, SYM_CLASSES, cur->tclass - 1, "");
|
|
cur = cur->next;
|
|
}
|
|
|
|
if (num_classes > 1)
|
|
fprintf(fp, " }");
|
|
fprintf(fp, " ");
|
|
|
|
if (avrule->specified & (AVRULE_AV | AVRULE_NEVERALLOW)) {
|
|
render_access_mask(avrule->perms->data, avrule->perms->tclass,
|
|
policy, fp);
|
|
} else if (avrule->specified & AVRULE_TYPE) {
|
|
display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, "");
|
|
} else if (avrule->specified & AVRULE_XPERMS) {
|
|
avtab_extended_perms_t xperms;
|
|
char *perms;
|
|
int i;
|
|
|
|
if (avrule->xperms->specified == AVRULE_XPERMS_IOCTLFUNCTION)
|
|
xperms.specified = AVTAB_XPERMS_IOCTLFUNCTION;
|
|
else if (avrule->xperms->specified == AVRULE_XPERMS_IOCTLDRIVER)
|
|
xperms.specified = AVTAB_XPERMS_IOCTLDRIVER;
|
|
else if (avrule->xperms->specified == AVRULE_XPERMS_NLMSG)
|
|
xperms.specified = AVTAB_XPERMS_NLMSG;
|
|
else {
|
|
fprintf(fp, " ERROR: no valid xperms specified\n");
|
|
return -1;
|
|
}
|
|
|
|
xperms.driver = avrule->xperms->driver;
|
|
for (i = 0; i < EXTENDED_PERMS_LEN; i++)
|
|
xperms.perms[i] = avrule->xperms->perms[i];
|
|
|
|
perms = sepol_extended_perms_to_string(&xperms);
|
|
if (!perms) {
|
|
fprintf(fp, " ERROR: failed to format xperms\n");
|
|
return -1;
|
|
}
|
|
fprintf(fp, "%s", perms);
|
|
free(perms);
|
|
}
|
|
|
|
fprintf(fp, ";\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int display_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
|
|
{
|
|
type_datum_t *type;
|
|
FILE *fp;
|
|
unsigned int i, first_attrib = 1;
|
|
|
|
type = (type_datum_t *) datum;
|
|
fp = (FILE *) data;
|
|
|
|
if (type->primary) {
|
|
display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, "");
|
|
fprintf(fp, " [%d]: ", type->s.value);
|
|
} else {
|
|
/* as that aliases have no value of their own and that
|
|
* they can never be required by a module, use this
|
|
* alternative way of displaying a name */
|
|
fprintf(fp, " %s [%d]: ", (char *)key, type->s.value);
|
|
}
|
|
if (type->flavor == TYPE_ATTRIB) {
|
|
fprintf(fp, "attribute for types");
|
|
for (i = ebitmap_startbit(&type->types);
|
|
i < ebitmap_length(&type->types); i++) {
|
|
if (!ebitmap_get_bit(&type->types, i))
|
|
continue;
|
|
if (first_attrib) {
|
|
first_attrib = 0;
|
|
} else {
|
|
fprintf(fp, ",");
|
|
}
|
|
display_id(&policydb, fp, SYM_TYPES, i, "");
|
|
}
|
|
} else if (type->primary) {
|
|
fprintf(fp, "type");
|
|
} else {
|
|
fprintf(fp, "alias for type");
|
|
display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, "");
|
|
}
|
|
fprintf(fp, " flags:%x\n", type->flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int display_types(policydb_t * p, FILE * fp)
|
|
{
|
|
if (hashtab_map(p->p_types.table, display_type_callback, fp))
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int display_users(policydb_t * p, FILE * fp)
|
|
{
|
|
unsigned int i, j;
|
|
ebitmap_t *bitmap;
|
|
for (i = 0; i < p->p_users.nprim; i++) {
|
|
display_id(p, fp, SYM_USERS, i, "");
|
|
fprintf(fp, ":");
|
|
bitmap = &(p->user_val_to_struct[i]->roles.roles);
|
|
for (j = ebitmap_startbit(bitmap); j < ebitmap_length(bitmap);
|
|
j++) {
|
|
if (ebitmap_get_bit(bitmap, j)) {
|
|
display_id(p, fp, SYM_ROLES, j, "");
|
|
}
|
|
}
|
|
fprintf(fp, "\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int display_bools(policydb_t * p, FILE * fp)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < p->p_bools.nprim; i++) {
|
|
display_id(p, fp, SYM_BOOLS, i, "");
|
|
fprintf(fp, " : %d\n", p->bool_val_to_struct[i]->state);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static 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->boolean - 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void display_policycon(FILE * fp)
|
|
{
|
|
/* There was an attempt to implement this at one time. Look through
|
|
* git history to find it. */
|
|
fprintf(fp, "Sorry, not implemented\n");
|
|
}
|
|
|
|
static void display_initial_sids(policydb_t * p, FILE * fp)
|
|
{
|
|
ocontext_t *cur;
|
|
char *user, *role, *type;
|
|
|
|
fprintf(fp, "Initial SIDs:\n");
|
|
for (cur = p->ocontexts[OCON_ISID]; cur != NULL; cur = cur->next) {
|
|
user = p->p_user_val_to_name[cur->context[0].user - 1];
|
|
role = p->p_role_val_to_name[cur->context[0].role - 1];
|
|
type = p->p_type_val_to_name[cur->context[0].type - 1];
|
|
fprintf(fp, "\tsid %d, context %s:%s:%s\n",
|
|
cur->sid[0], user, role, type);
|
|
}
|
|
#if 0
|
|
fprintf(fp, "Policy Initial SIDs:\n");
|
|
for (cur = p->ocontexts[OCON_POLICYISID]; cur != NULL; cur = cur->next) {
|
|
user = p->p_user_val_to_name[cur->context[0].user - 1];
|
|
role = p->p_role_val_to_name[cur->context[0].role - 1];
|
|
type = p->p_type_val_to_name[cur->context[0].type - 1];
|
|
fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n",
|
|
cur->u.name, cur->sid[0], user, role, type);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void display_class_set(ebitmap_t *classes, policydb_t *p, FILE *fp)
|
|
{
|
|
unsigned int i, num = 0;
|
|
|
|
for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) {
|
|
if (!ebitmap_get_bit(classes, i))
|
|
continue;
|
|
num++;
|
|
if (num > 1) {
|
|
fprintf(fp, "{");
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) {
|
|
if (ebitmap_get_bit(classes, i))
|
|
display_id(p, fp, SYM_CLASSES, i, "");
|
|
}
|
|
|
|
if (num > 1)
|
|
fprintf(fp, " }");
|
|
}
|
|
|
|
static void display_role_trans(role_trans_rule_t * tr, policydb_t * p, FILE * fp)
|
|
{
|
|
for (; tr; tr = tr->next) {
|
|
fprintf(fp, "role transition ");
|
|
display_mod_role_set(&tr->roles, p, fp);
|
|
display_type_set(&tr->types, 0, p, fp);
|
|
fprintf(fp, " :");
|
|
display_class_set(&tr->classes, p, fp);
|
|
display_id(p, fp, SYM_ROLES, tr->new_role - 1, "");
|
|
fprintf(fp, "\n");
|
|
}
|
|
}
|
|
|
|
static void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp)
|
|
{
|
|
for (; ra; ra = ra->next) {
|
|
fprintf(fp, "role allow ");
|
|
display_mod_role_set(&ra->roles, p, fp);
|
|
display_mod_role_set(&ra->new_roles, p, fp);
|
|
fprintf(fp, "\n");
|
|
}
|
|
}
|
|
|
|
static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp)
|
|
{
|
|
fprintf(fp, "filename transition");
|
|
for (; tr; tr = tr->next) {
|
|
display_type_set(&tr->stypes, 0, p, fp);
|
|
display_type_set(&tr->ttypes, 0, p, fp);
|
|
display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":");
|
|
display_id(p, fp, SYM_TYPES, tr->otype - 1, "");
|
|
fprintf(fp, " %s\n", tr->name);
|
|
}
|
|
}
|
|
|
|
static int role_display_callback(hashtab_key_t key __attribute__((unused)),
|
|
hashtab_datum_t datum, void *data)
|
|
{
|
|
role_datum_t *role;
|
|
FILE *fp;
|
|
|
|
role = (role_datum_t *) datum;
|
|
fp = (FILE *) data;
|
|
|
|
fprintf(fp, "role:");
|
|
display_id(&policydb, fp, SYM_ROLES, role->s.value - 1, "");
|
|
fprintf(fp, " types: ");
|
|
display_type_set(&role->types, 0, &policydb, fp);
|
|
fprintf(fp, "\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int display_scope_index(scope_index_t * indices, policydb_t * p,
|
|
FILE * out_fp)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < SYM_NUM; i++) {
|
|
unsigned int any_found = 0, j;
|
|
fprintf(out_fp, "%s:", symbol_labels[i]);
|
|
for (j = ebitmap_startbit(&indices->scope[i]);
|
|
j < ebitmap_length(&indices->scope[i]); j++) {
|
|
if (ebitmap_get_bit(&indices->scope[i], j)) {
|
|
any_found = 1;
|
|
fprintf(out_fp, " %s",
|
|
p->sym_val_to_name[i][j]);
|
|
if (i == SYM_CLASSES) {
|
|
if (j < indices->class_perms_len) {
|
|
render_access_bitmap(indices->
|
|
class_perms_map
|
|
+ j, j + 1,
|
|
p, out_fp);
|
|
} else {
|
|
fprintf(out_fp,
|
|
" <no perms known>");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!any_found) {
|
|
fprintf(out_fp, " <empty>");
|
|
}
|
|
fprintf(out_fp, "\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
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 change_bool(char *name, int state, policydb_t * p, FILE * fp)
|
|
{
|
|
cond_bool_datum_t *boolean;
|
|
|
|
boolean = hashtab_search(p->p_bools.table, name);
|
|
if (boolean == NULL) {
|
|
fprintf(fp, "Could not find bool %s\n", name);
|
|
return -1;
|
|
}
|
|
boolean->state = state;
|
|
evaluate_conds(p);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int display_avdecl(avrule_decl_t * decl, int field,
|
|
policydb_t * policy, FILE * out_fp)
|
|
{
|
|
fprintf(out_fp, "decl %u:%s\n", decl->decl_id,
|
|
(decl->enabled ? " [enabled]" : ""));
|
|
switch (field) {
|
|
case DISPLAY_AVBLOCK_COND_AVTAB:{
|
|
cond_list_t *cond = decl->cond_list;
|
|
avrule_t *avrule;
|
|
while (cond) {
|
|
fprintf(out_fp, "expression: ");
|
|
display_expr(&policydb, cond->expr, out_fp);
|
|
fprintf(out_fp, "current state: %d\n",
|
|
cond->cur_state);
|
|
fprintf(out_fp, "True list:\n");
|
|
avrule = cond->avtrue_list;
|
|
while (avrule) {
|
|
display_avrule(avrule,
|
|
&policydb, out_fp);
|
|
avrule = avrule->next;
|
|
}
|
|
fprintf(out_fp, "False list:\n");
|
|
avrule = cond->avfalse_list;
|
|
while (avrule) {
|
|
display_avrule(avrule,
|
|
&policydb, out_fp);
|
|
avrule = avrule->next;
|
|
}
|
|
cond = cond->next;
|
|
}
|
|
break;
|
|
}
|
|
case DISPLAY_AVBLOCK_UNCOND_AVTAB:{
|
|
avrule_t *avrule = decl->avrules;
|
|
if (avrule == NULL) {
|
|
fprintf(out_fp, " <empty>\n");
|
|
}
|
|
while (avrule != NULL) {
|
|
if (display_avrule(avrule, policy, out_fp))
|
|
return -1;
|
|
avrule = avrule->next;
|
|
}
|
|
break;
|
|
}
|
|
case DISPLAY_AVBLOCK_ROLE_TYPE_NODE:{ /* role_type_node */
|
|
break;
|
|
}
|
|
case DISPLAY_AVBLOCK_ROLE_TRANS:{
|
|
display_role_trans(decl->role_tr_rules, policy, out_fp);
|
|
break;
|
|
}
|
|
case DISPLAY_AVBLOCK_ROLE_ALLOW:{
|
|
display_role_allow(decl->role_allow_rules, policy,
|
|
out_fp);
|
|
break;
|
|
}
|
|
case DISPLAY_AVBLOCK_REQUIRES:{
|
|
if (display_scope_index
|
|
(&decl->required, policy, out_fp)) {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
case DISPLAY_AVBLOCK_DECLARES:{
|
|
if (display_scope_index
|
|
(&decl->declared, policy, out_fp)) {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
case DISPLAY_AVBLOCK_FILENAME_TRANS:
|
|
display_filename_trans(decl->filename_trans_rules, policy,
|
|
out_fp);
|
|
break;
|
|
default:{
|
|
assert(0);
|
|
}
|
|
}
|
|
return 0; /* should never get here */
|
|
}
|
|
|
|
static int display_avblock(int field, policydb_t * policy,
|
|
FILE * out_fp)
|
|
{
|
|
avrule_block_t *block = policydb.global;
|
|
while (block != NULL) {
|
|
avrule_decl_t *decl = block->branch_list;
|
|
fprintf(out_fp, "--- begin avrule block ---\n");
|
|
while (decl != NULL) {
|
|
if (display_avdecl(decl, field, policy, out_fp)) {
|
|
return -1;
|
|
}
|
|
decl = decl->next;
|
|
}
|
|
block = block->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int display_handle_unknown(policydb_t * p, FILE * out_fp)
|
|
{
|
|
if (p->handle_unknown == ALLOW_UNKNOWN)
|
|
fprintf(out_fp, "Allow unknown classes and perms\n");
|
|
else if (p->handle_unknown == DENY_UNKNOWN)
|
|
fprintf(out_fp, "Deny unknown classes and perms\n");
|
|
else if (p->handle_unknown == REJECT_UNKNOWN)
|
|
fprintf(out_fp, "Reject unknown classes and perms\n");
|
|
return 0;
|
|
}
|
|
|
|
static int read_policy(char *filename, policydb_t * policy, int verbose)
|
|
{
|
|
FILE *in_fp;
|
|
struct policy_file f;
|
|
int retval;
|
|
uint32_t buf[1];
|
|
|
|
if ((in_fp = fopen(filename, "rb")) == NULL) {
|
|
fprintf(stderr, "Can't open '%s': %s\n",
|
|
filename, strerror(errno));
|
|
exit(1);
|
|
}
|
|
policy_file_init(&f);
|
|
f.type = PF_USE_STDIO;
|
|
f.fp = in_fp;
|
|
|
|
/* peek at the first byte. if they are indicative of a
|
|
package use the package reader, otherwise use the normal
|
|
policy reader */
|
|
if (fread(buf, sizeof(uint32_t), 1, in_fp) != 1) {
|
|
fprintf(stderr, "Could not read from policy.\n");
|
|
exit(1);
|
|
}
|
|
rewind(in_fp);
|
|
if (le32_to_cpu(buf[0]) == SEPOL_MODULE_PACKAGE_MAGIC) {
|
|
sepol_module_package_t *package;
|
|
if (sepol_module_package_create(&package)) {
|
|
fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__);
|
|
exit(1);
|
|
}
|
|
sepol_policydb_free(package->policy);
|
|
package->policy = (sepol_policydb_t *) policy;
|
|
package->file_contexts = NULL;
|
|
retval =
|
|
sepol_module_package_read(package,
|
|
(sepol_policy_file_t *) & f, verbose);
|
|
package->policy = NULL;
|
|
sepol_module_package_free(package);
|
|
} else {
|
|
retval = policydb_read(policy, &f, verbose);
|
|
}
|
|
fclose(in_fp);
|
|
return retval;
|
|
}
|
|
|
|
static void link_module(policydb_t * base, FILE * out_fp, int verbose)
|
|
{
|
|
char module_name[80] = { 0 };
|
|
int ret;
|
|
policydb_t module, *mods = &module;
|
|
|
|
if (base->policy_type != POLICY_BASE) {
|
|
printf("Can only link if initial file was a base policy.\n");
|
|
return;
|
|
}
|
|
printf("\nModule filename: ");
|
|
if (fgets(module_name, sizeof(module_name), stdin) == NULL) {
|
|
fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
|
|
strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
module_name[strlen(module_name) - 1] = '\0'; /* remove LF */
|
|
if (module_name[0] == '\0') {
|
|
return;
|
|
}
|
|
|
|
if (policydb_init(mods)) {
|
|
fprintf(stderr, "Out of memory!\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* read the binary policy */
|
|
if (verbose)
|
|
fprintf(out_fp, "Reading module...\n");
|
|
policydb_set_target_platform(mods, base->target_platform);
|
|
if (read_policy(module_name, mods, verbose)) {
|
|
fprintf(stderr,
|
|
"%s: error(s) encountered while loading policy\n",
|
|
module_name);
|
|
exit(1);
|
|
}
|
|
if (module.policy_type != POLICY_MOD) {
|
|
fprintf(stderr, "This file is not a loadable policy module.\n");
|
|
exit(1);
|
|
}
|
|
if (policydb_index_classes(&module) ||
|
|
policydb_index_others(NULL, &module, 0)) {
|
|
fprintf(stderr, "Could not index module.\n");
|
|
exit(1);
|
|
}
|
|
ret = link_modules(NULL, base, &mods, 1, 0);
|
|
if (ret != 0) {
|
|
printf("Link failed (error %d)\n", ret);
|
|
printf("(You will probably need to restart dismod.)\n");
|
|
}
|
|
policydb_destroy(&module);
|
|
return;
|
|
}
|
|
|
|
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_positive_bit(&p->policycaps, node, i) {
|
|
capname = sepol_polcap_getname(i);
|
|
if (capname == NULL) {
|
|
snprintf(buf, sizeof(buf), "unknown (%u)", i);
|
|
capname = buf;
|
|
}
|
|
fprintf(fp, "\t%s\n", capname);
|
|
}
|
|
}
|
|
|
|
static int menu(void)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; commands[i].meta != EOL; i++) {
|
|
if (commands[i].meta == HEADER)
|
|
printf("%s\n", commands[i].desc);
|
|
else if (commands[i].meta & CMD)
|
|
printf("%c) %s\n", commands[i].cmd, commands[i].desc);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void print_version_info(policydb_t * p, FILE * fp)
|
|
{
|
|
if (p->policy_type == POLICY_BASE) {
|
|
fprintf(fp, "Binary base policy file loaded.\n");
|
|
} else {
|
|
fprintf(fp, "Binary policy module file loaded.\n");
|
|
fprintf(fp, "Module name: %s\n", p->name);
|
|
fprintf(fp, "Module version: %s\n", p->version);
|
|
}
|
|
|
|
fprintf(fp, "Policy version: %d\n\n", p->policyvers);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
char *ops = NULL;
|
|
char *mod;
|
|
FILE *out_fp = stdout;
|
|
char ans[81], OutfileName[121];
|
|
|
|
if (argc < 2 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)
|
|
usage(argv[0]);
|
|
|
|
mod = argv[1];
|
|
if (strcmp (mod, "--actions") == 0 || strcmp (mod, "-a") == 0) {
|
|
if (argc != 4) {
|
|
fprintf(stderr, "%s: unexpected number of arguments\n", argv[0]);
|
|
usage(argv[0]);
|
|
}
|
|
ops = argv[2];
|
|
mod = argv[3];
|
|
} else if (mod[0] == '-') {
|
|
fprintf(stderr, "%s: unknown option: %s\n", argv[0], mod);
|
|
usage(argv[0]);
|
|
}
|
|
|
|
/* read the binary policy */
|
|
if (!ops)
|
|
fprintf(out_fp, "Reading policy...\n");
|
|
if (policydb_init(&policydb)) {
|
|
fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__);
|
|
exit(1);
|
|
}
|
|
if (read_policy(mod, &policydb, ops? 0: 1)) {
|
|
fprintf(stderr,
|
|
"%s: error(s) encountered while loading policy\n",
|
|
argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
if (policydb.policy_type != POLICY_BASE &&
|
|
policydb.policy_type != POLICY_MOD) {
|
|
fprintf(stderr,
|
|
"This file is neither a base nor loadable policy module.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (policydb_index_classes(&policydb)) {
|
|
fprintf(stderr, "Error indexing classes\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (policydb_index_others(NULL, &policydb, ops? 0: 1)) {
|
|
fprintf(stderr, "Error indexing others\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (!ops) {
|
|
print_version_info(&policydb, stdout);
|
|
menu();
|
|
}
|
|
for (;;) {
|
|
if (ops) {
|
|
puts("");
|
|
ans[0] = *ops? *ops++: 'q';
|
|
ans[1] = '\0';
|
|
} else {
|
|
printf("\nCommand (\'m\' for menu): ");
|
|
if (fgets(ans, sizeof(ans), stdin) == NULL) {
|
|
if (feof(stdin))
|
|
break;
|
|
fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,
|
|
strerror(errno));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
switch (ans[0]) {
|
|
|
|
case '1':
|
|
fprintf(out_fp, "unconditional avtab:\n");
|
|
display_avblock(DISPLAY_AVBLOCK_UNCOND_AVTAB,
|
|
&policydb, out_fp);
|
|
break;
|
|
case '2':
|
|
fprintf(out_fp, "conditional avtab:\n");
|
|
display_avblock(DISPLAY_AVBLOCK_COND_AVTAB,
|
|
&policydb, out_fp);
|
|
break;
|
|
case '3':
|
|
display_users(&policydb, out_fp);
|
|
break;
|
|
case '4':
|
|
display_bools(&policydb, out_fp);
|
|
break;
|
|
case '5':
|
|
if (hashtab_map
|
|
(policydb.p_roles.table, role_display_callback,
|
|
out_fp))
|
|
exit(1);
|
|
break;
|
|
case '6':
|
|
if (display_types(&policydb, out_fp)) {
|
|
fprintf(stderr, "Error displaying types\n");
|
|
exit(1);
|
|
}
|
|
break;
|
|
case '7':
|
|
fprintf(out_fp, "role transitions:\n");
|
|
display_avblock(DISPLAY_AVBLOCK_ROLE_TRANS,
|
|
&policydb, out_fp);
|
|
break;
|
|
case '8':
|
|
fprintf(out_fp, "role allows:\n");
|
|
display_avblock(DISPLAY_AVBLOCK_ROLE_ALLOW,
|
|
&policydb, out_fp);
|
|
break;
|
|
case '9':
|
|
display_policycon(out_fp);
|
|
break;
|
|
case '0':
|
|
display_initial_sids(&policydb, out_fp);
|
|
break;
|
|
case 'a':
|
|
fprintf(out_fp, "avrule block requirements:\n");
|
|
display_avblock(DISPLAY_AVBLOCK_REQUIRES,
|
|
&policydb, out_fp);
|
|
break;
|
|
case 'b':
|
|
fprintf(out_fp, "avrule block declarations:\n");
|
|
display_avblock(DISPLAY_AVBLOCK_DECLARES,
|
|
&policydb, out_fp);
|
|
break;
|
|
case 'c':
|
|
display_policycaps(&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':
|
|
fprintf(out_fp, "filename_trans rules:\n");
|
|
display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS,
|
|
&policydb, out_fp);
|
|
break;
|
|
case 'l':
|
|
link_module(&policydb, out_fp, ops? 0: 1);
|
|
break;
|
|
case 'v':
|
|
print_version_info(&policydb, out_fp);
|
|
break;
|
|
case 'q':
|
|
policydb_destroy(&policydb);
|
|
exit(0);
|
|
break;
|
|
case 'm':
|
|
menu();
|
|
break;
|
|
default:
|
|
printf("\nInvalid choice\n");
|
|
menu();
|
|
break;
|
|
|
|
}
|
|
}
|
|
exit(EXIT_SUCCESS);
|
|
}
|