1 2/* 3 * Author : Stephen Smalley, <sds@tycho.nsa.gov> 4 */ 5 6/* 7 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 8 * 9 * Support for enhanced MLS infrastructure. 10 * 11 * Updated: Karl MacMillan <kmacmillan@tresys.com> 12 * 13 * Added conditional policy language extensions 14 * 15 * Updated: James Morris <jmorris@intercode.com.au> 16 * 17 * Added IPv6 support. 18 * 19 * Updated: Joshua Brindle <jbrindle@tresys.com> 20 * Karl MacMillan <kmacmillan@tresys.com> 21 * Jason Tang <jtang@tresys.com> 22 * 23 * Policy Module support. 24 * 25 * Copyright (C) 2017 Mellanox Technologies Inc. 26 * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 27 * Copyright (C) 2003 - 2005 Tresys Technology, LLC 28 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 29 * This program is free software; you can redistribute it and/or modify 30 * it under the terms of the GNU General Public License as published by 31 * the Free Software Foundation, version 2. 32 */ 33 34/* FLASK */ 35 36/* 37 * checkpolicy 38 * 39 * Load and check a policy configuration. 40 * 41 * A policy configuration is created in a text format, 42 * and then compiled into a binary format for use by 43 * the security server. By default, checkpolicy reads 44 * the text format. If '-b' is specified, then checkpolicy 45 * reads the binary format instead. 46 * 47 * If '-o output_file' is specified, then checkpolicy 48 * writes the binary format version of the configuration 49 * to the specified output file. 50 * 51 * If '-d' is specified, then checkpolicy permits the user 52 * to interactively test the security server functions with 53 * the loaded policy configuration. 54 * 55 * If '-c' is specified, then the supplied parameter is used to 56 * determine which policy version to use for generating binary 57 * policy. This is for compatibility with older kernels. If any 58 * booleans or conditional rules are thrown away a warning is printed. 59 */ 60 61#include <ctype.h> 62#include <getopt.h> 63#include <unistd.h> 64#include <stdlib.h> 65#include <sys/types.h> 66#include <sys/stat.h> 67#include <sys/socket.h> 68#include <netinet/in.h> 69#ifndef IPPROTO_DCCP 70#define IPPROTO_DCCP 33 71#endif 72#ifndef IPPROTO_SCTP 73#define IPPROTO_SCTP 132 74#endif 75#include <arpa/inet.h> 76#include <fcntl.h> 77#include <stdio.h> 78#include <errno.h> 79#include <sys/mman.h> 80 81#include <sepol/module_to_cil.h> 82#include <sepol/kernel_to_cil.h> 83#include <sepol/kernel_to_conf.h> 84#include <sepol/policydb/policydb.h> 85#include <sepol/policydb/services.h> 86#include <sepol/policydb/conditional.h> 87#include <sepol/policydb/hierarchy.h> 88#include <sepol/policydb/expand.h> 89#include <sepol/policydb/link.h> 90 91#include "queue.h" 92#include "checkpolicy.h" 93#include "parse_util.h" 94 95static policydb_t policydb; 96static sidtab_t sidtab; 97 98extern policydb_t *policydbp; 99extern int mlspol; 100extern int werror; 101 102static int handle_unknown = SEPOL_DENY_UNKNOWN; 103static const char *txtfile = "policy.conf"; 104static const char *binfile = "policy"; 105 106unsigned int policyvers = 0; 107 108static __attribute__((__noreturn__)) void usage(const char *progname) 109{ 110 printf 111 ("usage: %s [-b[F]] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M] " 112 "[-c policyvers (%d-%d)] [-o output_file|-] [-S] [-O] " 113 "[-t target_platform (selinux,xen)] [-E] [-V] [input_file]\n", 114 progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); 115 exit(1); 116} 117 118#define FGETS(out, size, in) \ 119do { \ 120 if (fgets(out,size,in)==NULL) { \ 121 fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__, \ 122 strerror(errno)); \ 123 exit(1);\ 124 } \ 125} while (0) 126 127static int print_sid(sepol_security_id_t sid, 128 context_struct_t * context 129 __attribute__ ((unused)), void *data 130 __attribute__ ((unused))) 131{ 132 sepol_security_context_t scontext; 133 size_t scontext_len; 134 int rc; 135 136 rc = sepol_sid_to_context(sid, &scontext, &scontext_len); 137 if (rc) 138 printf("sid %d -> error %d\n", sid, rc); 139 else { 140 printf("sid %d -> scontext %s\n", sid, scontext); 141 free(scontext); 142 } 143 return 0; 144} 145 146struct val_to_name { 147 unsigned int val; 148 char *name; 149}; 150 151static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p) 152{ 153 struct val_to_name *v = p; 154 perm_datum_t *perdatum; 155 156 perdatum = (perm_datum_t *) datum; 157 158 if (v->val == perdatum->s.value) { 159 v->name = key; 160 return 1; 161 } 162 163 return 0; 164} 165 166#ifdef EQUIVTYPES 167static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d, 168 struct avtab_node *type_rules) 169{ 170 struct avtab_node *p, *c, *n; 171 172 for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) { 173 /* 174 * Find the insertion point, keeping the list 175 * ordered by source type, then target type, then 176 * target class. 177 */ 178 if (k->source_type < c->key.source_type) 179 break; 180 if (k->source_type == c->key.source_type && 181 k->target_type < c->key.target_type) 182 break; 183 if (k->source_type == c->key.source_type && 184 k->target_type == c->key.target_type && 185 k->target_class < c->key.target_class) 186 break; 187 } 188 189 /* Insert the rule */ 190 n = malloc(sizeof(struct avtab_node)); 191 if (!n) { 192 fprintf(stderr, "out of memory\n"); 193 exit(1); 194 } 195 196 n->key = *k; 197 n->datum = *d; 198 n->next = p->next; 199 p->next = n; 200 return 0; 201} 202 203static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args) 204{ 205 struct avtab_node *type_rules = args; 206 207 if (d->specified & AVTAB_ALLOWED) { 208 /* 209 * Insert the rule into the lists for both 210 * the source type and the target type. 211 */ 212 if (insert_type_rule(k, d, &type_rules[k->source_type - 1])) 213 return -1; 214 if (insert_type_rule(k, d, &type_rules[k->target_type - 1])) 215 return -1; 216 } 217 218 return 0; 219} 220 221static void free_type_rules(struct avtab_node *l) 222{ 223 struct avtab_node *tmp; 224 225 while (l) { 226 tmp = l; 227 l = l->next; 228 free(tmp); 229 } 230} 231 232static int identify_equiv_types(void) 233{ 234 struct avtab_node *type_rules, *l1, *l2; 235 int i, j; 236 237 /* 238 * Create a list of access vector rules for each type 239 * from the access vector table. 240 */ 241 type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim); 242 if (!type_rules) { 243 fprintf(stderr, "out of memory\n"); 244 exit(1); 245 } 246 memset(type_rules, 0, 247 sizeof(struct avtab_node) * policydb.p_types.nprim); 248 if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules)) 249 exit(1); 250 251 /* 252 * Compare the type lists and identify equivalent types. 253 */ 254 for (i = 0; i < policydb.p_types.nprim - 1; i++) { 255 if (!type_rules[i].next) 256 continue; 257 for (j = i + 1; j < policydb.p_types.nprim; j++) { 258 for (l1 = type_rules[i].next, l2 = type_rules[j].next; 259 l1 && l2; l1 = l1->next, l2 = l2->next) { 260 if (l2->key.source_type == (j + 1)) { 261 if (l1->key.source_type != (i + 1)) 262 break; 263 } else { 264 if (l1->key.source_type != 265 l2->key.source_type) 266 break; 267 } 268 if (l2->key.target_type == (j + 1)) { 269 if (l1->key.target_type != (i + 1)) 270 break; 271 } else { 272 if (l1->key.target_type != 273 l2->key.target_type) 274 break; 275 } 276 if (l1->key.target_class != l2->key.target_class 277 || l1->datum.allowed != l2->datum.allowed) 278 break; 279 } 280 if (l1 || l2) 281 continue; 282 free_type_rules(type_rules[j].next); 283 type_rules[j].next = NULL; 284 printf("Types %s and %s are equivalent.\n", 285 policydb.p_type_val_to_name[i], 286 policydb.p_type_val_to_name[j]); 287 } 288 free_type_rules(type_rules[i].next); 289 type_rules[i].next = NULL; 290 } 291 292 free(type_rules); 293 return 0; 294} 295#endif 296 297static int display_bools(void) 298{ 299 uint32_t i; 300 301 for (i = 0; i < policydbp->p_bools.nprim; i++) { 302 printf("%s : %d\n", policydbp->p_bool_val_to_name[i], 303 policydbp->bool_val_to_struct[i]->state); 304 } 305 return 0; 306} 307 308static void display_expr(const cond_expr_t * exp) 309{ 310 311 const cond_expr_t *cur; 312 for (cur = exp; cur != NULL; cur = cur->next) { 313 switch (cur->expr_type) { 314 case COND_BOOL: 315 printf("%s ", 316 policydbp->p_bool_val_to_name[cur->bool - 1]); 317 break; 318 case COND_NOT: 319 printf("! "); 320 break; 321 case COND_OR: 322 printf("|| "); 323 break; 324 case COND_AND: 325 printf("&& "); 326 break; 327 case COND_XOR: 328 printf("^ "); 329 break; 330 case COND_EQ: 331 printf("== "); 332 break; 333 case COND_NEQ: 334 printf("!= "); 335 break; 336 default: 337 printf("error!"); 338 break; 339 } 340 } 341} 342 343static int display_cond_expressions(void) 344{ 345 const cond_node_t *cur; 346 347 for (cur = policydbp->cond_list; cur != NULL; cur = cur->next) { 348 printf("expression: "); 349 display_expr(cur->expr); 350 printf("current state: %d\n", cur->cur_state); 351 } 352 return 0; 353} 354 355static int change_bool(const char *name, int state) 356{ 357 cond_bool_datum_t *bool; 358 359 bool = hashtab_search(policydbp->p_bools.table, name); 360 if (bool == NULL) { 361 printf("Could not find bool %s\n", name); 362 return -1; 363 } 364 bool->state = state; 365 evaluate_conds(policydbp); 366 return 0; 367} 368 369static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused))) 370{ 371 level_datum_t *levdatum = (level_datum_t *) datum; 372 373 if (!levdatum->isalias && !levdatum->defined) { 374 fprintf(stderr, 375 "Error: sensitivity %s was not used in a level definition!\n", 376 key); 377 return -1; 378 } 379 return 0; 380} 381 382int main(int argc, char **argv) 383{ 384 policydb_t parse_policy; 385 sepol_security_class_t tclass; 386 sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid; 387 sepol_security_context_t scontext; 388 struct sepol_av_decision avd; 389 class_datum_t *cladatum; 390 const char *file = txtfile; 391 char ans[80 + 1], *path, *fstype; 392 const char *outfile = NULL; 393 size_t scontext_len, pathlen; 394 unsigned int i; 395 unsigned int protocol, port; 396 unsigned int binary = 0, debug = 0, sort = 0, cil = 0, conf = 0, optimize = 0; 397 struct val_to_name v; 398 int ret, ch, fd, target = SEPOL_TARGET_SELINUX; 399 unsigned int nel, uret; 400 struct stat sb; 401 void *map; 402 FILE *outfp = NULL; 403 char *name; 404 int state; 405 int show_version = 0; 406 char *reason_buf = NULL; 407 unsigned int reason; 408 int flags; 409 struct policy_file pf; 410 const struct option long_options[] = { 411 {"output", required_argument, NULL, 'o'}, 412 {"target", required_argument, NULL, 't'}, 413 {"binary", no_argument, NULL, 'b'}, 414 {"debug", no_argument, NULL, 'd'}, 415 {"version", no_argument, NULL, 'V'}, 416 {"handle-unknown", required_argument, NULL, 'U'}, 417 {"mls", no_argument, NULL, 'M'}, 418 {"cil", no_argument, NULL, 'C'}, 419 {"conf",no_argument, NULL, 'F'}, 420 {"sort", no_argument, NULL, 'S'}, 421 {"optimize", no_argument, NULL, 'O'}, 422 {"werror", no_argument, NULL, 'E'}, 423 {"help", no_argument, NULL, 'h'}, 424 {NULL, 0, NULL, 0} 425 }; 426 427 while ((ch = getopt_long(argc, argv, "o:t:dbU:MCFSVc:OEh", long_options, NULL)) != -1) { 428 switch (ch) { 429 case 'o': 430 outfile = optarg; 431 break; 432 case 't': 433 if (!strcasecmp(optarg, "Xen")) 434 target = SEPOL_TARGET_XEN; 435 else if (!strcasecmp(optarg, "SELinux")) 436 target = SEPOL_TARGET_SELINUX; 437 else{ 438 fprintf(stderr, "%s: Unknown target platform:" 439 "%s\n", argv[0], optarg); 440 exit(1); 441 } 442 break; 443 case 'b': 444 binary = 1; 445 file = binfile; 446 break; 447 case 'd': 448 debug = 1; 449 break; 450 case 'V': 451 show_version = 1; 452 break; 453 case 'U': 454 if (!strcasecmp(optarg, "deny")) { 455 handle_unknown = DENY_UNKNOWN; 456 break; 457 } 458 if (!strcasecmp(optarg, "allow")) { 459 handle_unknown = ALLOW_UNKNOWN; 460 break; 461 } 462 if (!strcasecmp(optarg, "reject")) { 463 handle_unknown = REJECT_UNKNOWN; 464 break; 465 } 466 usage(argv[0]); 467 case 'S': 468 sort = 1; 469 break; 470 case 'O': 471 optimize = 1; 472 break; 473 case 'M': 474 mlspol = 1; 475 break; 476 case 'C': 477 cil = 1; 478 break; 479 case 'F': 480 conf = 1; 481 break; 482 case 'c':{ 483 long int n; 484 errno = 0; 485 n = strtol(optarg, NULL, 10); 486 if (errno) { 487 fprintf(stderr, 488 "Invalid policyvers specified: %s\n", 489 optarg); 490 usage(argv[0]); 491 exit(1); 492 } 493 if (n < POLICYDB_VERSION_MIN 494 || n > POLICYDB_VERSION_MAX) { 495 fprintf(stderr, 496 "policyvers value %ld not in range %d-%d\n", 497 n, POLICYDB_VERSION_MIN, 498 POLICYDB_VERSION_MAX); 499 usage(argv[0]); 500 exit(1); 501 } 502 policyvers = n; 503 break; 504 } 505 case 'E': 506 werror = 1; 507 break; 508 case 'h': 509 default: 510 usage(argv[0]); 511 } 512 } 513 514 if (show_version) { 515 printf("%d (compatibility range %d-%d)\n", 516 policyvers ? policyvers : POLICYDB_VERSION_MAX , 517 POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN); 518 exit(0); 519 } 520 521 if (optind != argc) { 522 file = argv[optind++]; 523 if (optind != argc) 524 usage(argv[0]); 525 } 526 /* Set policydb and sidtab used by libsepol service functions 527 to my structures, so that I can directly populate and 528 manipulate them. */ 529 sepol_set_policydb(&policydb); 530 sepol_set_sidtab(&sidtab); 531 532 if (cil && conf) { 533 fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n"); 534 exit(1); 535 } 536 537 if (binary) { 538 fd = open(file, O_RDONLY); 539 if (fd < 0) { 540 fprintf(stderr, "Can't open '%s': %s\n", 541 file, strerror(errno)); 542 exit(1); 543 } 544 if (fstat(fd, &sb) < 0) { 545 fprintf(stderr, "Can't stat '%s': %s\n", 546 file, strerror(errno)); 547 exit(1); 548 } 549 map = 550 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, 551 fd, 0); 552 if (map == MAP_FAILED) { 553 fprintf(stderr, "Can't map '%s': %s\n", 554 file, strerror(errno)); 555 exit(1); 556 } 557 policy_file_init(&pf); 558 pf.type = PF_USE_MEMORY; 559 pf.data = map; 560 pf.len = sb.st_size; 561 if (policydb_init(&policydb)) { 562 fprintf(stderr, "%s: policydb_init: Out of memory!\n", 563 argv[0]); 564 exit(1); 565 } 566 ret = policydb_read(&policydb, &pf, 1); 567 if (ret) { 568 fprintf(stderr, 569 "%s: error(s) encountered while parsing configuration\n", 570 argv[0]); 571 exit(1); 572 } 573 policydbp = &policydb; 574 575 /* Check Policy Consistency */ 576 if (policydbp->mls) { 577 if (!mlspol) { 578 fprintf(stderr, "%s: MLS policy, but non-MLS" 579 " is specified\n", argv[0]); 580 exit(1); 581 } 582 } else { 583 if (mlspol) { 584 fprintf(stderr, "%s: non-MLS policy, but MLS" 585 " is specified\n", argv[0]); 586 exit(1); 587 } 588 } 589 590 if (policydbp->policyvers <= POLICYDB_VERSION_PERMISSIVE) { 591 if (policyvers > policydbp->policyvers) { 592 fprintf(stderr, "Binary policies with version <= %u cannot be upgraded\n", POLICYDB_VERSION_PERMISSIVE); 593 } else if (policyvers) { 594 policydbp->policyvers = policyvers; 595 } 596 } else { 597 policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX; 598 } 599 } else { 600 if (conf) { 601 fprintf(stderr, "Can only generate policy.conf from binary policy\n"); 602 exit(1); 603 } 604 if (policydb_init(&parse_policy)) 605 exit(1); 606 /* We build this as a base policy first since that is all the parser understands */ 607 parse_policy.policy_type = POLICY_BASE; 608 policydb_set_target_platform(&parse_policy, target); 609 610 /* Let sepol know if we are dealing with MLS support */ 611 parse_policy.mls = mlspol; 612 parse_policy.handle_unknown = handle_unknown; 613 614 policydbp = &parse_policy; 615 616 if (read_source_policy(policydbp, file, "checkpolicy") < 0) 617 exit(1); 618 619 if (hashtab_map(policydbp->p_levels.table, check_level, NULL)) 620 exit(1); 621 622 /* Linking takes care of optional avrule blocks */ 623 if (link_modules(NULL, policydbp, NULL, 0, 0)) { 624 fprintf(stderr, "Error while resolving optionals\n"); 625 exit(1); 626 } 627 628 if (!cil) { 629 if (policydb_init(&policydb)) { 630 fprintf(stderr, "%s: policydb_init failed\n", argv[0]); 631 exit(1); 632 } 633 if (expand_module(NULL, policydbp, &policydb, 0, 1)) { 634 fprintf(stderr, "Error while expanding policy\n"); 635 exit(1); 636 } 637 policydb_destroy(policydbp); 638 policydbp = &policydb; 639 } 640 641 policydbp->policyvers = policyvers ? policyvers : POLICYDB_VERSION_MAX; 642 } 643 644 if (policydb_load_isids(&policydb, &sidtab)) 645 exit(1); 646 647 if (optimize && policydbp->policy_type == POLICY_KERN) { 648 ret = policydb_optimize(policydbp); 649 if (ret) { 650 fprintf(stderr, "%s: error optimizing policy\n", argv[0]); 651 exit(1); 652 } 653 } 654 655 if (outfile) { 656 if (!strcmp(outfile, "-")) { 657 outfp = stdout; 658 outfile = "<STDOUT>"; 659 } else { 660 outfp = fopen(outfile, "w"); 661 if (!outfp) { 662 perror(outfile); 663 exit(1); 664 } 665 } 666 667 if (!cil) { 668 if (!conf) { 669 policydb.policy_type = POLICY_KERN; 670 671 policy_file_init(&pf); 672 pf.type = PF_USE_STDIO; 673 pf.fp = outfp; 674 if (sort) { 675 ret = policydb_sort_ocontexts(&policydb); 676 if (ret) { 677 fprintf(stderr, "%s: error sorting ocontexts\n", 678 argv[0]); 679 exit(1); 680 } 681 } 682 ret = policydb_write(&policydb, &pf); 683 } else { 684 ret = sepol_kernel_policydb_to_conf(outfp, policydbp); 685 } 686 if (ret) { 687 fprintf(stderr, "%s: error writing %s\n", 688 argv[0], outfile); 689 exit(1); 690 } 691 } else { 692 if (binary) { 693 ret = sepol_kernel_policydb_to_cil(outfp, policydbp); 694 } else { 695 ret = sepol_module_policydb_to_cil(outfp, policydbp, 1); 696 } 697 if (ret) { 698 fprintf(stderr, "%s: error writing %s\n", argv[0], outfile); 699 exit(1); 700 } 701 } 702 703 if (outfp != stdout) { 704 if(fclose(outfp)) { 705 fprintf(stderr, "%s: error closing %s: %s\n", argv[0], outfile, strerror(errno)); 706 exit(1); 707 } 708 } 709 } else if (cil) { 710 fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]); 711 exit(1); 712 } 713 714 if (!debug) { 715 policydb_destroy(&policydb); 716 sepol_sidtab_destroy(&sidtab); 717 exit(0); 718 } 719 720 menu: 721 printf("\nSelect an option:\n"); 722 printf("0) Call compute_access_vector\n"); 723 printf("1) Call sid_to_context\n"); 724 printf("2) Call context_to_sid\n"); 725 printf("3) Call transition_sid\n"); 726 printf("4) Call member_sid\n"); 727 printf("5) Call change_sid\n"); 728 printf("6) Call list_sids\n"); 729 printf("7) Call load_policy\n"); 730 printf("8) Call fs_sid\n"); 731 printf("9) Call port_sid\n"); 732 printf("a) Call netif_sid\n"); 733 printf("b) Call node_sid\n"); 734 printf("c) Call fs_use\n"); 735 printf("d) Call genfs_sid\n"); 736 printf("e) Call get_user_sids\n"); 737 printf("f) display conditional bools\n"); 738 printf("g) display conditional expressions\n"); 739 printf("h) change a boolean value\n"); 740 printf("i) display constraint expressions\n"); 741 printf("j) display validatetrans expressions\n"); 742 printf("k) Call ibpkey_sid\n"); 743 printf("l) Call ibendport_sid\n"); 744#ifdef EQUIVTYPES 745 printf("z) Show equivalent types\n"); 746#endif 747 printf("m) Show menu again\n"); 748 printf("q) Exit\n"); 749 while (1) { 750 printf("\nChoose: "); 751 FGETS(ans, sizeof(ans), stdin); 752 switch (ans[0]) { 753 case '0': 754 printf("source sid? "); 755 FGETS(ans, sizeof(ans), stdin); 756 ssid = atoi(ans); 757 758 printf("target sid? "); 759 FGETS(ans, sizeof(ans), stdin); 760 tsid = atoi(ans); 761 762 printf("target class? "); 763 FGETS(ans, sizeof(ans), stdin); 764 if (isdigit(ans[0])) { 765 tclass = atoi(ans); 766 if (!tclass 767 || tclass > policydb.p_classes.nprim) { 768 printf("\nNo such class.\n"); 769 break; 770 } 771 cladatum = 772 policydb.class_val_to_struct[tclass - 1]; 773 } else { 774 ans[strlen(ans) - 1] = 0; 775 cladatum = 776 (class_datum_t *) hashtab_search(policydb. 777 p_classes. 778 table, 779 ans); 780 if (!cladatum) { 781 printf("\nNo such class\n"); 782 break; 783 } 784 tclass = cladatum->s.value; 785 } 786 787 if (!cladatum->comdatum && !cladatum->permissions.nprim) { 788 printf 789 ("\nNo access vector definition for that class\n"); 790 break; 791 } 792 ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd); 793 switch (ret) { 794 case 0: 795 printf("\nallowed {"); 796 for (i = 1; i <= sizeof(avd.allowed) * 8; i++) { 797 if (avd.allowed & (UINT32_C(1) << (i - 1))) { 798 v.val = i; 799 ret = 800 hashtab_map(cladatum-> 801 permissions. 802 table, 803 find_perm, &v); 804 if (!ret && cladatum->comdatum) { 805 ret = 806 hashtab_map 807 (cladatum-> 808 comdatum-> 809 permissions.table, 810 find_perm, &v); 811 } 812 if (ret) 813 printf(" %s", v.name); 814 } 815 } 816 printf(" }\n"); 817 break; 818 case -EINVAL: 819 printf("\ninvalid sid\n"); 820 break; 821 default: 822 printf("return code 0x%x\n", ret); 823 } 824 break; 825 case '1': 826 printf("sid? "); 827 FGETS(ans, sizeof(ans), stdin); 828 ssid = atoi(ans); 829 ret = sepol_sid_to_context(ssid, 830 &scontext, &scontext_len); 831 switch (ret) { 832 case 0: 833 printf("\nscontext %s\n", scontext); 834 free(scontext); 835 break; 836 case -EINVAL: 837 printf("\ninvalid sid\n"); 838 break; 839 case -ENOMEM: 840 printf("\nout of memory\n"); 841 break; 842 default: 843 printf("return code 0x%x\n", ret); 844 } 845 break; 846 case '2': 847 printf("scontext? "); 848 FGETS(ans, sizeof(ans), stdin); 849 scontext_len = strlen(ans); 850 ans[scontext_len - 1] = 0; 851 ret = sepol_context_to_sid(ans, scontext_len, &ssid); 852 switch (ret) { 853 case 0: 854 printf("\nsid %d\n", ssid); 855 break; 856 case -EINVAL: 857 printf("\ninvalid context\n"); 858 break; 859 case -ENOMEM: 860 printf("\nout of memory\n"); 861 break; 862 default: 863 printf("return code 0x%x\n", ret); 864 } 865 break; 866 case '3': 867 case '4': 868 case '5': 869 ch = ans[0]; 870 871 printf("source sid? "); 872 FGETS(ans, sizeof(ans), stdin); 873 ssid = atoi(ans); 874 printf("target sid? "); 875 FGETS(ans, sizeof(ans), stdin); 876 tsid = atoi(ans); 877 878 printf("object class? "); 879 FGETS(ans, sizeof(ans), stdin); 880 if (isdigit(ans[0])) { 881 tclass = atoi(ans); 882 if (!tclass 883 || tclass > policydb.p_classes.nprim) { 884 printf("\nNo such class.\n"); 885 break; 886 } 887 } else { 888 ans[strlen(ans) - 1] = 0; 889 cladatum = 890 (class_datum_t *) hashtab_search(policydb. 891 p_classes. 892 table, 893 ans); 894 if (!cladatum) { 895 printf("\nNo such class\n"); 896 break; 897 } 898 tclass = cladatum->s.value; 899 } 900 901 if (ch == '3') 902 ret = 903 sepol_transition_sid(ssid, tsid, tclass, 904 &ssid); 905 else if (ch == '4') 906 ret = 907 sepol_member_sid(ssid, tsid, tclass, &ssid); 908 else 909 ret = 910 sepol_change_sid(ssid, tsid, tclass, &ssid); 911 switch (ret) { 912 case 0: 913 printf("\nsid %d\n", ssid); 914 break; 915 case -EINVAL: 916 printf("\ninvalid sid\n"); 917 break; 918 case -ENOMEM: 919 printf("\nout of memory\n"); 920 break; 921 default: 922 printf("return code 0x%x\n", ret); 923 } 924 break; 925 case '6': 926 sepol_sidtab_map(&sidtab, print_sid, 0); 927 break; 928 case '7': 929 printf("pathname? "); 930 FGETS(ans, sizeof(ans), stdin); 931 pathlen = strlen(ans); 932 ans[pathlen - 1] = 0; 933 fd = open(ans, O_RDONLY); 934 if (fd < 0) { 935 fprintf(stderr, "Can't open '%s': %s\n", 936 ans, strerror(errno)); 937 break; 938 } 939 if (fstat(fd, &sb) < 0) { 940 fprintf(stderr, "Can't stat '%s': %s\n", 941 ans, strerror(errno)); 942 break; 943 } 944 map = 945 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, 946 MAP_PRIVATE, fd, 0); 947 if (map == MAP_FAILED) { 948 fprintf(stderr, "Can't map '%s': %s\n", 949 ans, strerror(errno)); 950 break; 951 } 952 ret = sepol_load_policy(map, sb.st_size); 953 switch (ret) { 954 case 0: 955 printf("\nsuccess\n"); 956 break; 957 case -EINVAL: 958 printf("\ninvalid policy\n"); 959 break; 960 case -ENOMEM: 961 printf("\nout of memory\n"); 962 break; 963 default: 964 printf("return code 0x%x\n", ret); 965 } 966 break; 967 case '8': 968 printf("fs kdevname? "); 969 FGETS(ans, sizeof(ans), stdin); 970 ans[strlen(ans) - 1] = 0; 971 ret = sepol_fs_sid(ans, &ssid, &tsid); 972 if (ret) { 973 printf("unknown fs kdevname\n"); 974 } else { 975 printf("fs_sid %d default_file_sid %d\n", ssid, tsid); 976 } 977 break; 978 case '9': 979 printf("protocol? "); 980 FGETS(ans, sizeof(ans), stdin); 981 ans[strlen(ans) - 1] = 0; 982 if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP")) 983 protocol = IPPROTO_TCP; 984 else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP")) 985 protocol = IPPROTO_UDP; 986 else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP")) 987 protocol = IPPROTO_DCCP; 988 else if (!strcmp(ans, "sctp") || !strcmp(ans, "SCTP")) 989 protocol = IPPROTO_SCTP; 990 else { 991 printf("unknown protocol\n"); 992 break; 993 } 994 printf("port? "); 995 FGETS(ans, sizeof(ans), stdin); 996 port = atoi(ans); 997 sepol_port_sid(0, 0, protocol, port, &ssid); 998 printf("sid %d\n", ssid); 999 break; 1000 case 'a': 1001 printf("netif name? "); 1002 FGETS(ans, sizeof(ans), stdin); 1003 ans[strlen(ans) - 1] = 0; 1004 ret = sepol_netif_sid(ans, &ssid, &tsid); 1005 if (ret) { 1006 printf("unknown name\n"); 1007 } else { 1008 printf("if_sid %d default_msg_sid %d\n", ssid, tsid); 1009 } 1010 break; 1011 case 'b':{ 1012 char *p; 1013 int family, len; 1014 struct in_addr addr4; 1015 struct in6_addr addr6; 1016 1017 printf("protocol family? "); 1018 FGETS(ans, sizeof(ans), stdin); 1019 ans[strlen(ans) - 1] = 0; 1020 if (!strcasecmp(ans, "ipv4")) 1021 family = AF_INET; 1022 else if (!strcasecmp(ans, "ipv6")) 1023 family = AF_INET6; 1024 else { 1025 printf("unknown protocol family\n"); 1026 break; 1027 } 1028 1029 printf("node address? "); 1030 FGETS(ans, sizeof(ans), stdin); 1031 ans[strlen(ans) - 1] = 0; 1032 1033 if (family == AF_INET) { 1034 p = (char *)&addr4; 1035 len = sizeof(addr4); 1036 } else { 1037 p = (char *)&addr6; 1038 len = sizeof(addr6); 1039 } 1040 1041 if (inet_pton(family, ans, p) < 1) { 1042 printf("error parsing address\n"); 1043 break; 1044 } 1045 1046 sepol_node_sid(family, p, len, &ssid); 1047 printf("sid %d\n", ssid); 1048 break; 1049 } 1050 case 'c': 1051 printf("fstype? "); 1052 FGETS(ans, sizeof(ans), stdin); 1053 ans[strlen(ans) - 1] = 0; 1054 sepol_fs_use(ans, &uret, &ssid); 1055 switch (uret) { 1056 case SECURITY_FS_USE_XATTR: 1057 printf("use xattr\n"); 1058 break; 1059 case SECURITY_FS_USE_TRANS: 1060 printf("use transition SIDs\n"); 1061 break; 1062 case SECURITY_FS_USE_TASK: 1063 printf("use task SIDs\n"); 1064 break; 1065 case SECURITY_FS_USE_GENFS: 1066 printf("use genfs\n"); 1067 break; 1068 case SECURITY_FS_USE_NONE: 1069 printf("no labeling support\n"); 1070 break; 1071 } 1072 printf("sid %d\n", ssid); 1073 break; 1074 case 'd': 1075 printf("fstype? "); 1076 FGETS(ans, sizeof(ans), stdin); 1077 ans[strlen(ans) - 1] = 0; 1078 fstype = strdup(ans); 1079 printf("path? "); 1080 FGETS(ans, sizeof(ans), stdin); 1081 ans[strlen(ans) - 1] = 0; 1082 path = strdup(ans); 1083 printf("object class? "); 1084 FGETS(ans, sizeof(ans), stdin); 1085 if (isdigit(ans[0])) { 1086 tclass = atoi(ans); 1087 if (!tclass 1088 || tclass > policydb.p_classes.nprim) { 1089 printf("\nNo such class.\n"); 1090 break; 1091 } 1092 } else { 1093 ans[strlen(ans) - 1] = 0; 1094 cladatum = 1095 (class_datum_t *) hashtab_search(policydb. 1096 p_classes. 1097 table, 1098 ans); 1099 if (!cladatum) { 1100 printf("\nNo such class\n"); 1101 break; 1102 } 1103 tclass = cladatum->s.value; 1104 } 1105 sepol_genfs_sid(fstype, path, tclass, &ssid); 1106 printf("sid %d\n", ssid); 1107 free(fstype); 1108 free(path); 1109 break; 1110 case 'e': 1111 printf("from SID? "); 1112 FGETS(ans, sizeof(ans), stdin); 1113 ans[strlen(ans) - 1] = 0; 1114 ssid = atoi(ans); 1115 1116 printf("username? "); 1117 FGETS(ans, sizeof(ans), stdin); 1118 ans[strlen(ans) - 1] = 0; 1119 1120 ret = sepol_get_user_sids(ssid, ans, &sids, &nel); 1121 switch (ret) { 1122 case 0: 1123 if (!nel) 1124 printf("\nnone\n"); 1125 for (i = 0; i < nel; i++) 1126 print_sid(sids[i], NULL, NULL); 1127 free(sids); 1128 break; 1129 case -ENOMEM: 1130 printf("\nout of memory\n"); 1131 break; 1132 case -EINVAL: 1133 printf("\ninvalid argument\n"); 1134 break; 1135 default: 1136 printf("\nerror\n"); 1137 break; 1138 } 1139 break; 1140 case 'f': 1141 display_bools(); 1142 break; 1143 case 'g': 1144 display_cond_expressions(); 1145 break; 1146 case 'h': 1147 printf("name? "); 1148 FGETS(ans, sizeof(ans), stdin); 1149 ans[strlen(ans) - 1] = 0; 1150 1151 name = strdup(ans); 1152 if (name == NULL) { 1153 fprintf(stderr, "couldn't strdup string.\n"); 1154 break; 1155 } 1156 1157 printf("state? "); 1158 FGETS(ans, sizeof(ans), stdin); 1159 ans[strlen(ans) - 1] = 0; 1160 1161 if (atoi(ans)) 1162 state = 1; 1163 else 1164 state = 0; 1165 1166 change_bool(name, state); 1167 free(name); 1168 break; 1169 case 'i': 1170 printf("source sid? "); 1171 FGETS(ans, sizeof(ans), stdin); 1172 ssid = atoi(ans); 1173 1174 printf("target sid? "); 1175 FGETS(ans, sizeof(ans), stdin); 1176 tsid = atoi(ans); 1177 1178 printf("target class? "); 1179 FGETS(ans, sizeof(ans), stdin); 1180 if (isdigit(ans[0])) { 1181 tclass = atoi(ans); 1182 if (!tclass 1183 || tclass > policydb.p_classes.nprim) { 1184 printf("\nNo such class.\n"); 1185 break; 1186 } 1187 } else { 1188 ans[strlen(ans) - 1] = 0; 1189 cladatum = 1190 (class_datum_t *) hashtab_search(policydb. 1191 p_classes. 1192 table, 1193 ans); 1194 if (!cladatum) { 1195 printf("\nNo such class\n"); 1196 break; 1197 } 1198 tclass = cladatum->s.value; 1199 } 1200 1201 flags = SHOW_GRANTED; 1202 if (sepol_compute_av_reason_buffer(ssid, tsid, 1203 tclass, 0, &avd, &reason, 1204 &reason_buf, flags)) { 1205 printf("\nconstraint error\n"); 1206 break; 1207 } 1208 if (reason_buf) { 1209 printf("\nConstraint expressions:\n%s", 1210 reason_buf); 1211 free(reason_buf); 1212 } else { 1213 printf("\nNo constraints found.\n"); 1214 } 1215 break; 1216 case 'j': 1217 printf("old sid? "); 1218 FGETS(ans, sizeof(ans), stdin); 1219 oldsid = atoi(ans); 1220 1221 printf("new sid? "); 1222 FGETS(ans, sizeof(ans), stdin); 1223 newsid = atoi(ans); 1224 1225 printf("task sid? "); 1226 FGETS(ans, sizeof(ans), stdin); 1227 tasksid = atoi(ans); 1228 1229 printf("target class? "); 1230 FGETS(ans, sizeof(ans), stdin); 1231 if (isdigit(ans[0])) { 1232 tclass = atoi(ans); 1233 if (!tclass 1234 || tclass > policydb.p_classes.nprim) { 1235 printf("\nNo such class.\n"); 1236 break; 1237 } 1238 } else { 1239 ans[strlen(ans) - 1] = 0; 1240 cladatum = 1241 (class_datum_t *) hashtab_search(policydb. 1242 p_classes. 1243 table, 1244 ans); 1245 if (!cladatum) { 1246 printf("\nNo such class\n"); 1247 break; 1248 } 1249 tclass = cladatum->s.value; 1250 } 1251 1252 flags = SHOW_GRANTED; 1253 if (sepol_validate_transition_reason_buffer(oldsid, 1254 newsid, tasksid, tclass, 1255 &reason_buf, flags)) { 1256 printf("\nvalidatetrans error\n"); 1257 break; 1258 } 1259 if (reason_buf) { 1260 printf("\nValidatetrans expressions:\n%s", 1261 reason_buf); 1262 free(reason_buf); 1263 } else { 1264 printf( 1265 "\nNo validatetrans expressions found.\n"); 1266 } 1267 break; 1268 case 'k': 1269 { 1270 char *p; 1271 struct in6_addr addr6; 1272 uint64_t subnet_prefix; 1273 unsigned int pkey; 1274 1275 printf("subnet prefix? "); 1276 FGETS(ans, sizeof(ans), stdin); 1277 ans[strlen(ans) - 1] = 0; 1278 p = (char *)&addr6; 1279 1280 if (inet_pton(AF_INET6, ans, p) < 1) { 1281 printf("error parsing subnet prefix\n"); 1282 break; 1283 } 1284 1285 memcpy(&subnet_prefix, p, sizeof(subnet_prefix)); 1286 printf("pkey? "); 1287 FGETS(ans, sizeof(ans), stdin); 1288 pkey = atoi(ans); 1289 sepol_ibpkey_sid(subnet_prefix, pkey, &ssid); 1290 printf("sid %d\n", ssid); 1291 } 1292 break; 1293 case 'l': 1294 printf("device name (eg. mlx4_0)? "); 1295 FGETS(ans, sizeof(ans), stdin); 1296 ans[strlen(ans) - 1] = 0; 1297 1298 name = strdup(ans); 1299 if (!name) { 1300 fprintf(stderr, "couldn't strdup string.\n"); 1301 break; 1302 } 1303 1304 printf("port? "); 1305 FGETS(ans, sizeof(ans), stdin); 1306 port = atoi(ans); 1307 sepol_ibendport_sid(name, port, &ssid); 1308 printf("sid %d\n", ssid); 1309 free(name); 1310 break; 1311#ifdef EQUIVTYPES 1312 case 'z': 1313 identify_equiv_types(); 1314 break; 1315#endif 1316 case 'm': 1317 goto menu; 1318 case 'q': 1319 exit(0); 1320 break; 1321 default: 1322 printf("\nUnknown option %s.\n", ans); 1323 } 1324 } 1325 1326 return 0; 1327} 1328 1329/* FLASK */ 1330