Home | History | Annotate | Download | only in checkpolicy
      1 /*
      2  * Authors: Joshua Brindle <jbrindle (at) tresys.com>
      3  *	    Karl MacMillan <kmacmillan (at) tresys.com>
      4  *          Jason Tang     <jtang (at) tresys.com>
      5  *
      6  *
      7  * Copyright (C) 2004-5 Tresys Technology, LLC
      8  *	This program is free software; you can redistribute it and/or modify
      9  *  	it under the terms of the GNU General Public License as published by
     10  *	the Free Software Foundation, version 2.
     11  */
     12 
     13 #include <getopt.h>
     14 #include <unistd.h>
     15 #include <stdlib.h>
     16 #include <sys/types.h>
     17 #include <sys/stat.h>
     18 #include <fcntl.h>
     19 #include <stdio.h>
     20 #include <errno.h>
     21 #include <sys/mman.h>
     22 #include <libgen.h>
     23 
     24 #include <sepol/module_to_cil.h>
     25 #include <sepol/policydb/policydb.h>
     26 #include <sepol/policydb/services.h>
     27 #include <sepol/policydb/conditional.h>
     28 #include <sepol/policydb/flask.h>
     29 #include <sepol/policydb/hierarchy.h>
     30 #include <sepol/policydb/expand.h>
     31 #include <sepol/policydb/link.h>
     32 #include <sepol/policydb/sidtab.h>
     33 
     34 #include "queue.h"
     35 #include "checkpolicy.h"
     36 #include "parse_util.h"
     37 
     38 extern char *optarg;
     39 extern int optind;
     40 
     41 static sidtab_t sidtab;
     42 
     43 extern int mlspol;
     44 
     45 static int handle_unknown = SEPOL_DENY_UNKNOWN;
     46 static const char *txtfile = "policy.conf";
     47 static const char *binfile = "policy";
     48 
     49 unsigned int policy_type = POLICY_BASE;
     50 unsigned int policyvers = MOD_POLICYDB_VERSION_MAX;
     51 
     52 static int read_binary_policy(policydb_t * p, const char *file, const char *progname)
     53 {
     54 	int fd;
     55 	struct stat sb;
     56 	void *map;
     57 	struct policy_file f, *fp;
     58 
     59 	fd = open(file, O_RDONLY);
     60 	if (fd < 0) {
     61 		fprintf(stderr, "Can't open '%s':  %s\n",
     62 			file, strerror(errno));
     63 		return -1;
     64 	}
     65 	if (fstat(fd, &sb) < 0) {
     66 		fprintf(stderr, "Can't stat '%s':  %s\n",
     67 			file, strerror(errno));
     68 		close(fd);
     69 		return -1;
     70 	}
     71 	map =
     72 	    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
     73 	close(fd);
     74 	if (map == MAP_FAILED) {
     75 		fprintf(stderr, "Can't map '%s':  %s\n", file, strerror(errno));
     76 		return -1;
     77 	}
     78 	policy_file_init(&f);
     79 	f.type = PF_USE_MEMORY;
     80 	f.data = map;
     81 	f.len = sb.st_size;
     82 	fp = &f;
     83 
     84 	if (policydb_init(p)) {
     85 		fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
     86 			progname);
     87 		return -1;
     88 	}
     89 	if (policydb_read(p, fp, 1)) {
     90 		fprintf(stderr,
     91 			"%s:  error(s) encountered while parsing configuration\n",
     92 			progname);
     93 		return -1;
     94 	}
     95 
     96 	/* Check Policy Consistency */
     97 	if (p->mls) {
     98 		if (!mlspol) {
     99 			fprintf(stderr, "%s:  MLS policy, but non-MLS"
    100 				" is specified\n", progname);
    101 			return -1;
    102 		}
    103 	} else {
    104 		if (mlspol) {
    105 			fprintf(stderr, "%s:  non-MLS policy, but MLS"
    106 				" is specified\n", progname);
    107 			return -1;
    108 		}
    109 	}
    110 	return 0;
    111 }
    112 
    113 static int write_binary_policy(policydb_t * p, FILE *outfp)
    114 {
    115 	struct policy_file pf;
    116 
    117 	p->policy_type = policy_type;
    118 	p->policyvers = policyvers;
    119 	p->handle_unknown = handle_unknown;
    120 
    121 	policy_file_init(&pf);
    122 	pf.type = PF_USE_STDIO;
    123 	pf.fp = outfp;
    124 	return policydb_write(p, &pf);
    125 }
    126 
    127 static void usage(char *progname)
    128 {
    129 	printf("usage:  %s [-h] [-V] [-b] [-C] [-U handle_unknown] [-m] [-M] [-o FILE] [INPUT]\n", progname);
    130 	printf("Build base and policy modules.\n");
    131 	printf("Options:\n");
    132 	printf("  INPUT      build module from INPUT (else read from \"%s\")\n",
    133 	       txtfile);
    134 	printf("  -V         show policy versions created by this program\n");
    135 	printf("  -b         treat input as a binary policy file\n");
    136 	printf("  -C         output CIL policy instead of binary policy\n");
    137 	printf("  -h         print usage\n");
    138 	printf("  -U OPTION  How to handle unknown classes and permissions\n");
    139 	printf("               deny: Deny unknown kernel checks\n");
    140 	printf("               reject: Reject loading of policy with unknowns\n");
    141 	printf("               allow: Allow unknown kernel checks\n");
    142 	printf("  -m         build a policy module instead of a base module\n");
    143 	printf("  -M         enable MLS policy\n");
    144 	printf("  -o FILE    write module to FILE (else just check syntax)\n");
    145 	exit(1);
    146 }
    147 
    148 int main(int argc, char **argv)
    149 {
    150 	const char *file = txtfile, *outfile = NULL;
    151 	unsigned int binary = 0, cil = 0;
    152 	int ch;
    153 	int show_version = 0;
    154 	policydb_t modpolicydb;
    155 	struct option long_options[] = {
    156 		{"help", no_argument, NULL, 'h'},
    157 		{"output", required_argument, NULL, 'o'},
    158 		{"binary", no_argument, NULL, 'b'},
    159 		{"version", no_argument, NULL, 'V'},
    160 		{"handle-unknown", required_argument, NULL, 'U'},
    161 		{"mls", no_argument, NULL, 'M'},
    162 		{"cil", no_argument, NULL, 'C'},
    163 		{NULL, 0, NULL, 0}
    164 	};
    165 
    166 	while ((ch = getopt_long(argc, argv, "ho:bVU:mMC", long_options, NULL)) != -1) {
    167 		switch (ch) {
    168 		case 'h':
    169 			usage(argv[0]);
    170 			break;
    171 		case 'o':
    172 			outfile = optarg;
    173 			break;
    174 		case 'b':
    175 			binary = 1;
    176 			file = binfile;
    177 			break;
    178 		case 'V':
    179 			show_version = 1;
    180 			break;
    181 		case 'U':
    182 			if (!strcasecmp(optarg, "deny")) {
    183 				handle_unknown = DENY_UNKNOWN;
    184 				break;
    185 			}
    186 			if (!strcasecmp(optarg, "reject")) {
    187 				handle_unknown = REJECT_UNKNOWN;
    188 				break;
    189 			}
    190 			if (!strcasecmp(optarg, "allow")) {
    191 				handle_unknown = ALLOW_UNKNOWN;
    192 				break;
    193 			}
    194 			usage(argv[0]);
    195 		case 'm':
    196 			policy_type = POLICY_MOD;
    197 			policyvers = MOD_POLICYDB_VERSION_MAX;
    198 			break;
    199 		case 'M':
    200 			mlspol = 1;
    201 			break;
    202 		case 'C':
    203 			cil = 1;
    204 			break;
    205 		default:
    206 			usage(argv[0]);
    207 		}
    208 	}
    209 
    210 	if (show_version) {
    211 		printf("Module versions %d-%d\n",
    212 		       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
    213 		exit(0);
    214 	}
    215 
    216 	if (handle_unknown && (policy_type != POLICY_BASE)) {
    217 		fprintf(stderr, "%s:  Handling of unknown classes and permissions is only valid in the base module.\n", argv[0]);
    218 		exit(1);
    219 	}
    220 
    221 	if (binary && (policy_type != POLICY_BASE)) {
    222 		fprintf(stderr, "%s:  -b and -m are incompatible with each other.\n", argv[0]);
    223 		exit(1);
    224 	}
    225 
    226 	if (optind != argc) {
    227 		file = argv[optind++];
    228 		if (optind != argc)
    229 			usage(argv[0]);
    230 	}
    231 	printf("%s:  loading policy configuration from %s\n", argv[0], file);
    232 
    233 	/* Set policydb and sidtab used by libsepol service functions
    234 	   to my structures, so that I can directly populate and
    235 	   manipulate them. */
    236 	sepol_set_policydb(&modpolicydb);
    237 	sepol_set_sidtab(&sidtab);
    238 
    239 	if (binary) {
    240 		if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) {
    241 			exit(1);
    242 		}
    243 	} else {
    244 		if (policydb_init(&modpolicydb)) {
    245 			fprintf(stderr, "%s: out of memory!\n", argv[0]);
    246 			return -1;
    247 		}
    248 
    249 		modpolicydb.policy_type = policy_type;
    250 		modpolicydb.mls = mlspol;
    251 		modpolicydb.handle_unknown = handle_unknown;
    252 
    253 		if (read_source_policy(&modpolicydb, file, argv[0]) == -1) {
    254 			exit(1);
    255 		}
    256 
    257 		if (hierarchy_check_constraints(NULL, &modpolicydb)) {
    258 			return -1;
    259 		}
    260 	}
    261 
    262 	if (policy_type != POLICY_BASE && outfile) {
    263 		char *mod_name = modpolicydb.name;
    264 		char *out_path = strdup(outfile);
    265 		if (out_path == NULL) {
    266 			fprintf(stderr, "%s:  out of memory\n", argv[0]);
    267 			exit(1);
    268 		}
    269 		char *out_name = basename(out_path);
    270 		char *separator = strrchr(out_name, '.');
    271 		if (separator) {
    272 			*separator = '\0';
    273 		}
    274 		if (strcmp(mod_name, out_name) != 0) {
    275 			fprintf(stderr,	"%s:  Module name %s is different than the output base filename %s\n", argv[0], mod_name, out_name);
    276 			exit(1);
    277 		}
    278 		free(out_path);
    279 	}
    280 
    281 	if (modpolicydb.policy_type == POLICY_BASE && !cil) {
    282 		/* Verify that we can successfully expand the base module. */
    283 		policydb_t kernpolicydb;
    284 
    285 		if (policydb_init(&kernpolicydb)) {
    286 			fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
    287 			exit(1);
    288 		}
    289 		if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) {
    290 			fprintf(stderr, "%s:  link modules failed\n", argv[0]);
    291 			exit(1);
    292 		}
    293 		if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) {
    294 			fprintf(stderr, "%s:  expand module failed\n", argv[0]);
    295 			exit(1);
    296 		}
    297 		policydb_destroy(&kernpolicydb);
    298 	}
    299 
    300 	if (policydb_load_isids(&modpolicydb, &sidtab))
    301 		exit(1);
    302 
    303 	sepol_sidtab_destroy(&sidtab);
    304 
    305 	printf("%s:  policy configuration loaded\n", argv[0]);
    306 
    307 	if (outfile) {
    308 		FILE *outfp = fopen(outfile, "w");
    309 
    310 		if (!outfp) {
    311 			perror(outfile);
    312 			exit(1);
    313 		}
    314 
    315 		if (!cil) {
    316 			printf("%s:  writing binary representation (version %d) to %s\n",
    317 				   argv[0], policyvers, outfile);
    318 
    319 			if (write_binary_policy(&modpolicydb, outfp) != 0) {
    320 				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
    321 				exit(1);
    322 			}
    323 		} else {
    324 			printf("%s:  writing CIL to %s\n",argv[0], outfile);
    325 
    326 			if (sepol_module_policydb_to_cil(outfp, &modpolicydb, 0) != 0) {
    327 				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
    328 				exit(1);
    329 			}
    330 		}
    331 
    332 		fclose(outfp);
    333 	} else if (cil) {
    334 		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
    335 		exit(1);
    336 	}
    337 
    338 	policydb_destroy(&modpolicydb);
    339 
    340 	return 0;
    341 }
    342 
    343 /* FLASK */
    344