checkmodule.c revision 36fe4c35ee6b86d11db92f047120b3e38ff64fa9
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
23#include <sepol/policydb/policydb.h>
24#include <sepol/policydb/services.h>
25#include <sepol/policydb/conditional.h>
26#include <sepol/policydb/flask.h>
27#include <sepol/policydb/hierarchy.h>
28#include <sepol/policydb/expand.h>
29#include <sepol/policydb/link.h>
30#include <sepol/policydb/sidtab.h>
31
32#include "queue.h"
33#include "checkpolicy.h"
34#include "parse_util.h"
35
36extern char *optarg;
37extern int optind;
38
39static sidtab_t sidtab;
40
41extern int mlspol;
42
43static int handle_unknown = SEPOL_DENY_UNKNOWN;
44static char *txtfile = "policy.conf";
45static char *binfile = "policy";
46
47unsigned int policy_type = POLICY_BASE;
48unsigned int policyvers = MOD_POLICYDB_VERSION_MAX;
49
50static int read_binary_policy(policydb_t * p, char *file, char *progname)
51{
52	int fd;
53	struct stat sb;
54	void *map;
55	struct policy_file f, *fp;
56
57	fd = open(file, O_RDONLY);
58	if (fd < 0) {
59		fprintf(stderr, "Can't open '%s':  %s\n",
60			file, strerror(errno));
61		return -1;
62	}
63	if (fstat(fd, &sb) < 0) {
64		fprintf(stderr, "Can't stat '%s':  %s\n",
65			file, strerror(errno));
66		return -1;
67	}
68	map =
69	    mmap(NULL, sb.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
70	if (map == MAP_FAILED) {
71		fprintf(stderr, "Can't map '%s':  %s\n", file, strerror(errno));
72		return -1;
73	}
74	policy_file_init(&f);
75	f.type = PF_USE_MEMORY;
76	f.data = map;
77	f.len = sb.st_size;
78	fp = &f;
79
80	if (policydb_init(p)) {
81		fprintf(stderr, "%s:  policydb_init:  Out of memory!\n",
82			progname);
83		return -1;
84	}
85	if (policydb_read(p, fp, 1)) {
86		fprintf(stderr,
87			"%s:  error(s) encountered while parsing configuration\n",
88			progname);
89		return -1;
90	}
91
92	/* Check Policy Consistency */
93	if (p->mls) {
94		if (!mlspol) {
95			fprintf(stderr, "%s:  MLS policy, but non-MLS"
96				" is specified\n", progname);
97			return -1;
98		}
99	} else {
100		if (mlspol) {
101			fprintf(stderr, "%s:  non-MLS policy, but MLS"
102				" is specified\n", progname);
103			return -1;
104		}
105	}
106	return 0;
107}
108
109static int write_binary_policy(policydb_t * p, char *file, char *progname)
110{
111	FILE *outfp = NULL;
112	struct policy_file pf;
113	int ret;
114
115	printf("%s:  writing binary representation (version %d) to %s\n",
116	       progname, policyvers, file);
117
118	outfp = fopen(file, "w");
119	if (!outfp) {
120		perror(file);
121		exit(1);
122	}
123
124	p->policy_type = policy_type;
125	p->policyvers = policyvers;
126	p->handle_unknown = handle_unknown;
127
128	policy_file_init(&pf);
129	pf.type = PF_USE_STDIO;
130	pf.fp = outfp;
131	ret = policydb_write(p, &pf);
132	if (ret) {
133		fprintf(stderr, "%s:  error writing %s\n", progname, file);
134		return -1;
135	}
136	fclose(outfp);
137	return 0;
138}
139
140static void usage(char *progname)
141{
142	printf("usage:  %s [-h] [-V] [-b] [-U handle_unknown] [-m] [-M] [-o FILE] [INPUT]\n", progname);
143	printf("Build base and policy modules.\n");
144	printf("Options:\n");
145	printf("  INPUT      build module from INPUT (else read from \"%s\")\n",
146	       txtfile);
147	printf("  -V         show policy versions created by this program\n");
148	printf("  -b         treat input as a binary policy file\n");
149	printf("  -h         print usage\n");
150	printf("  -U OPTION  How to handle unknown classes and permissions\n");
151	printf("               deny: Deny unknown kernel checks\n");
152	printf("               reject: Reject loading of policy with unknowns\n");
153	printf("               allow: Allow unknown kernel checks\n");
154	printf("  -m         build a policy module instead of a base module\n");
155	printf("  -M         enable MLS policy\n");
156	printf("  -o FILE    write module to FILE (else just check syntax)\n");
157	exit(1);
158}
159
160int main(int argc, char **argv)
161{
162	char *file = txtfile, *outfile = NULL;
163	unsigned int binary = 0;
164	int ch;
165	int show_version = 0;
166	policydb_t modpolicydb;
167	struct option long_options[] = {
168		{"help", no_argument, NULL, 'h'},
169		{"output", required_argument, NULL, 'o'},
170		{"binary", no_argument, NULL, 'b'},
171		{"version", no_argument, NULL, 'V'},
172		{"handle-unknown", optional_argument, NULL, 'U'},
173		{"mls", no_argument, NULL, 'M'},
174		{NULL, 0, NULL, 0}
175	};
176
177	while ((ch = getopt_long(argc, argv, "ho:bVU:mM", long_options, NULL)) != -1) {
178		switch (ch) {
179		case 'h':
180			usage(argv[0]);
181			break;
182		case 'o':
183			outfile = optarg;
184			break;
185		case 'b':
186			binary = 1;
187			file = binfile;
188			break;
189		case 'V':
190			show_version = 1;
191			break;
192		case 'U':
193			if (!strcasecmp(optarg, "deny")) {
194				handle_unknown = DENY_UNKNOWN;
195				break;
196			}
197			if (!strcasecmp(optarg, "reject")) {
198				handle_unknown = REJECT_UNKNOWN;
199				break;
200			}
201			if (!strcasecmp(optarg, "allow")) {
202				handle_unknown = ALLOW_UNKNOWN;
203				break;
204			}
205			usage(argv[0]);
206		case 'm':
207			policy_type = POLICY_MOD;
208			policyvers = MOD_POLICYDB_VERSION_MAX;
209			break;
210		case 'M':
211			mlspol = 1;
212			break;
213		default:
214			usage(argv[0]);
215		}
216	}
217
218	if (show_version) {
219		printf("Module versions %d-%d\n",
220		       MOD_POLICYDB_VERSION_MIN, MOD_POLICYDB_VERSION_MAX);
221		exit(0);
222	}
223
224	if (handle_unknown && (policy_type != POLICY_BASE)) {
225		printf("Handling of unknown classes and permissions is only ");
226		printf("valid in the base module\n");
227		exit(1);
228	}
229
230	if (optind != argc) {
231		file = argv[optind++];
232		if (optind != argc)
233			usage(argv[0]);
234	}
235	printf("%s:  loading policy configuration from %s\n", argv[0], file);
236
237	/* Set policydb and sidtab used by libsepol service functions
238	   to my structures, so that I can directly populate and
239	   manipulate them. */
240	sepol_set_policydb(&modpolicydb);
241	sepol_set_sidtab(&sidtab);
242
243	if (binary) {
244		if (read_binary_policy(&modpolicydb, file, argv[0]) == -1) {
245			exit(1);
246		}
247	} else {
248		if (policydb_init(&modpolicydb)) {
249			fprintf(stderr, "%s: out of memory!\n", argv[0]);
250			return -1;
251		}
252
253		modpolicydb.policy_type = policy_type;
254		modpolicydb.mls = mlspol;
255		modpolicydb.handle_unknown = handle_unknown;
256
257		if (read_source_policy(&modpolicydb, file, argv[0]) == -1) {
258			exit(1);
259		}
260
261		if (hierarchy_check_constraints(NULL, &modpolicydb)) {
262			return -1;
263		}
264	}
265
266	if (modpolicydb.policy_type == POLICY_BASE) {
267		/* Verify that we can successfully expand the base module. */
268		policydb_t kernpolicydb;
269
270		if (policydb_init(&kernpolicydb)) {
271			fprintf(stderr, "%s:  policydb_init failed\n", argv[0]);
272			exit(1);
273		}
274		if (link_modules(NULL, &modpolicydb, NULL, 0, 0)) {
275			fprintf(stderr, "%s:  link modules failed\n", argv[0]);
276			exit(1);
277		}
278		if (expand_module(NULL, &modpolicydb, &kernpolicydb, 0, 1)) {
279			fprintf(stderr, "%s:  expand module failed\n", argv[0]);
280			exit(1);
281		}
282		policydb_destroy(&kernpolicydb);
283	}
284
285	if (policydb_load_isids(&modpolicydb, &sidtab))
286		exit(1);
287
288	sepol_sidtab_destroy(&sidtab);
289
290	printf("%s:  policy configuration loaded\n", argv[0]);
291
292	if (outfile &&
293	    write_binary_policy(&modpolicydb, outfile, argv[0]) == -1) {
294		exit(1);
295	}
296	policydb_destroy(&modpolicydb);
297
298	return 0;
299}
300
301/* FLASK */
302