1 /* 2 * Copyright 2011 Tresys Technology, LLC. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY TRESYS TECHNOLOGY, LLC ``AS IS'' AND ANY EXPRESS 15 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 * EVENT SHALL TRESYS TECHNOLOGY, LLC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 22 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * The views and conclusions contained in the software and documentation are those 26 * of the authors and should not be interpreted as representing official policies, 27 * either expressed or implied, of Tresys Technology, LLC. 28 */ 29 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <stdint.h> 33 #include <string.h> 34 #include <getopt.h> 35 #include <sys/stat.h> 36 37 #ifdef ANDROID 38 #include <cil/cil.h> 39 #else 40 #include <sepol/cil/cil.h> 41 #endif 42 #include <sepol/policydb.h> 43 44 static __attribute__((__noreturn__)) void usage(const char *prog) 45 { 46 printf("Usage: %s [OPTION]... FILE...\n", prog); 47 printf("\n"); 48 printf("Options:\n"); 49 printf(" -o, --output=<file> write binary policy to <file>\n"); 50 printf(" (default: policy.<version>)\n"); 51 printf(" -f, --filecontext=<file> write file contexts to <file>\n"); 52 printf(" (default: file_contexts)\n"); 53 printf(" -t, --target=<type> specify target architecture. may be selinux or\n"); 54 printf(" xen. (default: selinux)\n"); 55 printf(" -M, --mls true|false build an mls policy. Must be true or false.\n"); 56 printf(" This will override the (mls boolean) statement\n"); 57 printf(" if present in the policy\n"); 58 printf(" -c, --policyvers=<version> build a binary policy with a given <version>\n"); 59 printf(" (default: %i)\n", POLICYDB_VERSION_MAX); 60 printf(" -U, --handle-unknown=<action> how to handle unknown classes or permissions.\n"); 61 printf(" may be deny, allow, or reject. (default: deny)\n"); 62 printf(" This will override the (handleunknown action)\n"); 63 printf(" statement if present in the policy\n"); 64 printf(" -D, --disable-dontaudit do not add dontaudit rules to the binary policy\n"); 65 printf(" -P, --preserve-tunables treat tunables as booleans\n"); 66 printf(" -m, --multiple-decls allow some statements to be re-declared\n"); 67 printf(" -N, --disable-neverallow do not check neverallow rules\n"); 68 printf(" -G, --expand-generated Expand and remove auto-generated attributes\n"); 69 printf(" -X, --expand-size <SIZE> Expand type attributes with fewer than <SIZE>\n"); 70 printf(" members.\n"); 71 printf(" -v, --verbose increment verbosity level\n"); 72 printf(" -h, --help display usage information\n"); 73 exit(1); 74 } 75 76 int main(int argc, char *argv[]) 77 { 78 int rc = SEPOL_ERR; 79 sepol_policydb_t *pdb = NULL; 80 struct sepol_policy_file *pf = NULL; 81 FILE *binary = NULL; 82 FILE *file_contexts; 83 FILE *file = NULL; 84 char *buffer = NULL; 85 struct stat filedata; 86 uint32_t file_size; 87 char *output = NULL; 88 char *filecontexts = NULL; 89 struct cil_db *db = NULL; 90 int target = SEPOL_TARGET_SELINUX; 91 int mls = -1; 92 int disable_dontaudit = 0; 93 int multiple_decls = 0; 94 int disable_neverallow = 0; 95 int preserve_tunables = 0; 96 int handle_unknown = -1; 97 int policyvers = POLICYDB_VERSION_MAX; 98 int attrs_expand_generated = 0; 99 int attrs_expand_size = -1; 100 int opt_char; 101 int opt_index = 0; 102 char *fc_buf = NULL; 103 size_t fc_size; 104 enum cil_log_level log_level = CIL_ERR; 105 static struct option long_opts[] = { 106 {"help", no_argument, 0, 'h'}, 107 {"verbose", no_argument, 0, 'v'}, 108 {"target", required_argument, 0, 't'}, 109 {"mls", required_argument, 0, 'M'}, 110 {"policyversion", required_argument, 0, 'c'}, 111 {"handle-unknown", required_argument, 0, 'U'}, 112 {"disable-dontaudit", no_argument, 0, 'D'}, 113 {"multiple-decls", no_argument, 0, 'm'}, 114 {"disable-neverallow", no_argument, 0, 'N'}, 115 {"preserve-tunables", no_argument, 0, 'P'}, 116 {"output", required_argument, 0, 'o'}, 117 {"filecontexts", required_argument, 0, 'f'}, 118 {"expand-generated", no_argument, 0, 'G'}, 119 {"expand-size", required_argument, 0, 'X'}, 120 {0, 0, 0, 0} 121 }; 122 int i; 123 124 while (1) { 125 opt_char = getopt_long(argc, argv, "o:f:U:hvt:M:PDmNc:GX:", long_opts, &opt_index); 126 if (opt_char == -1) { 127 break; 128 } 129 switch (opt_char) { 130 case 'v': 131 log_level++; 132 break; 133 case 't': 134 if (!strcmp(optarg, "selinux")) { 135 target = SEPOL_TARGET_SELINUX; 136 } else if (!strcmp(optarg, "xen")) { 137 target = SEPOL_TARGET_XEN; 138 } else { 139 fprintf(stderr, "Unknown target: %s\n", optarg); 140 usage(argv[0]); 141 } 142 break; 143 case 'M': 144 if (!strcasecmp(optarg, "true") || !strcasecmp(optarg, "1")) { 145 mls = 1; 146 } else if (!strcasecmp(optarg, "false") || !strcasecmp(optarg, "0")) { 147 mls = 0; 148 } else { 149 usage(argv[0]); 150 } 151 break; 152 case 'c': { 153 char *endptr = NULL; 154 errno = 0; 155 policyvers = strtol(optarg, &endptr, 10); 156 if (errno != 0 || endptr == optarg || *endptr != '\0') { 157 fprintf(stderr, "Bad policy version: %s\n", optarg); 158 usage(argv[0]); 159 } 160 if (policyvers > POLICYDB_VERSION_MAX || policyvers < POLICYDB_VERSION_MIN) { 161 fprintf(stderr, "Policy version must be between %d and %d\n", 162 POLICYDB_VERSION_MIN, POLICYDB_VERSION_MAX); 163 usage(argv[0]); 164 } 165 break; 166 } 167 case 'U': 168 if (!strcasecmp(optarg, "deny")) { 169 handle_unknown = SEPOL_DENY_UNKNOWN; 170 } else if (!strcasecmp(optarg, "allow")) { 171 handle_unknown = SEPOL_ALLOW_UNKNOWN; 172 } else if (!strcasecmp(optarg, "reject")) { 173 handle_unknown = SEPOL_REJECT_UNKNOWN; 174 } else { 175 usage(argv[0]); 176 } 177 break; 178 case 'D': 179 disable_dontaudit = 1; 180 break; 181 case 'm': 182 multiple_decls = 1; 183 break; 184 case 'N': 185 disable_neverallow = 1; 186 break; 187 case 'P': 188 preserve_tunables = 1; 189 break; 190 case 'o': 191 output = strdup(optarg); 192 break; 193 case 'f': 194 filecontexts = strdup(optarg); 195 break; 196 case 'G': 197 attrs_expand_generated = 1; 198 break; 199 case 'X': { 200 char *endptr = NULL; 201 errno = 0; 202 attrs_expand_size = strtol(optarg, &endptr, 10); 203 if (errno != 0 || endptr == optarg || *endptr != '\0') { 204 fprintf(stderr, "Bad attribute expand size: %s\n", optarg); 205 usage(argv[0]); 206 } 207 208 if (attrs_expand_size < 0) { 209 fprintf(stderr, "Attribute expand size must be > 0\n"); 210 usage(argv[0]); 211 } 212 break; 213 } 214 case 'h': 215 usage(argv[0]); 216 case '?': 217 break; 218 default: 219 fprintf(stderr, "Unsupported option: %s\n", optarg); 220 usage(argv[0]); 221 } 222 } 223 if (optind >= argc) { 224 fprintf(stderr, "No cil files specified\n"); 225 usage(argv[0]); 226 } 227 228 cil_set_log_level(log_level); 229 230 cil_db_init(&db); 231 cil_set_disable_dontaudit(db, disable_dontaudit); 232 cil_set_multiple_decls(db, multiple_decls); 233 cil_set_disable_neverallow(db, disable_neverallow); 234 cil_set_preserve_tunables(db, preserve_tunables); 235 if (handle_unknown != -1) { 236 rc = cil_set_handle_unknown(db, handle_unknown); 237 if (rc != SEPOL_OK) { 238 goto exit; 239 } 240 } 241 242 cil_set_mls(db, mls); 243 cil_set_target_platform(db, target); 244 cil_set_policy_version(db, policyvers); 245 cil_set_attrs_expand_generated(db, attrs_expand_generated); 246 if (attrs_expand_size >= 0) { 247 cil_set_attrs_expand_size(db, (unsigned)attrs_expand_size); 248 } 249 250 for (i = optind; i < argc; i++) { 251 file = fopen(argv[i], "r"); 252 if (!file) { 253 fprintf(stderr, "Could not open file: %s\n", argv[i]); 254 rc = SEPOL_ERR; 255 goto exit; 256 } 257 rc = stat(argv[i], &filedata); 258 if (rc == -1) { 259 fprintf(stderr, "Could not stat file: %s\n", argv[i]); 260 rc = SEPOL_ERR; 261 goto exit; 262 } 263 file_size = filedata.st_size; 264 265 buffer = malloc(file_size); 266 rc = fread(buffer, file_size, 1, file); 267 if (rc != 1) { 268 fprintf(stderr, "Failure reading file: %s\n", argv[i]); 269 rc = SEPOL_ERR; 270 goto exit; 271 } 272 fclose(file); 273 file = NULL; 274 275 rc = cil_add_file(db, argv[i], buffer, file_size); 276 if (rc != SEPOL_OK) { 277 fprintf(stderr, "Failure adding %s\n", argv[i]); 278 goto exit; 279 } 280 281 free(buffer); 282 buffer = NULL; 283 } 284 285 rc = cil_compile(db); 286 if (rc != SEPOL_OK) { 287 fprintf(stderr, "Failed to compile cildb: %d\n", rc); 288 goto exit; 289 } 290 291 rc = cil_build_policydb(db, &pdb); 292 if (rc != SEPOL_OK) { 293 fprintf(stderr, "Failed to build policydb\n"); 294 goto exit; 295 } 296 297 if (output == NULL) { 298 int size = snprintf(NULL, 0, "policy.%d", policyvers); 299 output = malloc((size + 1) * sizeof(char)); 300 if (output == NULL) { 301 fprintf(stderr, "Failed to create output filename\n"); 302 rc = SEPOL_ERR; 303 goto exit; 304 } 305 if (snprintf(output, size + 1, "policy.%d", policyvers) != size) { 306 fprintf(stderr, "Failed to create output filename\n"); 307 rc = SEPOL_ERR; 308 goto exit; 309 } 310 } 311 312 binary = fopen(output, "w"); 313 if (binary == NULL) { 314 fprintf(stderr, "Failure opening binary file for writing\n"); 315 rc = SEPOL_ERR; 316 goto exit; 317 } 318 319 rc = sepol_policy_file_create(&pf); 320 if (rc != 0) { 321 fprintf(stderr, "Failed to create policy file: %d\n", rc); 322 goto exit; 323 } 324 325 sepol_policy_file_set_fp(pf, binary); 326 327 rc = sepol_policydb_write(pdb, pf); 328 if (rc != 0) { 329 fprintf(stderr, "Failed to write binary policy: %d\n", rc); 330 goto exit; 331 } 332 333 fclose(binary); 334 binary = NULL; 335 336 rc = cil_filecons_to_string(db, &fc_buf, &fc_size); 337 if (rc != SEPOL_OK) { 338 fprintf(stderr, "Failed to get file context data\n"); 339 goto exit; 340 } 341 342 if (filecontexts == NULL) { 343 file_contexts = fopen("file_contexts", "w+"); 344 } else { 345 file_contexts = fopen(filecontexts, "w+"); 346 } 347 348 if (file_contexts == NULL) { 349 fprintf(stderr, "Failed to open file_contexts file\n"); 350 rc = SEPOL_ERR; 351 goto exit; 352 } 353 354 if (fwrite(fc_buf, sizeof(char), fc_size, file_contexts) != fc_size) { 355 fprintf(stderr, "Failed to write file_contexts file\n"); 356 rc = SEPOL_ERR; 357 goto exit; 358 } 359 360 fclose(file_contexts); 361 file_contexts = NULL; 362 363 rc = SEPOL_OK; 364 365 exit: 366 if (binary != NULL) { 367 fclose(binary); 368 } 369 if (file != NULL) { 370 fclose(file); 371 } 372 free(buffer); 373 free(output); 374 free(filecontexts); 375 cil_db_destroy(&db); 376 sepol_policydb_free(pdb); 377 sepol_policy_file_free(pf); 378 free(fc_buf); 379 return rc; 380 } 381