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