blob: e0a00f7c27767951a1273d8196323037b126e75a [file] [log] [blame]
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001
2/*
Stephen Smalley53bb2a12017-08-17 14:16:06 -04003 * Author : Stephen Smalley, <sds@tycho.nsa.gov>
Joshua Brindle13cd4c82008-08-19 15:30:36 -04004 */
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 *
Daniel Jurgens9fbb3112017-05-22 16:08:24 +030025 * Copyright (C) 2017 Mellanox Technologies Inc.
Joshua Brindle13cd4c82008-08-19 15:30:36 -040026 * 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
Nicolas Iooss61f760b2017-01-08 19:45:52 +010061#include <ctype.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040062#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>
Richard Hainesaac93602016-04-24 10:34:47 +010069#ifndef IPPROTO_DCCP
70#define IPPROTO_DCCP 33
71#endif
Richard Haines via Selinuxcf0ab122018-03-11 16:22:55 +000072#ifndef IPPROTO_SCTP
73#define IPPROTO_SCTP 132
74#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -040075#include <arpa/inet.h>
76#include <fcntl.h>
77#include <stdio.h>
78#include <errno.h>
79#include <sys/mman.h>
80
James Carterb1d94562015-04-01 10:05:04 -040081#include <sepol/module_to_cil.h>
James Carter13c27d62017-03-21 16:00:30 -040082#include <sepol/kernel_to_cil.h>
83#include <sepol/kernel_to_conf.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -040084#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/flask.h>
89#include <sepol/policydb/expand.h>
90#include <sepol/policydb/link.h>
91
92#include "queue.h"
93#include "checkpolicy.h"
94#include "parse_util.h"
95
96extern char *optarg;
97extern int optind;
98
99static policydb_t policydb;
100static sidtab_t sidtab;
101
102extern policydb_t *policydbp;
103extern int mlspol;
104
105static int handle_unknown = SEPOL_DENY_UNKNOWN;
Nicolas Iooss7dcb7a52014-09-14 23:41:46 +0200106static const char *txtfile = "policy.conf";
107static const char *binfile = "policy";
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400108
109unsigned int policyvers = POLICYDB_VERSION_MAX;
110
Nicolas Ioossef61dd72017-03-05 18:13:01 +0100111static __attribute__((__noreturn__)) void usage(const char *progname)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400112{
113 printf
James Carter9077c5c2018-10-11 08:35:43 -0400114 ("usage: %s [-b[F]] [-C] [-d] [-U handle_unknown (allow,deny,reject)] [-M] "
115 "[-c policyvers (%d-%d)] [-o output_file] [-S] "
Vit Mojzis3cad4742019-02-07 11:25:45 +0100116 "[-t target_platform (selinux,xen)] [-V] [input_file]\n",
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400117 progname, POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX);
118 exit(1);
119}
120
121#define FGETS(out, size, in) \
122if (fgets(out,size,in)==NULL) { \
123 fprintf(stderr, "fgets failed at line %d: %s\n", __LINE__,\
124 strerror(errno)); \
125 exit(1);\
126}
127static int print_sid(sepol_security_id_t sid,
128 context_struct_t * context
129 __attribute__ ((unused)), void *data
130 __attribute__ ((unused)))
131{
132 sepol_security_context_t scontext;
133 size_t scontext_len;
134 int rc;
135
136 rc = sepol_sid_to_context(sid, &scontext, &scontext_len);
137 if (rc)
138 printf("sid %d -> error %d\n", sid, rc);
139 else {
140 printf("sid %d -> scontext %s\n", sid, scontext);
141 free(scontext);
142 }
143 return 0;
144}
145
146struct val_to_name {
147 unsigned int val;
148 char *name;
149};
150
151static int find_perm(hashtab_key_t key, hashtab_datum_t datum, void *p)
152{
153 struct val_to_name *v = p;
154 perm_datum_t *perdatum;
155
156 perdatum = (perm_datum_t *) datum;
157
158 if (v->val == perdatum->s.value) {
159 v->name = key;
160 return 1;
161 }
162
163 return 0;
164}
165
166#ifdef EQUIVTYPES
167static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
168 struct avtab_node *type_rules)
169{
170 struct avtab_node *p, *c, *n;
171
172 for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
173 /*
174 * Find the insertion point, keeping the list
175 * ordered by source type, then target type, then
176 * target class.
177 */
178 if (k->source_type < c->key.source_type)
179 break;
180 if (k->source_type == c->key.source_type &&
181 k->target_type < c->key.target_type)
182 break;
183 if (k->source_type == c->key.source_type &&
184 k->target_type == c->key.target_type &&
185 k->target_class < c->key.target_class)
186 break;
187 }
188
189 /* Insert the rule */
190 n = malloc(sizeof(struct avtab_node));
191 if (!n) {
192 fprintf(stderr, "out of memory\n");
193 exit(1);
194 }
195
196 n->key = *k;
197 n->datum = *d;
198 n->next = p->next;
199 p->next = n;
200 return 0;
201}
202
203static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
204{
205 struct avtab_node *type_rules = args;
206
207 if (d->specified & AVTAB_ALLOWED) {
208 /*
209 * Insert the rule into the lists for both
210 * the source type and the target type.
211 */
212 if (insert_type_rule(k, d, &type_rules[k->source_type - 1]))
213 return -1;
214 if (insert_type_rule(k, d, &type_rules[k->target_type - 1]))
215 return -1;
216 }
217
218 return 0;
219}
220
221static void free_type_rules(struct avtab_node *l)
222{
223 struct avtab_node *tmp;
224
225 while (l) {
226 tmp = l;
227 l = l->next;
228 free(tmp);
229 }
230}
231
232static int identify_equiv_types(void)
233{
234 struct avtab_node *type_rules, *l1, *l2;
235 int i, j;
236
237 /*
238 * Create a list of access vector rules for each type
239 * from the access vector table.
240 */
241 type_rules = malloc(sizeof(struct avtab_node) * policydb.p_types.nprim);
242 if (!type_rules) {
243 fprintf(stderr, "out of memory\n");
244 exit(1);
245 }
246 memset(type_rules, 0,
247 sizeof(struct avtab_node) * policydb.p_types.nprim);
248 if (avtab_map(&policydb.te_avtab, create_type_rules, type_rules))
249 exit(1);
250
251 /*
252 * Compare the type lists and identify equivalent types.
253 */
254 for (i = 0; i < policydb.p_types.nprim - 1; i++) {
255 if (!type_rules[i].next)
256 continue;
257 for (j = i + 1; j < policydb.p_types.nprim; j++) {
258 for (l1 = type_rules[i].next, l2 = type_rules[j].next;
259 l1 && l2; l1 = l1->next, l2 = l2->next) {
260 if (l2->key.source_type == (j + 1)) {
261 if (l1->key.source_type != (i + 1))
262 break;
263 } else {
264 if (l1->key.source_type !=
265 l2->key.source_type)
266 break;
267 }
268 if (l2->key.target_type == (j + 1)) {
269 if (l1->key.target_type != (i + 1))
270 break;
271 } else {
272 if (l1->key.target_type !=
273 l2->key.target_type)
274 break;
275 }
276 if (l1->key.target_class != l2->key.target_class
277 || l1->datum.allowed != l2->datum.allowed)
278 break;
279 }
280 if (l1 || l2)
281 continue;
282 free_type_rules(type_rules[j].next);
283 type_rules[j].next = NULL;
284 printf("Types %s and %s are equivalent.\n",
285 policydb.p_type_val_to_name[i],
286 policydb.p_type_val_to_name[j]);
287 }
288 free_type_rules(type_rules[i].next);
289 type_rules[i].next = NULL;
290 }
291
292 free(type_rules);
293 return 0;
294}
295#endif
296
297extern char *av_to_string(uint32_t tclass, sepol_access_vector_t av);
298
Nicolas Ioossc4a4a1a2014-09-14 23:41:49 +0200299int display_bools(void)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400300{
Nicolas Iooss581d3eb2014-09-14 23:41:41 +0200301 uint32_t i;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400302
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
310void display_expr(cond_expr_t * exp)
311{
312
313 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->bool - 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
Nicolas Ioossc4a4a1a2014-09-14 23:41:49 +0200345int display_cond_expressions(void)
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400346{
347 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
357int change_bool(char *name, int state)
358{
359 cond_bool_datum_t *bool;
360
361 bool = hashtab_search(policydbp->p_bools.table, name);
362 if (bool == NULL) {
363 printf("Could not find bool %s\n", name);
364 return -1;
365 }
366 bool->state = state;
367 evaluate_conds(policydbp);
368 return 0;
369}
370
Nicolas Iooss5af8c5a2014-09-14 23:41:50 +0200371static int check_level(hashtab_key_t key, hashtab_datum_t datum, void *arg __attribute__ ((unused)))
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400372{
373 level_datum_t *levdatum = (level_datum_t *) datum;
374
375 if (!levdatum->isalias && !levdatum->defined) {
376 fprintf(stderr,
377 "Error: sensitivity %s was not used in a level definition!\n",
378 key);
379 return -1;
380 }
381 return 0;
382}
383
384int main(int argc, char **argv)
385{
James Carterb1d94562015-04-01 10:05:04 -0400386 policydb_t parse_policy;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400387 sepol_security_class_t tclass;
Richard Hainesab9cbb12013-11-03 19:12:29 +0000388 sepol_security_id_t ssid, tsid, *sids, oldsid, newsid, tasksid;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400389 sepol_security_context_t scontext;
390 struct sepol_av_decision avd;
391 class_datum_t *cladatum;
Nicolas Iooss7dcb7a52014-09-14 23:41:46 +0200392 const char *file = txtfile;
393 char ans[80 + 1], *outfile = NULL, *path, *fstype;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400394 size_t scontext_len, pathlen;
395 unsigned int i;
396 unsigned int protocol, port;
James Carter9077c5c2018-10-11 08:35:43 -0400397 unsigned int binary = 0, debug = 0, sort = 0, cil = 0, conf = 0;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400398 struct val_to_name v;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400399 int ret, ch, fd, target = SEPOL_TARGET_SELINUX;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400400 unsigned int nel, uret;
401 struct stat sb;
402 void *map;
403 FILE *outfp = NULL;
404 char *name;
405 int state;
406 int show_version = 0;
Richard Hainesab9cbb12013-11-03 19:12:29 +0000407 char *reason_buf = NULL;
408 unsigned int reason;
409 int flags;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400410 struct policy_file pf;
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100411 struct option long_options[] = {
412 {"output", required_argument, NULL, 'o'},
413 {"target", required_argument, NULL, 't'},
414 {"binary", no_argument, NULL, 'b'},
415 {"debug", no_argument, NULL, 'd'},
416 {"version", no_argument, NULL, 'V'},
Laurent Bigonvillef6a03f12013-07-06 14:32:33 +0200417 {"handle-unknown", required_argument, NULL, 'U'},
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100418 {"mls", no_argument, NULL, 'M'},
James Carterb1d94562015-04-01 10:05:04 -0400419 {"cil", no_argument, NULL, 'C'},
James Carter13c27d62017-03-21 16:00:30 -0400420 {"conf",no_argument, NULL, 'F'},
James Carter9077c5c2018-10-11 08:35:43 -0400421 {"sort", no_argument, NULL, 'S'},
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100422 {"help", no_argument, NULL, 'h'},
423 {NULL, 0, NULL, 0}
424 };
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400425
James Carter9077c5c2018-10-11 08:35:43 -0400426 while ((ch = getopt_long(argc, argv, "o:t:dbU:MCFSVc:h", long_options, NULL)) != -1) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400427 switch (ch) {
428 case 'o':
429 outfile = optarg;
430 break;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400431 case 't':
432 if (!strcasecmp(optarg, "Xen"))
433 target = SEPOL_TARGET_XEN;
434 else if (!strcasecmp(optarg, "SELinux"))
435 target = SEPOL_TARGET_SELINUX;
436 else{
437 fprintf(stderr, "%s: Unknown target platform:"
438 "%s\n", argv[0], optarg);
439 exit(1);
440 }
441 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400442 case 'b':
443 binary = 1;
444 file = binfile;
445 break;
446 case 'd':
447 debug = 1;
448 break;
449 case 'V':
450 show_version = 1;
451 break;
452 case 'U':
453 if (!strcasecmp(optarg, "deny")) {
454 handle_unknown = DENY_UNKNOWN;
455 break;
456 }
457 if (!strcasecmp(optarg, "allow")) {
458 handle_unknown = ALLOW_UNKNOWN;
459 break;
460 }
461 if (!strcasecmp(optarg, "reject")) {
462 handle_unknown = REJECT_UNKNOWN;
463 break;
464 }
465 usage(argv[0]);
James Carter9077c5c2018-10-11 08:35:43 -0400466 case 'S':
467 sort = 1;
468 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400469 case 'M':
470 mlspol = 1;
471 break;
James Carterb1d94562015-04-01 10:05:04 -0400472 case 'C':
473 cil = 1;
474 break;
James Carter13c27d62017-03-21 16:00:30 -0400475 case 'F':
476 conf = 1;
477 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400478 case 'c':{
Dan Albertb1bbd302014-12-10 11:28:44 -0800479 long int n;
480 errno = 0;
481 n = strtol(optarg, NULL, 10);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400482 if (errno) {
483 fprintf(stderr,
484 "Invalid policyvers specified: %s\n",
485 optarg);
486 usage(argv[0]);
487 exit(1);
488 }
489 if (n < POLICYDB_VERSION_MIN
490 || n > POLICYDB_VERSION_MAX) {
491 fprintf(stderr,
492 "policyvers value %ld not in range %d-%d\n",
493 n, POLICYDB_VERSION_MIN,
494 POLICYDB_VERSION_MAX);
495 usage(argv[0]);
496 exit(1);
497 }
498 if (policyvers != n)
499 policyvers = n;
500 break;
501 }
Guido Trentalanciabf57d232009-11-02 18:14:28 +0100502 case 'h':
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400503 default:
504 usage(argv[0]);
505 }
506 }
507
508 if (show_version) {
509 printf("%d (compatibility range %d-%d)\n", policyvers,
510 POLICYDB_VERSION_MAX, POLICYDB_VERSION_MIN);
511 exit(0);
512 }
513
514 if (optind != argc) {
515 file = argv[optind++];
516 if (optind != argc)
517 usage(argv[0]);
518 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400519 /* Set policydb and sidtab used by libsepol service functions
520 to my structures, so that I can directly populate and
521 manipulate them. */
522 sepol_set_policydb(&policydb);
523 sepol_set_sidtab(&sidtab);
524
James Carter13c27d62017-03-21 16:00:30 -0400525 if (cil && conf) {
526 fprintf(stderr, "Can't convert to CIL and policy.conf at the same time\n");
527 exit(1);
528 }
529
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400530 if (binary) {
531 fd = open(file, O_RDONLY);
532 if (fd < 0) {
533 fprintf(stderr, "Can't open '%s': %s\n",
534 file, strerror(errno));
535 exit(1);
536 }
537 if (fstat(fd, &sb) < 0) {
538 fprintf(stderr, "Can't stat '%s': %s\n",
539 file, strerror(errno));
540 exit(1);
541 }
542 map =
543 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
544 fd, 0);
545 if (map == MAP_FAILED) {
546 fprintf(stderr, "Can't map '%s': %s\n",
547 file, strerror(errno));
548 exit(1);
549 }
550 policy_file_init(&pf);
551 pf.type = PF_USE_MEMORY;
552 pf.data = map;
553 pf.len = sb.st_size;
554 if (policydb_init(&policydb)) {
555 fprintf(stderr, "%s: policydb_init: Out of memory!\n",
556 argv[0]);
557 exit(1);
558 }
559 ret = policydb_read(&policydb, &pf, 1);
560 if (ret) {
561 fprintf(stderr,
562 "%s: error(s) encountered while parsing configuration\n",
563 argv[0]);
564 exit(1);
565 }
566 policydbp = &policydb;
567
568 /* Check Policy Consistency */
569 if (policydbp->mls) {
570 if (!mlspol) {
571 fprintf(stderr, "%s: MLS policy, but non-MLS"
572 " is specified\n", argv[0]);
573 exit(1);
574 }
575 } else {
576 if (mlspol) {
577 fprintf(stderr, "%s: non-MLS policy, but MLS"
578 " is specified\n", argv[0]);
579 exit(1);
580 }
581 }
582 } else {
James Carter13c27d62017-03-21 16:00:30 -0400583 if (conf) {
584 fprintf(stderr, "Can only generate policy.conf from binary policy\n");
585 exit(1);
586 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400587 if (policydb_init(&parse_policy))
588 exit(1);
589 /* We build this as a base policy first since that is all the parser understands */
590 parse_policy.policy_type = POLICY_BASE;
Paul Nuzzi79d10a82009-09-29 10:06:26 -0400591 policydb_set_target_platform(&parse_policy, target);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400592
593 /* Let sepol know if we are dealing with MLS support */
594 parse_policy.mls = mlspol;
595 parse_policy.handle_unknown = handle_unknown;
596
597 policydbp = &parse_policy;
598
599 if (read_source_policy(policydbp, file, "checkpolicy") < 0)
600 exit(1);
601
602 if (hashtab_map(policydbp->p_levels.table, check_level, NULL))
603 exit(1);
604
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400605 /* Linking takes care of optional avrule blocks */
James Carterb1d94562015-04-01 10:05:04 -0400606 if (link_modules(NULL, policydbp, NULL, 0, 0)) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400607 fprintf(stderr, "Error while resolving optionals\n");
608 exit(1);
609 }
610
James Carterb1d94562015-04-01 10:05:04 -0400611 if (!cil) {
612 if (policydb_init(&policydb)) {
613 fprintf(stderr, "%s: policydb_init failed\n", argv[0]);
614 exit(1);
615 }
616 if (expand_module(NULL, policydbp, &policydb, 0, 1)) {
617 fprintf(stderr, "Error while expanding policy\n");
618 exit(1);
619 }
620 policydb_destroy(policydbp);
621 policydbp = &policydb;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400622 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400623 }
624
625 if (policydb_load_isids(&policydb, &sidtab))
626 exit(1);
627
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400628 if (outfile) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400629 outfp = fopen(outfile, "w");
630 if (!outfp) {
631 perror(outfile);
632 exit(1);
633 }
634
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400635 policydb.policyvers = policyvers;
636
James Carterb1d94562015-04-01 10:05:04 -0400637 if (!cil) {
James Carter13c27d62017-03-21 16:00:30 -0400638 if (!conf) {
James Carter13c27d62017-03-21 16:00:30 -0400639 policydb.policy_type = POLICY_KERN;
640
641 policy_file_init(&pf);
642 pf.type = PF_USE_STDIO;
643 pf.fp = outfp;
James Carter9077c5c2018-10-11 08:35:43 -0400644 if (sort) {
645 ret = policydb_sort_ocontexts(&policydb);
646 if (ret) {
647 fprintf(stderr, "%s: error sorting ocontexts\n",
648 argv[0]);
649 exit(1);
650 }
651 }
James Carter13c27d62017-03-21 16:00:30 -0400652 ret = policydb_write(&policydb, &pf);
653 } else {
James Carter13c27d62017-03-21 16:00:30 -0400654 ret = sepol_kernel_policydb_to_conf(outfp, policydbp);
655 }
James Carterb1d94562015-04-01 10:05:04 -0400656 if (ret) {
657 fprintf(stderr, "%s: error writing %s\n",
658 argv[0], outfile);
659 exit(1);
660 }
661 } else {
James Carter13c27d62017-03-21 16:00:30 -0400662 if (binary) {
663 ret = sepol_kernel_policydb_to_cil(outfp, policydbp);
664 } else {
665 ret = sepol_module_policydb_to_cil(outfp, policydbp, 1);
666 }
James Carterb1d94562015-04-01 10:05:04 -0400667 if (ret) {
668 fprintf(stderr, "%s: error writing %s\n", argv[0], outfile);
669 exit(1);
670 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400671 }
James Carterb1d94562015-04-01 10:05:04 -0400672
673 if (outfile) {
674 fclose(outfp);
675 }
676 } else if (cil) {
677 fprintf(stderr, "%s: No file to write CIL was specified\n", argv[0]);
678 exit(1);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400679 }
James Carterb1d94562015-04-01 10:05:04 -0400680
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400681 if (!debug) {
682 policydb_destroy(&policydb);
James Carterdd11ab62017-03-17 15:58:29 -0400683 sepol_sidtab_destroy(&sidtab);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400684 exit(0);
685 }
686
687 menu:
688 printf("\nSelect an option:\n");
689 printf("0) Call compute_access_vector\n");
690 printf("1) Call sid_to_context\n");
691 printf("2) Call context_to_sid\n");
692 printf("3) Call transition_sid\n");
693 printf("4) Call member_sid\n");
694 printf("5) Call change_sid\n");
695 printf("6) Call list_sids\n");
696 printf("7) Call load_policy\n");
697 printf("8) Call fs_sid\n");
698 printf("9) Call port_sid\n");
699 printf("a) Call netif_sid\n");
700 printf("b) Call node_sid\n");
701 printf("c) Call fs_use\n");
702 printf("d) Call genfs_sid\n");
703 printf("e) Call get_user_sids\n");
704 printf("f) display conditional bools\n");
705 printf("g) display conditional expressions\n");
706 printf("h) change a boolean value\n");
Richard Hainesab9cbb12013-11-03 19:12:29 +0000707 printf("i) display constraint expressions\n");
708 printf("j) display validatetrans expressions\n");
Daniel Jurgens9fbb3112017-05-22 16:08:24 +0300709 printf("k) Call ibpkey_sid\n");
Daniel Jurgens118c0cd2017-05-22 16:08:27 +0300710 printf("l) Call ibendport_sid\n");
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400711#ifdef EQUIVTYPES
712 printf("z) Show equivalent types\n");
713#endif
714 printf("m) Show menu again\n");
715 printf("q) Exit\n");
716 while (1) {
717 printf("\nChoose: ");
718 FGETS(ans, sizeof(ans), stdin);
719 switch (ans[0]) {
720 case '0':
721 printf("source sid? ");
722 FGETS(ans, sizeof(ans), stdin);
723 ssid = atoi(ans);
724
725 printf("target sid? ");
726 FGETS(ans, sizeof(ans), stdin);
727 tsid = atoi(ans);
728
729 printf("target class? ");
730 FGETS(ans, sizeof(ans), stdin);
731 if (isdigit(ans[0])) {
732 tclass = atoi(ans);
733 if (!tclass
734 || tclass > policydb.p_classes.nprim) {
735 printf("\nNo such class.\n");
736 break;
737 }
738 cladatum =
739 policydb.class_val_to_struct[tclass - 1];
740 } else {
741 ans[strlen(ans) - 1] = 0;
742 cladatum =
743 (class_datum_t *) hashtab_search(policydb.
744 p_classes.
745 table,
746 ans);
747 if (!cladatum) {
748 printf("\nNo such class\n");
749 break;
750 }
751 tclass = cladatum->s.value;
752 }
753
754 if (!cladatum->comdatum && !cladatum->permissions.nprim) {
755 printf
756 ("\nNo access vector definition for that class\n");
757 break;
758 }
759 ret = sepol_compute_av(ssid, tsid, tclass, 0, &avd);
760 switch (ret) {
761 case 0:
762 printf("\nallowed {");
763 for (i = 1; i <= sizeof(avd.allowed) * 8; i++) {
764 if (avd.allowed & (1 << (i - 1))) {
765 v.val = i;
766 ret =
767 hashtab_map(cladatum->
768 permissions.
769 table,
770 find_perm, &v);
771 if (!ret && cladatum->comdatum) {
772 ret =
773 hashtab_map
774 (cladatum->
775 comdatum->
776 permissions.table,
777 find_perm, &v);
778 }
779 if (ret)
780 printf(" %s", v.name);
781 }
782 }
783 printf(" }\n");
784 break;
785 case -EINVAL:
786 printf("\ninvalid sid\n");
787 break;
788 default:
789 printf("return code 0x%x\n", ret);
790 }
791 break;
792 case '1':
793 printf("sid? ");
794 FGETS(ans, sizeof(ans), stdin);
795 ssid = atoi(ans);
796 ret = sepol_sid_to_context(ssid,
797 &scontext, &scontext_len);
798 switch (ret) {
799 case 0:
800 printf("\nscontext %s\n", scontext);
801 free(scontext);
802 break;
803 case -EINVAL:
804 printf("\ninvalid sid\n");
805 break;
806 case -ENOMEM:
807 printf("\nout of memory\n");
808 break;
809 default:
810 printf("return code 0x%x\n", ret);
811 }
812 break;
813 case '2':
814 printf("scontext? ");
815 FGETS(ans, sizeof(ans), stdin);
816 scontext_len = strlen(ans);
817 ans[scontext_len - 1] = 0;
818 ret = sepol_context_to_sid(ans, scontext_len, &ssid);
819 switch (ret) {
820 case 0:
821 printf("\nsid %d\n", ssid);
822 break;
823 case -EINVAL:
824 printf("\ninvalid context\n");
825 break;
826 case -ENOMEM:
827 printf("\nout of memory\n");
828 break;
829 default:
830 printf("return code 0x%x\n", ret);
831 }
832 break;
833 case '3':
834 case '4':
835 case '5':
836 ch = ans[0];
837
838 printf("source sid? ");
839 FGETS(ans, sizeof(ans), stdin);
840 ssid = atoi(ans);
841 printf("target sid? ");
842 FGETS(ans, sizeof(ans), stdin);
843 tsid = atoi(ans);
844
845 printf("object class? ");
846 FGETS(ans, sizeof(ans), stdin);
847 if (isdigit(ans[0])) {
848 tclass = atoi(ans);
849 if (!tclass
850 || tclass > policydb.p_classes.nprim) {
851 printf("\nNo such class.\n");
852 break;
853 }
854 } else {
855 ans[strlen(ans) - 1] = 0;
856 cladatum =
857 (class_datum_t *) hashtab_search(policydb.
858 p_classes.
859 table,
860 ans);
861 if (!cladatum) {
862 printf("\nNo such class\n");
863 break;
864 }
865 tclass = cladatum->s.value;
866 }
867
868 if (ch == '3')
869 ret =
870 sepol_transition_sid(ssid, tsid, tclass,
871 &ssid);
872 else if (ch == '4')
873 ret =
874 sepol_member_sid(ssid, tsid, tclass, &ssid);
875 else
876 ret =
877 sepol_change_sid(ssid, tsid, tclass, &ssid);
878 switch (ret) {
879 case 0:
880 printf("\nsid %d\n", ssid);
881 break;
882 case -EINVAL:
883 printf("\ninvalid sid\n");
884 break;
885 case -ENOMEM:
886 printf("\nout of memory\n");
887 break;
888 default:
889 printf("return code 0x%x\n", ret);
890 }
891 break;
892 case '6':
893 sepol_sidtab_map(&sidtab, print_sid, 0);
894 break;
895 case '7':
896 printf("pathname? ");
897 FGETS(ans, sizeof(ans), stdin);
898 pathlen = strlen(ans);
899 ans[pathlen - 1] = 0;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400900 fd = open(ans, O_RDONLY);
901 if (fd < 0) {
902 fprintf(stderr, "Can't open '%s': %s\n",
903 ans, strerror(errno));
904 break;
905 }
906 if (fstat(fd, &sb) < 0) {
907 fprintf(stderr, "Can't stat '%s': %s\n",
908 ans, strerror(errno));
909 break;
910 }
911 map =
912 mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE,
913 MAP_PRIVATE, fd, 0);
914 if (map == MAP_FAILED) {
915 fprintf(stderr, "Can't map '%s': %s\n",
916 ans, strerror(errno));
917 break;
918 }
919 ret = sepol_load_policy(map, sb.st_size);
920 switch (ret) {
921 case 0:
922 printf("\nsuccess\n");
923 break;
924 case -EINVAL:
925 printf("\ninvalid policy\n");
926 break;
927 case -ENOMEM:
928 printf("\nout of memory\n");
929 break;
930 default:
931 printf("return code 0x%x\n", ret);
932 }
933 break;
934 case '8':
935 printf("fs kdevname? ");
936 FGETS(ans, sizeof(ans), stdin);
937 ans[strlen(ans) - 1] = 0;
938 sepol_fs_sid(ans, &ssid, &tsid);
939 printf("fs_sid %d default_file_sid %d\n", ssid, tsid);
940 break;
941 case '9':
942 printf("protocol? ");
943 FGETS(ans, sizeof(ans), stdin);
944 ans[strlen(ans) - 1] = 0;
945 if (!strcmp(ans, "tcp") || !strcmp(ans, "TCP"))
946 protocol = IPPROTO_TCP;
947 else if (!strcmp(ans, "udp") || !strcmp(ans, "UDP"))
948 protocol = IPPROTO_UDP;
Richard Haines3895fbb2016-04-06 12:44:35 +0100949 else if (!strcmp(ans, "dccp") || !strcmp(ans, "DCCP"))
950 protocol = IPPROTO_DCCP;
Richard Haines via Selinuxcf0ab122018-03-11 16:22:55 +0000951 else if (!strcmp(ans, "sctp") || !strcmp(ans, "SCTP"))
952 protocol = IPPROTO_SCTP;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400953 else {
954 printf("unknown protocol\n");
955 break;
956 }
957 printf("port? ");
958 FGETS(ans, sizeof(ans), stdin);
959 port = atoi(ans);
960 sepol_port_sid(0, 0, protocol, port, &ssid);
961 printf("sid %d\n", ssid);
962 break;
963 case 'a':
964 printf("netif name? ");
965 FGETS(ans, sizeof(ans), stdin);
966 ans[strlen(ans) - 1] = 0;
967 sepol_netif_sid(ans, &ssid, &tsid);
968 printf("if_sid %d default_msg_sid %d\n", ssid, tsid);
969 break;
970 case 'b':{
971 char *p;
972 int family, len;
973 struct in_addr addr4;
974 struct in6_addr addr6;
975
976 printf("protocol family? ");
977 FGETS(ans, sizeof(ans), stdin);
978 ans[strlen(ans) - 1] = 0;
979 if (!strcasecmp(ans, "ipv4"))
980 family = AF_INET;
981 else if (!strcasecmp(ans, "ipv6"))
982 family = AF_INET6;
983 else {
984 printf("unknown protocol family\n");
985 break;
986 }
987
988 printf("node address? ");
989 FGETS(ans, sizeof(ans), stdin);
990 ans[strlen(ans) - 1] = 0;
991
992 if (family == AF_INET) {
993 p = (char *)&addr4;
994 len = sizeof(addr4);
995 } else {
996 p = (char *)&addr6;
997 len = sizeof(addr6);
998 }
999
1000 if (inet_pton(family, ans, p) < 1) {
1001 printf("error parsing address\n");
1002 break;
1003 }
1004
1005 sepol_node_sid(family, p, len, &ssid);
1006 printf("sid %d\n", ssid);
1007 break;
1008 }
1009 case 'c':
1010 printf("fstype? ");
1011 FGETS(ans, sizeof(ans), stdin);
1012 ans[strlen(ans) - 1] = 0;
1013 sepol_fs_use(ans, &uret, &ssid);
1014 switch (uret) {
1015 case SECURITY_FS_USE_XATTR:
1016 printf("use xattr\n");
1017 break;
1018 case SECURITY_FS_USE_TRANS:
1019 printf("use transition SIDs\n");
1020 break;
1021 case SECURITY_FS_USE_TASK:
1022 printf("use task SIDs\n");
1023 break;
1024 case SECURITY_FS_USE_GENFS:
1025 printf("use genfs\n");
1026 break;
1027 case SECURITY_FS_USE_NONE:
1028 printf("no labeling support\n");
1029 break;
1030 }
1031 printf("sid %d\n", ssid);
1032 break;
1033 case 'd':
1034 printf("fstype? ");
1035 FGETS(ans, sizeof(ans), stdin);
1036 ans[strlen(ans) - 1] = 0;
1037 fstype = strdup(ans);
1038 printf("path? ");
1039 FGETS(ans, sizeof(ans), stdin);
1040 ans[strlen(ans) - 1] = 0;
1041 path = strdup(ans);
1042 printf("object class? ");
1043 FGETS(ans, sizeof(ans), stdin);
1044 if (isdigit(ans[0])) {
1045 tclass = atoi(ans);
1046 if (!tclass
1047 || tclass > policydb.p_classes.nprim) {
1048 printf("\nNo such class.\n");
1049 break;
1050 }
1051 } else {
1052 ans[strlen(ans) - 1] = 0;
1053 cladatum =
1054 (class_datum_t *) hashtab_search(policydb.
1055 p_classes.
1056 table,
1057 ans);
1058 if (!cladatum) {
1059 printf("\nNo such class\n");
1060 break;
1061 }
1062 tclass = cladatum->s.value;
1063 }
1064 sepol_genfs_sid(fstype, path, tclass, &ssid);
1065 printf("sid %d\n", ssid);
1066 free(fstype);
1067 free(path);
1068 break;
1069 case 'e':
1070 printf("from SID? ");
1071 FGETS(ans, sizeof(ans), stdin);
1072 ans[strlen(ans) - 1] = 0;
1073 ssid = atoi(ans);
1074
1075 printf("username? ");
1076 FGETS(ans, sizeof(ans), stdin);
1077 ans[strlen(ans) - 1] = 0;
1078
1079 ret = sepol_get_user_sids(ssid, ans, &sids, &nel);
1080 switch (ret) {
1081 case 0:
1082 if (!nel)
1083 printf("\nnone\n");
1084 for (i = 0; i < nel; i++)
1085 print_sid(sids[i], NULL, NULL);
1086 free(sids);
1087 break;
1088 case -ENOMEM:
1089 printf("\nout of memory\n");
1090 break;
1091 case -EINVAL:
1092 printf("\ninvalid argument\n");
1093 break;
1094 default:
1095 printf("\nerror\n");
1096 break;
1097 }
1098 break;
1099 case 'f':
1100 display_bools();
1101 break;
1102 case 'g':
1103 display_cond_expressions();
1104 break;
1105 case 'h':
1106 printf("name? ");
1107 FGETS(ans, sizeof(ans), stdin);
1108 ans[strlen(ans) - 1] = 0;
1109
1110 name = malloc((strlen(ans) + 1) * sizeof(char));
1111 if (name == NULL) {
1112 fprintf(stderr, "couldn't malloc string.\n");
1113 break;
1114 }
1115 strcpy(name, ans);
1116
1117 printf("state? ");
1118 FGETS(ans, sizeof(ans), stdin);
1119 ans[strlen(ans) - 1] = 0;
1120
1121 if (atoi(ans))
1122 state = 1;
1123 else
1124 state = 0;
1125
1126 change_bool(name, state);
1127 free(name);
1128 break;
Richard Hainesab9cbb12013-11-03 19:12:29 +00001129 case 'i':
1130 printf("source sid? ");
1131 FGETS(ans, sizeof(ans), stdin);
1132 ssid = atoi(ans);
1133
1134 printf("target sid? ");
1135 FGETS(ans, sizeof(ans), stdin);
1136 tsid = atoi(ans);
1137
1138 printf("target class? ");
1139 FGETS(ans, sizeof(ans), stdin);
1140 if (isdigit(ans[0])) {
1141 tclass = atoi(ans);
1142 if (!tclass
1143 || tclass > policydb.p_classes.nprim) {
1144 printf("\nNo such class.\n");
1145 break;
1146 }
1147 cladatum =
1148 policydb.class_val_to_struct[tclass - 1];
1149 } else {
1150 ans[strlen(ans) - 1] = 0;
1151 cladatum =
1152 (class_datum_t *) hashtab_search(policydb.
1153 p_classes.
1154 table,
1155 ans);
1156 if (!cladatum) {
1157 printf("\nNo such class\n");
1158 break;
1159 }
1160 tclass = cladatum->s.value;
1161 }
1162
1163 flags = SHOW_GRANTED;
1164 if (sepol_compute_av_reason_buffer(ssid, tsid,
1165 tclass, 0, &avd, &reason,
1166 &reason_buf, flags)) {
1167 printf("\nconstraint error\n");
1168 break;
1169 }
1170 if (reason_buf) {
1171 printf("\nConstraint expressions:\n%s",
1172 reason_buf);
1173 free(reason_buf);
1174 } else {
1175 printf("\nNo constraints found.\n");
1176 }
1177 break;
1178 case 'j':
1179 printf("old sid? ");
1180 FGETS(ans, sizeof(ans), stdin);
1181 oldsid = atoi(ans);
1182
1183 printf("new sid? ");
1184 FGETS(ans, sizeof(ans), stdin);
1185 newsid = atoi(ans);
1186
1187 printf("task sid? ");
1188 FGETS(ans, sizeof(ans), stdin);
1189 tasksid = atoi(ans);
1190
1191 printf("target class? ");
1192 FGETS(ans, sizeof(ans), stdin);
1193 if (isdigit(ans[0])) {
1194 tclass = atoi(ans);
1195 if (!tclass
1196 || tclass > policydb.p_classes.nprim) {
1197 printf("\nNo such class.\n");
1198 break;
1199 }
1200 cladatum =
1201 policydb.class_val_to_struct[tclass - 1];
1202 } else {
1203 ans[strlen(ans) - 1] = 0;
1204 cladatum =
1205 (class_datum_t *) hashtab_search(policydb.
1206 p_classes.
1207 table,
1208 ans);
1209 if (!cladatum) {
1210 printf("\nNo such class\n");
1211 break;
1212 }
1213 tclass = cladatum->s.value;
1214 }
1215
1216 flags = SHOW_GRANTED;
1217 if (sepol_validate_transition_reason_buffer(oldsid,
1218 newsid, tasksid, tclass,
1219 &reason_buf, flags)) {
1220 printf("\nvalidatetrans error\n");
1221 break;
1222 }
1223 if (reason_buf) {
1224 printf("\nValidatetrans expressions:\n%s",
1225 reason_buf);
1226 free(reason_buf);
1227 } else {
1228 printf(
1229 "\nNo validatetrans expressions found.\n");
1230 }
1231 break;
Daniel Jurgens9fbb3112017-05-22 16:08:24 +03001232 case 'k':
1233 {
1234 char *p;
1235 struct in6_addr addr6;
1236 uint64_t subnet_prefix;
1237 unsigned int pkey;
1238
1239 printf("subnet prefix? ");
1240 FGETS(ans, sizeof(ans), stdin);
1241 ans[strlen(ans) - 1] = 0;
1242 p = (char *)&addr6;
1243
1244 if (inet_pton(AF_INET6, ans, p) < 1) {
1245 printf("error parsing subnet prefix\n");
1246 break;
1247 }
1248
1249 memcpy(&subnet_prefix, p, sizeof(subnet_prefix));
1250 printf("pkey? ");
1251 FGETS(ans, sizeof(ans), stdin);
1252 pkey = atoi(ans);
1253 sepol_ibpkey_sid(subnet_prefix, pkey, &ssid);
1254 printf("sid %d\n", ssid);
1255 }
1256 break;
Daniel Jurgens118c0cd2017-05-22 16:08:27 +03001257 case 'l':
1258 printf("device name (eg. mlx4_0)? ");
1259 FGETS(ans, sizeof(ans), stdin);
1260 ans[strlen(ans) - 1] = 0;
1261
1262 name = malloc((strlen(ans) + 1) * sizeof(char));
1263 if (!name) {
1264 fprintf(stderr, "couldn't malloc string.\n");
1265 break;
1266 }
1267 strcpy(name, ans);
1268
1269 printf("port? ");
1270 FGETS(ans, sizeof(ans), stdin);
1271 port = atoi(ans);
1272 sepol_ibendport_sid(name, port, &ssid);
1273 printf("sid %d\n", ssid);
1274 free(name);
1275 break;
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001276#ifdef EQUIVTYPES
1277 case 'z':
1278 identify_equiv_types();
1279 break;
1280#endif
1281 case 'm':
1282 goto menu;
1283 case 'q':
1284 exit(0);
1285 break;
1286 default:
1287 printf("\nUnknown option %s.\n", ans);
1288 }
1289 }
1290
1291 return 0;
1292}
1293
1294/* FLASK */