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