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