SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 1 | |
| 2 | /* Authors: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> |
| 3 | * |
| 4 | * Copyright (C) 2003,2004,2005 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 | * dismod.c |
| 12 | * |
| 13 | * Test program to the contents of a binary policy in text |
| 14 | * form. |
| 15 | * |
| 16 | * dismod binary_mod_file |
| 17 | */ |
| 18 | |
| 19 | #include <getopt.h> |
| 20 | #include <assert.h> |
| 21 | #include <sys/stat.h> |
| 22 | #include <sys/types.h> |
| 23 | #include <sys/mman.h> |
| 24 | #include <errno.h> |
| 25 | #include <stdio.h> |
| 26 | #include <fcntl.h> |
| 27 | #include <stdlib.h> |
| 28 | #include <unistd.h> |
| 29 | |
| 30 | #include <sepol/policydb/policydb.h> |
| 31 | #include <sepol/policydb/services.h> |
| 32 | #include <sepol/policydb/conditional.h> |
| 33 | #include <sepol/policydb/flask.h> |
| 34 | #include <sepol/policydb/link.h> |
| 35 | #include <sepol/policydb/module.h> |
| 36 | #include <sepol/policydb/util.h> |
| 37 | #include <sepol/policydb/polcaps.h> |
| 38 | |
| 39 | #include <byteswap.h> |
| 40 | #include <endian.h> |
| 41 | |
| 42 | #if __BYTE_ORDER == __LITTLE_ENDIAN |
| 43 | #define le32_to_cpu(x) (x) |
| 44 | #else |
| 45 | #define le32_to_cpu(x) bswap_32(x) |
| 46 | #endif |
| 47 | |
| 48 | #define DISPLAY_AVBLOCK_COND_AVTAB 0 |
| 49 | #define DISPLAY_AVBLOCK_UNCOND_AVTAB 1 |
| 50 | #define DISPLAY_AVBLOCK_ROLE_TYPE_NODE 2 /* unused? */ |
| 51 | #define DISPLAY_AVBLOCK_ROLE_TRANS 3 |
| 52 | #define DISPLAY_AVBLOCK_ROLE_ALLOW 4 |
| 53 | #define DISPLAY_AVBLOCK_REQUIRES 5 |
| 54 | #define DISPLAY_AVBLOCK_DECLARES 6 |
| 55 | #define DISPLAY_AVBLOCK_FILENAME_TRANS 7 |
| 56 | |
| 57 | static policydb_t policydb; |
| 58 | extern unsigned int ss_initialized; |
| 59 | |
| 60 | int policyvers = MOD_POLICYDB_VERSION_BASE; |
| 61 | |
| 62 | static const char *symbol_labels[9] = { |
| 63 | "commons", |
| 64 | "classes", "roles ", "types ", "users ", "bools ", |
| 65 | "levels ", "cats ", "attribs" |
| 66 | }; |
| 67 | |
| 68 | void usage(char *progname) |
| 69 | { |
| 70 | printf("usage: %s binary_pol_file\n\n", progname); |
| 71 | exit(1); |
| 72 | } |
| 73 | |
| 74 | static void render_access_mask(uint32_t mask, uint32_t class, policydb_t * p, |
| 75 | FILE * fp) |
| 76 | { |
| 77 | char *perm; |
| 78 | fprintf(fp, "{"); |
| 79 | perm = sepol_av_to_string(p, class, mask); |
| 80 | if (perm) |
| 81 | fprintf(fp, "%s ", perm); |
| 82 | fprintf(fp, "}"); |
| 83 | } |
| 84 | |
| 85 | static void render_access_bitmap(ebitmap_t * map, uint32_t class, |
| 86 | policydb_t * p, FILE * fp) |
| 87 | { |
| 88 | unsigned int i; |
| 89 | char *perm; |
| 90 | fprintf(fp, "{"); |
| 91 | for (i = ebitmap_startbit(map); i < ebitmap_length(map); i++) { |
| 92 | if (ebitmap_get_bit(map, i)) { |
| 93 | perm = sepol_av_to_string(p, class, 1 << i); |
| 94 | if (perm) |
| 95 | fprintf(fp, " %s", perm); |
| 96 | } |
| 97 | } |
| 98 | fprintf(fp, " }"); |
| 99 | } |
| 100 | |
| 101 | static void display_id(policydb_t * p, FILE * fp, uint32_t symbol_type, |
| 102 | uint32_t symbol_value, char *prefix) |
| 103 | { |
| 104 | char *id = p->sym_val_to_name[symbol_type][symbol_value]; |
| 105 | scope_datum_t *scope = |
| 106 | (scope_datum_t *) hashtab_search(p->scope[symbol_type].table, id); |
| 107 | assert(scope != NULL); |
| 108 | if (scope->scope == SCOPE_REQ) { |
| 109 | fprintf(fp, " [%s%s]", prefix, id); |
| 110 | } else { |
| 111 | fprintf(fp, " %s%s", prefix, id); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | int display_type_set(type_set_t * set, uint32_t flags, policydb_t * policy, |
| 116 | FILE * fp) |
| 117 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 118 | unsigned int i, num_types; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 119 | |
| 120 | if (set->flags & TYPE_STAR) { |
| 121 | fprintf(fp, " * "); |
| 122 | return 0; |
| 123 | } else if (set->flags & TYPE_COMP) { |
| 124 | fprintf(fp, " ~"); |
| 125 | } |
| 126 | |
| 127 | num_types = 0; |
| 128 | if (flags & RULE_SELF) { |
| 129 | num_types++; |
| 130 | } |
| 131 | |
| 132 | for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); |
| 133 | i++) { |
| 134 | if (!ebitmap_get_bit(&set->types, i)) |
| 135 | continue; |
| 136 | num_types++; |
| 137 | if (num_types > 1) |
| 138 | break; |
| 139 | } |
| 140 | |
| 141 | if (num_types <= 1) { |
| 142 | for (i = ebitmap_startbit(&set->negset); |
| 143 | i < ebitmap_length(&set->negset); i++) { |
| 144 | if (!ebitmap_get_bit(&set->negset, i)) |
| 145 | continue; |
| 146 | num_types++; |
| 147 | if (num_types > 1) |
| 148 | break; |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | if (num_types > 1) |
| 153 | fprintf(fp, "{"); |
| 154 | |
| 155 | for (i = ebitmap_startbit(&set->types); i < ebitmap_length(&set->types); |
| 156 | i++) { |
| 157 | if (!ebitmap_get_bit(&set->types, i)) |
| 158 | continue; |
| 159 | display_id(policy, fp, SYM_TYPES, i, ""); |
| 160 | } |
| 161 | |
| 162 | for (i = ebitmap_startbit(&set->negset); |
| 163 | i < ebitmap_length(&set->negset); i++) { |
| 164 | if (!ebitmap_get_bit(&set->negset, i)) |
| 165 | continue; |
| 166 | display_id(policy, fp, SYM_TYPES, i, "-"); |
| 167 | } |
| 168 | |
| 169 | if (flags & RULE_SELF) { |
| 170 | fprintf(fp, " self"); |
| 171 | } |
| 172 | |
| 173 | if (num_types > 1) |
| 174 | fprintf(fp, " }"); |
| 175 | |
| 176 | return 0; |
| 177 | } |
| 178 | |
| 179 | int display_mod_role_set(role_set_t * roles, policydb_t * p, FILE * fp) |
| 180 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 181 | unsigned int i, num = 0; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 182 | |
| 183 | if (roles->flags & ROLE_STAR) { |
| 184 | fprintf(fp, " * "); |
| 185 | return 0; |
| 186 | } else if (roles->flags & ROLE_COMP) { |
| 187 | fprintf(fp, " ~"); |
| 188 | } |
| 189 | |
| 190 | for (i = ebitmap_startbit(&roles->roles); |
| 191 | i < ebitmap_length(&roles->roles); i++) { |
| 192 | if (!ebitmap_get_bit(&roles->roles, i)) |
| 193 | continue; |
| 194 | num++; |
| 195 | if (num > 1) { |
| 196 | fprintf(fp, "{"); |
| 197 | break; |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | for (i = ebitmap_startbit(&roles->roles); |
| 202 | i < ebitmap_length(&roles->roles); i++) { |
| 203 | if (ebitmap_get_bit(&roles->roles, i)) |
| 204 | display_id(p, fp, SYM_ROLES, i, ""); |
| 205 | } |
| 206 | |
| 207 | if (num > 1) |
| 208 | fprintf(fp, " }"); |
| 209 | |
| 210 | return 0; |
| 211 | |
| 212 | } |
| 213 | |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 214 | int display_avrule(avrule_t * avrule, policydb_t * policy, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 215 | FILE * fp) |
| 216 | { |
| 217 | class_perm_node_t *cur; |
| 218 | int num_classes; |
| 219 | |
| 220 | if (avrule == NULL) { |
| 221 | fprintf(fp, " <empty>\n"); |
| 222 | return 0; |
| 223 | } |
| 224 | if (avrule->specified & AVRULE_AV) { |
| 225 | if (avrule->specified & AVRULE_ALLOWED) { |
| 226 | fprintf(fp, " allow"); |
| 227 | } |
| 228 | if (avrule->specified & AVRULE_AUDITALLOW) { |
| 229 | fprintf(fp, " auditallow "); |
| 230 | } |
| 231 | if (avrule->specified & AVRULE_DONTAUDIT) { |
| 232 | fprintf(fp, " dontaudit"); |
| 233 | } |
| 234 | } else if (avrule->specified & AVRULE_TYPE) { |
| 235 | if (avrule->specified & AVRULE_TRANSITION) { |
| 236 | fprintf(fp, " type_transition"); |
| 237 | } |
| 238 | if (avrule->specified & AVRULE_MEMBER) { |
| 239 | fprintf(fp, " type_member"); |
| 240 | } |
| 241 | if (avrule->specified & AVRULE_CHANGE) { |
| 242 | fprintf(fp, " type_change"); |
| 243 | } |
| 244 | } else if (avrule->specified & AVRULE_NEVERALLOW) { |
| 245 | fprintf(fp, " neverallow"); |
| 246 | } else { |
| 247 | fprintf(fp, " ERROR: no valid rule type specified\n"); |
| 248 | return -1; |
| 249 | } |
| 250 | |
| 251 | if (display_type_set(&avrule->stypes, 0, policy, fp)) |
| 252 | return -1; |
| 253 | |
| 254 | if (display_type_set(&avrule->ttypes, avrule->flags, policy, fp)) |
| 255 | return -1; |
| 256 | |
| 257 | fprintf(fp, " :"); |
| 258 | cur = avrule->perms; |
| 259 | num_classes = 0; |
| 260 | while (cur) { |
| 261 | num_classes++; |
| 262 | if (num_classes > 1) |
| 263 | break; |
| 264 | cur = cur->next; |
| 265 | } |
| 266 | |
| 267 | if (num_classes > 1) |
| 268 | fprintf(fp, " {"); |
| 269 | |
| 270 | cur = avrule->perms; |
| 271 | while (cur) { |
| 272 | display_id(policy, fp, SYM_CLASSES, cur->class - 1, ""); |
| 273 | cur = cur->next; |
| 274 | } |
| 275 | |
| 276 | if (num_classes > 1) |
| 277 | fprintf(fp, " }"); |
| 278 | fprintf(fp, " "); |
| 279 | |
| 280 | if (avrule->specified & (AVRULE_AV | AVRULE_NEVERALLOW)) { |
| 281 | render_access_mask(avrule->perms->data, avrule->perms->class, |
| 282 | policy, fp); |
| 283 | } else if (avrule->specified & AVRULE_TYPE) { |
| 284 | display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, ""); |
| 285 | } |
| 286 | |
| 287 | fprintf(fp, ";\n"); |
| 288 | |
| 289 | return 0; |
| 290 | } |
| 291 | |
| 292 | int display_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data) |
| 293 | { |
| 294 | type_datum_t *type; |
| 295 | FILE *fp; |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 296 | unsigned int i, first_attrib = 1; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 297 | |
| 298 | type = (type_datum_t *) datum; |
| 299 | fp = (FILE *) data; |
| 300 | |
| 301 | if (type->primary) { |
| 302 | display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); |
| 303 | fprintf(fp, " [%d]: ", type->s.value); |
| 304 | } else { |
| 305 | /* as that aliases have no value of their own and that |
| 306 | * they can never be required by a module, use this |
| 307 | * alternative way of displaying a name */ |
| 308 | fprintf(fp, " %s [%d]: ", (char *)key, type->s.value); |
| 309 | } |
| 310 | if (type->flavor == TYPE_ATTRIB) { |
| 311 | fprintf(fp, "attribute for types"); |
| 312 | for (i = ebitmap_startbit(&type->types); |
| 313 | i < ebitmap_length(&type->types); i++) { |
| 314 | if (!ebitmap_get_bit(&type->types, i)) |
| 315 | continue; |
| 316 | if (first_attrib) { |
| 317 | first_attrib = 0; |
| 318 | } else { |
| 319 | fprintf(fp, ","); |
| 320 | } |
| 321 | display_id(&policydb, fp, SYM_TYPES, i, ""); |
| 322 | } |
| 323 | } else if (type->primary) { |
| 324 | fprintf(fp, "type"); |
| 325 | } else { |
| 326 | fprintf(fp, "alias for type"); |
| 327 | display_id(&policydb, fp, SYM_TYPES, type->s.value - 1, ""); |
| 328 | } |
| 329 | fprintf(fp, " flags:%x\n", type->flags); |
| 330 | |
| 331 | return 0; |
| 332 | } |
| 333 | |
| 334 | int display_types(policydb_t * p, FILE * fp) |
| 335 | { |
| 336 | if (hashtab_map(p->p_types.table, display_type_callback, fp)) |
| 337 | return -1; |
| 338 | return 0; |
| 339 | } |
| 340 | |
| 341 | int display_users(policydb_t * p, FILE * fp) |
| 342 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 343 | unsigned int i, j; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 344 | ebitmap_t *bitmap; |
| 345 | for (i = 0; i < p->p_users.nprim; i++) { |
| 346 | display_id(p, fp, SYM_USERS, i, ""); |
| 347 | fprintf(fp, ":"); |
| 348 | bitmap = &(p->user_val_to_struct[i]->roles.roles); |
| 349 | for (j = ebitmap_startbit(bitmap); j < ebitmap_length(bitmap); |
| 350 | j++) { |
| 351 | if (ebitmap_get_bit(bitmap, j)) { |
| 352 | display_id(p, fp, SYM_ROLES, j, ""); |
| 353 | } |
| 354 | } |
| 355 | fprintf(fp, "\n"); |
| 356 | } |
| 357 | return 0; |
| 358 | } |
| 359 | |
| 360 | int display_bools(policydb_t * p, FILE * fp) |
| 361 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 362 | unsigned int i; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 363 | |
| 364 | for (i = 0; i < p->p_bools.nprim; i++) { |
| 365 | display_id(p, fp, SYM_BOOLS, i, ""); |
| 366 | fprintf(fp, " : %d\n", p->bool_val_to_struct[i]->state); |
| 367 | } |
| 368 | return 0; |
| 369 | } |
| 370 | |
| 371 | void display_expr(policydb_t * p, cond_expr_t * exp, FILE * fp) |
| 372 | { |
| 373 | |
| 374 | cond_expr_t *cur; |
| 375 | for (cur = exp; cur != NULL; cur = cur->next) { |
| 376 | switch (cur->expr_type) { |
| 377 | case COND_BOOL: |
| 378 | fprintf(fp, "%s ", |
| 379 | p->p_bool_val_to_name[cur->bool - 1]); |
| 380 | break; |
| 381 | case COND_NOT: |
| 382 | fprintf(fp, "! "); |
| 383 | break; |
| 384 | case COND_OR: |
| 385 | fprintf(fp, "|| "); |
| 386 | break; |
| 387 | case COND_AND: |
| 388 | fprintf(fp, "&& "); |
| 389 | break; |
| 390 | case COND_XOR: |
| 391 | fprintf(fp, "^ "); |
| 392 | break; |
| 393 | case COND_EQ: |
| 394 | fprintf(fp, "== "); |
| 395 | break; |
| 396 | case COND_NEQ: |
| 397 | fprintf(fp, "!= "); |
| 398 | break; |
| 399 | default: |
| 400 | fprintf(fp, "error!"); |
| 401 | break; |
| 402 | } |
| 403 | } |
| 404 | } |
| 405 | |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 406 | void display_policycon(FILE * fp) |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 407 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 408 | /* There was an attempt to implement this at one time. Look through |
| 409 | * git history to find it. */ |
| 410 | fprintf(fp, "Sorry, not implemented\n"); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 411 | } |
| 412 | |
| 413 | void display_initial_sids(policydb_t * p, FILE * fp) |
| 414 | { |
| 415 | ocontext_t *cur; |
| 416 | char *user, *role, *type; |
| 417 | |
| 418 | fprintf(fp, "Initial SIDs:\n"); |
| 419 | for (cur = p->ocontexts[OCON_ISID]; cur != NULL; cur = cur->next) { |
| 420 | user = p->p_user_val_to_name[cur->context[0].user - 1]; |
| 421 | role = p->p_role_val_to_name[cur->context[0].role - 1]; |
| 422 | type = p->p_type_val_to_name[cur->context[0].type - 1]; |
| 423 | fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", |
| 424 | cur->u.name, cur->sid[0], user, role, type); |
| 425 | } |
| 426 | #if 0 |
| 427 | fprintf(fp, "Policy Initial SIDs:\n"); |
| 428 | for (cur = p->ocontexts[OCON_POLICYISID]; cur != NULL; cur = cur->next) { |
| 429 | user = p->p_user_val_to_name[cur->context[0].user - 1]; |
| 430 | role = p->p_role_val_to_name[cur->context[0].role - 1]; |
| 431 | type = p->p_type_val_to_name[cur->context[0].type - 1]; |
| 432 | fprintf(fp, "\t%s: sid %d, context %s:%s:%s\n", |
| 433 | cur->u.name, cur->sid[0], user, role, type); |
| 434 | } |
| 435 | #endif |
| 436 | } |
| 437 | |
| 438 | void display_class_set(ebitmap_t *classes, policydb_t *p, FILE *fp) |
| 439 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 440 | unsigned int i, num = 0; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 441 | |
| 442 | for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { |
| 443 | if (!ebitmap_get_bit(classes, i)) |
| 444 | continue; |
| 445 | num++; |
| 446 | if (num > 1) { |
| 447 | fprintf(fp, "{"); |
| 448 | break; |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | for (i = ebitmap_startbit(classes); i < ebitmap_length(classes); i++) { |
| 453 | if (ebitmap_get_bit(classes, i)) |
| 454 | display_id(p, fp, SYM_CLASSES, i, ""); |
| 455 | } |
| 456 | |
| 457 | if (num > 1) |
| 458 | fprintf(fp, " }"); |
| 459 | } |
| 460 | |
| 461 | void display_role_trans(role_trans_rule_t * tr, policydb_t * p, FILE * fp) |
| 462 | { |
| 463 | for (; tr; tr = tr->next) { |
| 464 | fprintf(fp, "role transition "); |
| 465 | display_mod_role_set(&tr->roles, p, fp); |
| 466 | display_type_set(&tr->types, 0, p, fp); |
| 467 | fprintf(fp, " :"); |
| 468 | display_class_set(&tr->classes, p, fp); |
| 469 | display_id(p, fp, SYM_ROLES, tr->new_role - 1, ""); |
| 470 | fprintf(fp, "\n"); |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp) |
| 475 | { |
| 476 | for (; ra; ra = ra->next) { |
| 477 | fprintf(fp, "role allow "); |
| 478 | display_mod_role_set(&ra->roles, p, fp); |
| 479 | display_mod_role_set(&ra->new_roles, p, fp); |
| 480 | fprintf(fp, "\n"); |
| 481 | } |
| 482 | } |
| 483 | |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 484 | static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp) |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 485 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 486 | fprintf(fp, "filename transition"); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 487 | for (; tr; tr = tr->next) { |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 488 | display_type_set(&tr->stypes, 0, p, fp); |
| 489 | display_type_set(&tr->ttypes, 0, p, fp); |
| 490 | display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":"); |
| 491 | display_id(p, fp, SYM_TYPES, tr->otype - 1, ""); |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 492 | fprintf(fp, " %s\n", tr->name); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 493 | } |
| 494 | } |
| 495 | |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 496 | int role_display_callback(hashtab_key_t key __attribute__((unused)), |
| 497 | hashtab_datum_t datum, void *data) |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 498 | { |
| 499 | role_datum_t *role; |
| 500 | FILE *fp; |
| 501 | |
| 502 | role = (role_datum_t *) datum; |
| 503 | fp = (FILE *) data; |
| 504 | |
| 505 | fprintf(fp, "role:"); |
| 506 | display_id(&policydb, fp, SYM_ROLES, role->s.value - 1, ""); |
| 507 | fprintf(fp, " types: "); |
| 508 | display_type_set(&role->types, 0, &policydb, fp); |
| 509 | fprintf(fp, "\n"); |
| 510 | |
| 511 | return 0; |
| 512 | } |
| 513 | |
| 514 | static int display_scope_index(scope_index_t * indices, policydb_t * p, |
| 515 | FILE * out_fp) |
| 516 | { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 517 | unsigned int i; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 518 | for (i = 0; i < SYM_NUM; i++) { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 519 | unsigned int any_found = 0, j; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 520 | fprintf(out_fp, "%s:", symbol_labels[i]); |
| 521 | for (j = ebitmap_startbit(&indices->scope[i]); |
| 522 | j < ebitmap_length(&indices->scope[i]); j++) { |
| 523 | if (ebitmap_get_bit(&indices->scope[i], j)) { |
| 524 | any_found = 1; |
| 525 | fprintf(out_fp, " %s", |
| 526 | p->sym_val_to_name[i][j]); |
| 527 | if (i == SYM_CLASSES) { |
| 528 | if (j < indices->class_perms_len) { |
| 529 | render_access_bitmap(indices-> |
| 530 | class_perms_map |
| 531 | + j, j + 1, |
| 532 | p, out_fp); |
| 533 | } else { |
| 534 | fprintf(out_fp, |
| 535 | "<no perms known>"); |
| 536 | } |
| 537 | } |
| 538 | } |
| 539 | } |
| 540 | if (!any_found) { |
| 541 | fprintf(out_fp, " <empty>"); |
| 542 | } |
| 543 | fprintf(out_fp, "\n"); |
| 544 | } |
| 545 | return 0; |
| 546 | } |
| 547 | |
| 548 | #if 0 |
| 549 | int display_cond_expressions(policydb_t * p, FILE * fp) |
| 550 | { |
| 551 | cond_node_t *cur; |
| 552 | cond_av_list_t *av_cur; |
| 553 | for (cur = p->cond_list; cur != NULL; cur = cur->next) { |
| 554 | fprintf(fp, "expression: "); |
| 555 | display_expr(p, cur->expr, fp); |
| 556 | fprintf(fp, "current state: %d\n", cur->cur_state); |
| 557 | fprintf(fp, "True list:\n"); |
| 558 | for (av_cur = cur->true_list; av_cur != NULL; |
| 559 | av_cur = av_cur->next) { |
| 560 | fprintf(fp, "\t"); |
| 561 | render_av_rule(&av_cur->node->key, &av_cur->node->datum, |
| 562 | RENDER_CONDITIONAL, p, fp); |
| 563 | } |
| 564 | fprintf(fp, "False list:\n"); |
| 565 | for (av_cur = cur->false_list; av_cur != NULL; |
| 566 | av_cur = av_cur->next) { |
| 567 | fprintf(fp, "\t"); |
| 568 | render_av_rule(&av_cur->node->key, &av_cur->node->datum, |
| 569 | RENDER_CONDITIONAL, p, fp); |
| 570 | } |
| 571 | } |
| 572 | return 0; |
| 573 | } |
| 574 | |
| 575 | int change_bool(char *name, int state, policydb_t * p, FILE * fp) |
| 576 | { |
| 577 | cond_bool_datum_t *bool; |
| 578 | |
| 579 | bool = hashtab_search(p->p_bools.table, name); |
| 580 | if (bool == NULL) { |
| 581 | fprintf(fp, "Could not find bool %s\n", name); |
| 582 | return -1; |
| 583 | } |
| 584 | bool->state = state; |
| 585 | evaluate_conds(p); |
| 586 | return 0; |
| 587 | } |
| 588 | #endif |
| 589 | |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 590 | int display_avdecl(avrule_decl_t * decl, int field, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 591 | policydb_t * policy, FILE * out_fp) |
| 592 | { |
| 593 | fprintf(out_fp, "decl %u:%s\n", decl->decl_id, |
| 594 | (decl->enabled ? " [enabled]" : "")); |
| 595 | switch (field) { |
| 596 | case DISPLAY_AVBLOCK_COND_AVTAB:{ |
| 597 | cond_list_t *cond = decl->cond_list; |
| 598 | avrule_t *avrule; |
| 599 | while (cond) { |
| 600 | fprintf(out_fp, "expression: "); |
| 601 | display_expr(&policydb, cond->expr, out_fp); |
| 602 | fprintf(out_fp, "current state: %d\n", |
| 603 | cond->cur_state); |
| 604 | fprintf(out_fp, "True list:\n"); |
| 605 | avrule = cond->avtrue_list; |
| 606 | while (avrule) { |
| 607 | display_avrule(avrule, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 608 | &policydb, out_fp); |
| 609 | avrule = avrule->next; |
| 610 | } |
| 611 | fprintf(out_fp, "False list:\n"); |
| 612 | avrule = cond->avfalse_list; |
| 613 | while (avrule) { |
| 614 | display_avrule(avrule, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 615 | &policydb, out_fp); |
| 616 | avrule = avrule->next; |
| 617 | } |
| 618 | cond = cond->next; |
| 619 | } |
| 620 | break; |
| 621 | } |
| 622 | case DISPLAY_AVBLOCK_UNCOND_AVTAB:{ |
| 623 | avrule_t *avrule = decl->avrules; |
| 624 | if (avrule == NULL) { |
| 625 | fprintf(out_fp, " <empty>\n"); |
| 626 | } |
| 627 | while (avrule != NULL) { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 628 | if (display_avrule(avrule, policy, out_fp)) |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 629 | return -1; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 630 | avrule = avrule->next; |
| 631 | } |
| 632 | break; |
| 633 | } |
| 634 | case DISPLAY_AVBLOCK_ROLE_TYPE_NODE:{ /* role_type_node */ |
| 635 | break; |
| 636 | } |
| 637 | case DISPLAY_AVBLOCK_ROLE_TRANS:{ |
| 638 | display_role_trans(decl->role_tr_rules, policy, out_fp); |
| 639 | break; |
| 640 | } |
| 641 | case DISPLAY_AVBLOCK_ROLE_ALLOW:{ |
| 642 | display_role_allow(decl->role_allow_rules, policy, |
| 643 | out_fp); |
| 644 | break; |
| 645 | } |
| 646 | case DISPLAY_AVBLOCK_REQUIRES:{ |
| 647 | if (display_scope_index |
| 648 | (&decl->required, policy, out_fp)) { |
| 649 | return -1; |
| 650 | } |
| 651 | break; |
| 652 | } |
| 653 | case DISPLAY_AVBLOCK_DECLARES:{ |
| 654 | if (display_scope_index |
| 655 | (&decl->declared, policy, out_fp)) { |
| 656 | return -1; |
| 657 | } |
| 658 | break; |
| 659 | } |
| 660 | case DISPLAY_AVBLOCK_FILENAME_TRANS: |
| 661 | display_filename_trans(decl->filename_trans_rules, policy, |
| 662 | out_fp); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 663 | break; |
| 664 | default:{ |
| 665 | assert(0); |
| 666 | } |
| 667 | } |
| 668 | return 0; /* should never get here */ |
| 669 | } |
| 670 | |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 671 | int display_avblock(int field, policydb_t * policy, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 672 | FILE * out_fp) |
| 673 | { |
| 674 | avrule_block_t *block = policydb.global; |
| 675 | while (block != NULL) { |
| 676 | fprintf(out_fp, "--- begin avrule block ---\n"); |
| 677 | avrule_decl_t *decl = block->branch_list; |
| 678 | while (decl != NULL) { |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 679 | if (display_avdecl(decl, field, policy, out_fp)) { |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 680 | return -1; |
| 681 | } |
| 682 | decl = decl->next; |
| 683 | } |
| 684 | block = block->next; |
| 685 | } |
| 686 | return 0; |
| 687 | } |
| 688 | |
| 689 | int display_handle_unknown(policydb_t * p, FILE * out_fp) |
| 690 | { |
| 691 | if (p->handle_unknown == ALLOW_UNKNOWN) |
| 692 | fprintf(out_fp, "Allow unknown classes and perms\n"); |
| 693 | else if (p->handle_unknown == DENY_UNKNOWN) |
| 694 | fprintf(out_fp, "Deny unknown classes and perms\n"); |
| 695 | else if (p->handle_unknown == REJECT_UNKNOWN) |
| 696 | fprintf(out_fp, "Reject unknown classes and perms\n"); |
| 697 | return 0; |
| 698 | } |
| 699 | |
| 700 | static int read_policy(char *filename, policydb_t * policy) |
| 701 | { |
| 702 | FILE *in_fp; |
| 703 | struct policy_file f; |
| 704 | int retval; |
| 705 | uint32_t buf[1]; |
| 706 | |
| 707 | if ((in_fp = fopen(filename, "rb")) == NULL) { |
| 708 | fprintf(stderr, "Can't open '%s': %s\n", |
| 709 | filename, strerror(errno)); |
| 710 | exit(1); |
| 711 | } |
| 712 | policy_file_init(&f); |
| 713 | f.type = PF_USE_STDIO; |
| 714 | f.fp = in_fp; |
| 715 | |
| 716 | /* peek at the first byte. if they are indicative of a |
| 717 | package use the package reader, otherwise use the normal |
| 718 | policy reader */ |
| 719 | if (fread(buf, sizeof(uint32_t), 1, in_fp) != 1) { |
| 720 | fprintf(stderr, "Could not read from policy.\n"); |
| 721 | exit(1); |
| 722 | } |
| 723 | rewind(in_fp); |
| 724 | if (le32_to_cpu(buf[0]) == SEPOL_MODULE_PACKAGE_MAGIC) { |
| 725 | sepol_module_package_t *package; |
| 726 | if (sepol_module_package_create(&package)) { |
| 727 | fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); |
| 728 | exit(1); |
| 729 | } |
| 730 | package->policy = (sepol_policydb_t *) policy; |
| 731 | package->file_contexts = NULL; |
| 732 | retval = |
| 733 | sepol_module_package_read(package, |
| 734 | (sepol_policy_file_t *) & f, 1); |
| 735 | free(package->file_contexts); |
| 736 | } else { |
| 737 | if (policydb_init(policy)) { |
| 738 | fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); |
| 739 | exit(1); |
| 740 | } |
| 741 | retval = policydb_read(policy, &f, 1); |
| 742 | } |
| 743 | fclose(in_fp); |
| 744 | return retval; |
| 745 | } |
| 746 | |
| 747 | static void link_module(policydb_t * base, FILE * out_fp) |
| 748 | { |
| 749 | char module_name[80] = { 0 }; |
| 750 | int ret; |
| 751 | policydb_t module, *mods = &module; |
| 752 | |
| 753 | if (base->policy_type != POLICY_BASE) { |
| 754 | printf("Can only link if initial file was a base policy.\n"); |
| 755 | return; |
| 756 | } |
| 757 | printf("\nModule filename: "); |
| 758 | fgets(module_name, sizeof(module_name), stdin); |
| 759 | module_name[strlen(module_name) - 1] = '\0'; /* remove LF */ |
| 760 | if (module_name[0] == '\0') { |
| 761 | return; |
| 762 | } |
| 763 | |
| 764 | /* read the binary policy */ |
| 765 | fprintf(out_fp, "Reading module...\n"); |
| 766 | if (read_policy(module_name, mods)) { |
| 767 | fprintf(stderr, |
| 768 | "%s: error(s) encountered while loading policy\n", |
| 769 | module_name); |
| 770 | exit(1); |
| 771 | } |
| 772 | if (module.policy_type != POLICY_MOD) { |
| 773 | fprintf(stderr, "This file is not a loadable policy module.\n"); |
| 774 | exit(1); |
| 775 | } |
| 776 | if (policydb_index_classes(&module) || |
| 777 | policydb_index_others(NULL, &module, 0)) { |
| 778 | fprintf(stderr, "Could not index module.\n"); |
| 779 | exit(1); |
| 780 | } |
| 781 | ret = link_modules(NULL, base, &mods, 1, 0); |
| 782 | if (ret != 0) { |
| 783 | printf("Link failed (error %d)\n", ret); |
| 784 | printf("(You will probably need to restart dismod.)\n"); |
| 785 | } |
| 786 | policydb_destroy(&module); |
| 787 | return; |
| 788 | } |
| 789 | |
| 790 | static void display_policycaps(policydb_t * p, FILE * fp) |
| 791 | { |
| 792 | ebitmap_node_t *node; |
| 793 | const char *capname; |
| 794 | char buf[64]; |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 795 | unsigned int i; |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 796 | |
| 797 | fprintf(fp, "policy capabilities:\n"); |
| 798 | ebitmap_for_each_bit(&p->policycaps, node, i) { |
| 799 | if (ebitmap_node_get_bit(node, i)) { |
| 800 | capname = sepol_polcap_getname(i); |
| 801 | if (capname == NULL) { |
| 802 | snprintf(buf, sizeof(buf), "unknown (%d)", i); |
| 803 | capname = buf; |
| 804 | } |
| 805 | fprintf(fp, "\t%s\n", capname); |
| 806 | } |
| 807 | } |
| 808 | } |
| 809 | |
| 810 | int menu() |
| 811 | { |
| 812 | printf("\nSelect a command:\n"); |
| 813 | printf("1) display unconditional AVTAB\n"); |
| 814 | printf("2) display conditional AVTAB\n"); |
| 815 | printf("3) display users\n"); |
| 816 | printf("4) display bools\n"); |
| 817 | printf("5) display roles\n"); |
| 818 | printf("6) display types, attributes, and aliases\n"); |
| 819 | printf("7) display role transitions\n"); |
| 820 | printf("8) display role allows\n"); |
| 821 | printf("9) Display policycon\n"); |
| 822 | printf("0) Display initial SIDs\n"); |
| 823 | printf("\n"); |
| 824 | printf("a) Display avrule requirements\n"); |
| 825 | printf("b) Display avrule declarations\n"); |
| 826 | printf("c) Display policy capabilities\n"); |
| 827 | printf("l) Link in a module\n"); |
| 828 | printf("u) Display the unknown handling setting\n"); |
| 829 | printf("F) Display filename_trans rules\n"); |
| 830 | printf("\n"); |
| 831 | printf("f) set output file\n"); |
| 832 | printf("m) display menu\n"); |
| 833 | printf("q) quit\n"); |
| 834 | return 0; |
| 835 | } |
| 836 | |
| 837 | int main(int argc, char **argv) |
| 838 | { |
| 839 | FILE *out_fp = stdout; |
| 840 | char ans[81], OutfileName[121]; |
| 841 | |
| 842 | if (argc != 2) |
| 843 | usage(argv[0]); |
| 844 | |
| 845 | /* read the binary policy */ |
| 846 | fprintf(out_fp, "Reading policy...\n"); |
Stephen Smalley | 968aed0 | 2013-10-30 15:38:49 -0400 | [diff] [blame] | 847 | if (policydb_init(&policydb)) { |
| 848 | fprintf(stderr, "%s: Out of memory!\n", __FUNCTION__); |
| 849 | exit(1); |
| 850 | } |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 851 | if (read_policy(argv[1], &policydb)) { |
| 852 | fprintf(stderr, |
| 853 | "%s: error(s) encountered while loading policy\n", |
| 854 | argv[0]); |
| 855 | exit(1); |
| 856 | } |
| 857 | |
| 858 | if (policydb.policy_type != POLICY_BASE && |
| 859 | policydb.policy_type != POLICY_MOD) { |
| 860 | fprintf(stderr, |
| 861 | "This file is neither a base nor loadable policy module.\n"); |
| 862 | exit(1); |
| 863 | } |
| 864 | |
| 865 | if (policydb_index_classes(&policydb)) { |
| 866 | fprintf(stderr, "Error indexing classes\n"); |
| 867 | exit(1); |
| 868 | } |
| 869 | |
| 870 | if (policydb_index_others(NULL, &policydb, 1)) { |
| 871 | fprintf(stderr, "Error indexing others\n"); |
| 872 | exit(1); |
| 873 | } |
| 874 | |
| 875 | if (policydb.policy_type == POLICY_BASE) { |
| 876 | printf("Binary base policy file loaded.\n\n"); |
| 877 | } else { |
| 878 | printf("Binary policy module file loaded.\n"); |
| 879 | printf("Module name: %s\n", policydb.name); |
| 880 | printf("Module version: %s\n", policydb.version); |
| 881 | printf("\n"); |
| 882 | } |
| 883 | |
| 884 | menu(); |
| 885 | for (;;) { |
| 886 | printf("\nCommand (\'m\' for menu): "); |
| 887 | fgets(ans, sizeof(ans), stdin); |
| 888 | switch (ans[0]) { |
| 889 | |
| 890 | case '1': |
| 891 | fprintf(out_fp, "unconditional avtab:\n"); |
| 892 | display_avblock(DISPLAY_AVBLOCK_UNCOND_AVTAB, |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 893 | &policydb, out_fp); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 894 | break; |
| 895 | case '2': |
| 896 | fprintf(out_fp, "conditional avtab:\n"); |
| 897 | display_avblock(DISPLAY_AVBLOCK_COND_AVTAB, |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 898 | &policydb, out_fp); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 899 | break; |
| 900 | case '3': |
| 901 | display_users(&policydb, out_fp); |
| 902 | break; |
| 903 | case '4': |
| 904 | display_bools(&policydb, out_fp); |
| 905 | break; |
| 906 | case '5': |
| 907 | if (hashtab_map |
| 908 | (policydb.p_roles.table, role_display_callback, |
| 909 | out_fp)) |
| 910 | exit(1); |
| 911 | break; |
| 912 | case '6': |
| 913 | if (display_types(&policydb, out_fp)) { |
| 914 | fprintf(stderr, "Error displaying types\n"); |
| 915 | exit(1); |
| 916 | } |
| 917 | break; |
| 918 | case '7': |
| 919 | fprintf(out_fp, "role transitions:\n"); |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 920 | display_avblock(DISPLAY_AVBLOCK_ROLE_TRANS, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 921 | &policydb, out_fp); |
| 922 | break; |
| 923 | case '8': |
| 924 | fprintf(out_fp, "role allows:\n"); |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 925 | display_avblock(DISPLAY_AVBLOCK_ROLE_ALLOW, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 926 | &policydb, out_fp); |
| 927 | break; |
| 928 | case '9': |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 929 | display_policycon(out_fp); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 930 | break; |
| 931 | case '0': |
| 932 | display_initial_sids(&policydb, out_fp); |
| 933 | break; |
| 934 | case 'a': |
| 935 | fprintf(out_fp, "avrule block requirements:\n"); |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 936 | display_avblock(DISPLAY_AVBLOCK_REQUIRES, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 937 | &policydb, out_fp); |
| 938 | break; |
| 939 | case 'b': |
| 940 | fprintf(out_fp, "avrule block declarations:\n"); |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 941 | display_avblock(DISPLAY_AVBLOCK_DECLARES, |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 942 | &policydb, out_fp); |
| 943 | break; |
| 944 | case 'c': |
| 945 | display_policycaps(&policydb, out_fp); |
| 946 | break; |
| 947 | case 'u': |
| 948 | case 'U': |
| 949 | display_handle_unknown(&policydb, out_fp); |
| 950 | break; |
| 951 | case 'f': |
| 952 | printf |
| 953 | ("\nFilename for output (<CR> for screen output): "); |
| 954 | fgets(OutfileName, sizeof(OutfileName), stdin); |
| 955 | OutfileName[strlen(OutfileName) - 1] = '\0'; /* fix_string (remove LF) */ |
| 956 | if (strlen(OutfileName) == 0) |
| 957 | out_fp = stdout; |
| 958 | else if ((out_fp = fopen(OutfileName, "w")) == NULL) { |
| 959 | fprintf(stderr, "Cannot open output file %s\n", |
| 960 | OutfileName); |
| 961 | out_fp = stdout; |
| 962 | } |
| 963 | if (out_fp != stdout) |
| 964 | printf("\nOutput to file: %s\n", OutfileName); |
| 965 | break; |
| 966 | case 'F': |
| 967 | fprintf(out_fp, "filename_trans rules:\n"); |
| 968 | display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS, |
Stephen Smalley | cd88c5c | 2012-02-21 14:27:00 -0500 | [diff] [blame] | 969 | &policydb, out_fp); |
SE Android | 8c48de1 | 2012-01-24 05:27:18 -0800 | [diff] [blame] | 970 | break; |
| 971 | case 'l': |
| 972 | link_module(&policydb, out_fp); |
| 973 | break; |
| 974 | case 'q': |
| 975 | policydb_destroy(&policydb); |
| 976 | exit(0); |
| 977 | break; |
| 978 | case 'm': |
| 979 | menu(); |
| 980 | break; |
| 981 | default: |
| 982 | printf("\nInvalid choice\n"); |
| 983 | menu(); |
| 984 | break; |
| 985 | |
| 986 | } |
| 987 | } |
| 988 | exit(EXIT_SUCCESS); |
| 989 | } |