• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Authors: Joshua Brindle <jbrindle@tresys.com>
3  *	    Karl MacMillan <kmacmillan@tresys.com>
4  *          Jason Tang     <jtang@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 
read_binary_policy(policydb_t * p,const char * file,const char * progname)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 
write_binary_policy(policydb_t * p,FILE * outfp)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 
usage(const char * progname)127 static __attribute__((__noreturn__)) void usage(const 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 	printf("  -c VERSION build a policy module targeting a modular policy version (%d-%d)\n",
146 	       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
147 	exit(1);
148 }
149 
main(int argc,char ** argv)150 int main(int argc, char **argv)
151 {
152 	const char *file = txtfile, *outfile = NULL;
153 	unsigned int binary = 0, cil = 0;
154 	int ch;
155 	int show_version = 0;
156 	policydb_t modpolicydb;
157 	struct option long_options[] = {
158 		{"help", no_argument, NULL, 'h'},
159 		{"output", required_argument, NULL, 'o'},
160 		{"binary", no_argument, NULL, 'b'},
161 		{"version", no_argument, NULL, 'V'},
162 		{"handle-unknown", required_argument, NULL, 'U'},
163 		{"mls", no_argument, NULL, 'M'},
164 		{"cil", no_argument, NULL, 'C'},
165 		{NULL, 0, NULL, 0}
166 	};
167 
168 	while ((ch = getopt_long(argc, argv, "ho:bVU:mMCc:", long_options, NULL)) != -1) {
169 		switch (ch) {
170 		case 'h':
171 			usage(argv[0]);
172 			break;
173 		case 'o':
174 			outfile = optarg;
175 			break;
176 		case 'b':
177 			binary = 1;
178 			file = binfile;
179 			break;
180 		case 'V':
181 			show_version = 1;
182 			break;
183 		case 'U':
184 			if (!strcasecmp(optarg, "deny")) {
185 				handle_unknown = DENY_UNKNOWN;
186 				break;
187 			}
188 			if (!strcasecmp(optarg, "reject")) {
189 				handle_unknown = REJECT_UNKNOWN;
190 				break;
191 			}
192 			if (!strcasecmp(optarg, "allow")) {
193 				handle_unknown = ALLOW_UNKNOWN;
194 				break;
195 			}
196 			usage(argv[0]);
197 		case 'm':
198 			policy_type = POLICY_MOD;
199 			break;
200 		case 'M':
201 			mlspol = 1;
202 			break;
203 		case 'C':
204 			cil = 1;
205 			break;
206 		case 'c': {
207 			long int n;
208 			errno = 0;
209 			n = strtol(optarg, NULL, 10);
210 			if (errno) {
211 				fprintf(stderr,
212 					"Invalid policyvers specified: %s\n",
213 					optarg);
214 				usage(argv[0]);
215 			}
216 
217 			if (n < MOD_POLICYDB_VERSION_MIN
218 			    || n > MOD_POLICYDB_VERSION_MAX) {
219 				fprintf(stderr,
220 					"policyvers value %ld not in range %d-%d\n",
221 					n, MOD_POLICYDB_VERSION_MIN,
222 					MOD_POLICYDB_VERSION_MAX);
223 				usage(argv[0]);
224 			}
225 
226 			policyvers = n;
227 			break;
228 		}
229 		default:
230 			usage(argv[0]);
231 		}
232 	}
233 
234 	if (show_version) {
235 		printf("Module versions %d-%d\n",
236 		       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
237 		exit(0);
238 	}
239 
240 	if (handle_unknown && (policy_type != POLICY_BASE)) {
241 		fprintf(stderr, "%s:  Handling of unknown classes and permissions is only valid in the base module.\n", argv[0]);
242 		exit(1);
243 	}
244 
245 	if (binary && (policy_type != POLICY_BASE)) {
246 		fprintf(stderr, "%s:  -b and -m are incompatible with each other.\n", argv[0]);
247 		exit(1);
248 	}
249 
250 	if (optind != argc) {
251 		file = argv[optind++];
252 		if (optind != argc)
253 			usage(argv[0]);
254 	}
255 
256 	/* Set policydb and sidtab used by libsepol service functions
257 	   to my structures, so that I can directly populate and
258 	   manipulate them. */
259 	sepol_set_policydb(&modpolicydb);
260 	sepol_set_sidtab(&sidtab);
261 
262 	if (binary) {
263 		if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) {
264 			exit(1);
265 		}
266 	} else {
267 		if (policydb_init(&modpolicydb)) {
268 			fprintf(stderr, "%s: out of memory!\n", argv[0]);
269 			return -1;
270 		}
271 
272 		modpolicydb.policy_type = policy_type;
273 		modpolicydb.mls = mlspol;
274 		modpolicydb.handle_unknown = handle_unknown;
275 
276 		if (read_source_policy(&modpolicydb, file, argv[0]) == -1) {
277 			exit(1);
278 		}
279 
280 		if (hierarchy_check_constraints(NULL, &modpolicydb)) {
281 			return -1;
282 		}
283 	}
284 
285 	if (policy_type != POLICY_BASE && outfile) {
286 		char *mod_name = modpolicydb.name;
287 		char *out_path = strdup(outfile);
288 		if (out_path == NULL) {
289 			fprintf(stderr, "%s:  out of memory\n", argv[0]);
290 			exit(1);
291 		}
292 		char *out_name = basename(out_path);
293 		char *separator = strrchr(out_name, '.');
294 		if (separator) {
295 			*separator = '\0';
296 		}
297 		if (strcmp(mod_name, out_name) != 0) {
298 			fprintf(stderr,	"%s:  Module name %s is different than the output base filename %s\n", argv[0], mod_name, out_name);
299 			exit(1);
300 		}
301 		free(out_path);
302 	}
303 
304 	if (modpolicydb.policy_type == POLICY_BASE && !cil) {
305 		/* Verify that we can successfully expand the base module. */
306 		policydb_t kernpolicydb;
307 
308 		if (policydb_init(&kernpolicydb)) {
309 			fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
310 			exit(1);
311 		}
312 		if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) {
313 			fprintf(stderr, "%s:  link modules failed\n", argv[0]);
314 			exit(1);
315 		}
316 		if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) {
317 			fprintf(stderr, "%s:  expand module failed\n", argv[0]);
318 			exit(1);
319 		}
320 		policydb_destroy(&kernpolicydb);
321 	}
322 
323 	if (policydb_load_isids(&modpolicydb, &sidtab))
324 		exit(1);
325 
326 	sepol_sidtab_destroy(&sidtab);
327 
328 	if (outfile) {
329 		FILE *outfp = fopen(outfile, "w");
330 
331 		if (!outfp) {
332 			perror(outfile);
333 			exit(1);
334 		}
335 
336 		if (!cil) {
337 			if (write_binary_policy(&modpolicydb, outfp) != 0) {
338 				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
339 				exit(1);
340 			}
341 		} else {
342 			if (sepol_module_policydb_to_cil(outfp, &modpolicydb, 0) != 0) {
343 				fprintf(stderr, "%s:  error writing %s\n", argv[0], outfile);
344 				exit(1);
345 			}
346 		}
347 
348 		fclose(outfp);
349 	} else if (cil) {
350 		fprintf(stderr, "%s:  No file to write CIL was specified\n", argv[0]);
351 		exit(1);
352 	}
353 
354 	policydb_destroy(&modpolicydb);
355 
356 	return 0;
357 }
358 
359 /* FLASK */
360