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