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 static policydb_t policydb;
96 static sidtab_t sidtab;
97
98 extern policydb_t *policydbp;
99 extern int mlspol;
100 extern int werror;
101
102 static int handle_unknown = SEPOL_DENY_UNKNOWN;
103 static const char *txtfile = "policy.conf";
104 static const char *binfile = "policy";
105
106 unsigned int policyvers = 0;
107
usage(const char * progname)108 static __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) \
119 do { \
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
print_sid(sepol_security_id_t sid,context_struct_t * context,void * data)127 static 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
146 struct val_to_name {
147 unsigned int val;
148 char *name;
149 };
150
find_perm(hashtab_key_t key,hashtab_datum_t datum,void * p)151 static 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
insert_type_rule(avtab_key_t * k,avtab_datum_t * d,struct avtab_node * type_rules)167 static 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
create_type_rules(avtab_key_t * k,avtab_datum_t * d,void * args)203 static 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
free_type_rules(struct avtab_node * l)221 static 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
identify_equiv_types(void)232 static 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
display_bools(void)297 static 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
display_expr(const cond_expr_t * exp)308 static 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
display_cond_expressions(void)343 static 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
change_bool(const char * name,int state)355 static 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
check_level(hashtab_key_t key,hashtab_datum_t datum,void * arg)369 static 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
main(int argc,char ** argv)382 int 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 = malloc((strlen(ans) + 1) * sizeof(char));
1152 if (name == NULL) {
1153 fprintf(stderr, "couldn't malloc string.\n");
1154 break;
1155 }
1156 strcpy(name, ans);
1157
1158 printf("state? ");
1159 FGETS(ans, sizeof(ans), stdin);
1160 ans[strlen(ans) - 1] = 0;
1161
1162 if (atoi(ans))
1163 state = 1;
1164 else
1165 state = 0;
1166
1167 change_bool(name, state);
1168 free(name);
1169 break;
1170 case 'i':
1171 printf("source sid? ");
1172 FGETS(ans, sizeof(ans), stdin);
1173 ssid = atoi(ans);
1174
1175 printf("target sid? ");
1176 FGETS(ans, sizeof(ans), stdin);
1177 tsid = atoi(ans);
1178
1179 printf("target class? ");
1180 FGETS(ans, sizeof(ans), stdin);
1181 if (isdigit(ans[0])) {
1182 tclass = atoi(ans);
1183 if (!tclass
1184 || tclass > policydb.p_classes.nprim) {
1185 printf("\nNo such class.\n");
1186 break;
1187 }
1188 } else {
1189 ans[strlen(ans) - 1] = 0;
1190 cladatum =
1191 (class_datum_t *) hashtab_search(policydb.
1192 p_classes.
1193 table,
1194 ans);
1195 if (!cladatum) {
1196 printf("\nNo such class\n");
1197 break;
1198 }
1199 tclass = cladatum->s.value;
1200 }
1201
1202 flags = SHOW_GRANTED;
1203 if (sepol_compute_av_reason_buffer(ssid, tsid,
1204 tclass, 0, &avd, &reason,
1205 &reason_buf, flags)) {
1206 printf("\nconstraint error\n");
1207 break;
1208 }
1209 if (reason_buf) {
1210 printf("\nConstraint expressions:\n%s",
1211 reason_buf);
1212 free(reason_buf);
1213 } else {
1214 printf("\nNo constraints found.\n");
1215 }
1216 break;
1217 case 'j':
1218 printf("old sid? ");
1219 FGETS(ans, sizeof(ans), stdin);
1220 oldsid = atoi(ans);
1221
1222 printf("new sid? ");
1223 FGETS(ans, sizeof(ans), stdin);
1224 newsid = atoi(ans);
1225
1226 printf("task sid? ");
1227 FGETS(ans, sizeof(ans), stdin);
1228 tasksid = atoi(ans);
1229
1230 printf("target class? ");
1231 FGETS(ans, sizeof(ans), stdin);
1232 if (isdigit(ans[0])) {
1233 tclass = atoi(ans);
1234 if (!tclass
1235 || tclass > policydb.p_classes.nprim) {
1236 printf("\nNo such class.\n");
1237 break;
1238 }
1239 } else {
1240 ans[strlen(ans) - 1] = 0;
1241 cladatum =
1242 (class_datum_t *) hashtab_search(policydb.
1243 p_classes.
1244 table,
1245 ans);
1246 if (!cladatum) {
1247 printf("\nNo such class\n");
1248 break;
1249 }
1250 tclass = cladatum->s.value;
1251 }
1252
1253 flags = SHOW_GRANTED;
1254 if (sepol_validate_transition_reason_buffer(oldsid,
1255 newsid, tasksid, tclass,
1256 &reason_buf, flags)) {
1257 printf("\nvalidatetrans error\n");
1258 break;
1259 }
1260 if (reason_buf) {
1261 printf("\nValidatetrans expressions:\n%s",
1262 reason_buf);
1263 free(reason_buf);
1264 } else {
1265 printf(
1266 "\nNo validatetrans expressions found.\n");
1267 }
1268 break;
1269 case 'k':
1270 {
1271 char *p;
1272 struct in6_addr addr6;
1273 uint64_t subnet_prefix;
1274 unsigned int pkey;
1275
1276 printf("subnet prefix? ");
1277 FGETS(ans, sizeof(ans), stdin);
1278 ans[strlen(ans) - 1] = 0;
1279 p = (char *)&addr6;
1280
1281 if (inet_pton(AF_INET6, ans, p) < 1) {
1282 printf("error parsing subnet prefix\n");
1283 break;
1284 }
1285
1286 memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
1287 printf("pkey? ");
1288 FGETS(ans, sizeof(ans), stdin);
1289 pkey = atoi(ans);
1290 sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
1291 printf("sid %d\n", ssid);
1292 }
1293 break;
1294 case 'l':
1295 printf("device name (eg. mlx4_0)? ");
1296 FGETS(ans, sizeof(ans), stdin);
1297 ans[strlen(ans) - 1] = 0;
1298
1299 name = malloc((strlen(ans) + 1) * sizeof(char));
1300 if (!name) {
1301 fprintf(stderr, "couldn't malloc string.\n");
1302 break;
1303 }
1304 strcpy(name, ans);
1305
1306 printf("port? ");
1307 FGETS(ans, sizeof(ans), stdin);
1308 port = atoi(ans);
1309 sepol_ibendport_sid(name, port, &ssid);
1310 printf("sid %d\n", ssid);
1311 free(name);
1312 break;
1313 #ifdef EQUIVTYPES
1314 case 'z':
1315 identify_equiv_types();
1316 break;
1317 #endif
1318 case 'm':
1319 goto menu;
1320 case 'q':
1321 exit(0);
1322 break;
1323 default:
1324 printf("\nUnknown option %s.\n", ans);
1325 }
1326 }
1327
1328 return 0;
1329 }
1330
1331 /* FLASK */
1332