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