1 #include <ctype.h> 2 #include <fcntl.h> 3 #include <getopt.h> 4 #include <stdbool.h> 5 #include <stdio.h> 6 #include <sys/mman.h> 7 #include <sys/stat.h> 8 #include <sys/types.h> 9 #include <unistd.h> 10 11 #include "neverallow.h" 12 13 static int debug; 14 static int warn; 15 16 void neverallow_usage() { 17 fprintf(stderr, "\tneverallow [-w|--warn] [-d|--debug] [-n|--neverallows <neverallow-rules>] | [-f|--file <neverallow-file>]\n"); 18 } 19 20 static int read_typeset(policydb_t *policydb, char **ptr, char *end, 21 type_set_t *typeset, uint32_t *flags) 22 { 23 const char *keyword = "self"; 24 size_t keyword_size = strlen(keyword), len; 25 char *p = *ptr; 26 unsigned openparens = 0; 27 char *start, *id; 28 type_datum_t *type; 29 struct ebitmap_node *n; 30 unsigned int bit; 31 bool negate = false; 32 int rc; 33 34 do { 35 while (p < end && isspace(*p)) 36 p++; 37 38 if (p == end) 39 goto err; 40 41 if (*p == '~') { 42 if (debug) 43 printf(" ~"); 44 typeset->flags = TYPE_COMP; 45 p++; 46 while (p < end && isspace(*p)) 47 p++; 48 if (p == end) 49 goto err; 50 } 51 52 if (*p == '{') { 53 if (debug && !openparens) 54 printf(" {"); 55 openparens++; 56 p++; 57 continue; 58 } 59 60 if (*p == '}') { 61 if (debug && openparens == 1) 62 printf(" }"); 63 if (openparens == 0) 64 goto err; 65 openparens--; 66 p++; 67 continue; 68 } 69 70 if (*p == '*') { 71 if (debug) 72 printf(" *"); 73 typeset->flags = TYPE_STAR; 74 p++; 75 continue; 76 } 77 78 if (*p == '-') { 79 if (debug) 80 printf(" -"); 81 negate = true; 82 p++; 83 continue; 84 } 85 86 if (*p == '#') { 87 while (p < end && *p != '\n') 88 p++; 89 continue; 90 } 91 92 start = p; 93 while (p < end && !isspace(*p) && *p != ':' && *p != ';' && *p != '{' && *p != '}' && *p != '#') 94 p++; 95 96 if (p == start) 97 goto err; 98 99 len = p - start; 100 if (len == keyword_size && !strncmp(start, keyword, keyword_size)) { 101 if (debug) 102 printf(" self"); 103 *flags |= RULE_SELF; 104 continue; 105 } 106 107 id = calloc(1, len + 1); 108 if (!id) 109 goto err; 110 memcpy(id, start, len); 111 if (debug) 112 printf(" %s", id); 113 type = hashtab_search(policydb->p_types.table, id); 114 if (!type) { 115 if (warn) 116 fprintf(stderr, "Warning! Type or attribute %s used in neverallow undefined in policy being checked.\n", id); 117 negate = false; 118 continue; 119 } 120 free(id); 121 122 if (type->flavor == TYPE_ATTRIB) { 123 if (negate) 124 rc = ebitmap_union(&typeset->negset, &policydb->attr_type_map[type->s.value - 1]); 125 else 126 rc = ebitmap_union(&typeset->types, &policydb->attr_type_map[type->s.value - 1]); 127 } else if (negate) { 128 rc = ebitmap_set_bit(&typeset->negset, type->s.value - 1, 1); 129 } else { 130 rc = ebitmap_set_bit(&typeset->types, type->s.value - 1, 1); 131 } 132 133 negate = false; 134 135 if (rc) 136 goto err; 137 138 } while (p < end && openparens); 139 140 if (p == end) 141 goto err; 142 143 if (typeset->flags & TYPE_STAR) { 144 for (bit = 0; bit < policydb->p_types.nprim; bit++) { 145 if (ebitmap_get_bit(&typeset->negset, bit)) 146 continue; 147 if (policydb->type_val_to_struct[bit] && 148 policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB) 149 continue; 150 if (ebitmap_set_bit(&typeset->types, bit, 1)) 151 goto err; 152 } 153 } 154 155 ebitmap_for_each_bit(&typeset->negset, n, bit) { 156 if (!ebitmap_node_get_bit(n, bit)) 157 continue; 158 if (ebitmap_set_bit(&typeset->types, bit, 0)) 159 goto err; 160 } 161 162 if (typeset->flags & TYPE_COMP) { 163 for (bit = 0; bit < policydb->p_types.nprim; bit++) { 164 if (policydb->type_val_to_struct[bit] && 165 policydb->type_val_to_struct[bit]->flavor == TYPE_ATTRIB) 166 continue; 167 if (ebitmap_get_bit(&typeset->types, bit)) 168 ebitmap_set_bit(&typeset->types, bit, 0); 169 else { 170 if (ebitmap_set_bit(&typeset->types, bit, 1)) 171 goto err; 172 } 173 } 174 } 175 176 *ptr = p; 177 return 0; 178 err: 179 return -1; 180 } 181 182 static int read_classperms(policydb_t *policydb, char **ptr, char *end, 183 class_perm_node_t **perms) 184 { 185 char *p = *ptr; 186 unsigned openparens = 0; 187 char *id, *start; 188 class_datum_t *cls = NULL; 189 perm_datum_t *perm = NULL; 190 class_perm_node_t *classperms = NULL, *node = NULL; 191 bool complement = false; 192 193 while (p < end && isspace(*p)) 194 p++; 195 196 if (p == end || *p != ':') 197 goto err; 198 p++; 199 200 if (debug) 201 printf(" :"); 202 203 do { 204 while (p < end && isspace(*p)) 205 p++; 206 207 if (p == end) 208 goto err; 209 210 if (*p == '{') { 211 if (debug && !openparens) 212 printf(" {"); 213 openparens++; 214 p++; 215 continue; 216 } 217 218 if (*p == '}') { 219 if (debug && openparens == 1) 220 printf(" }"); 221 if (openparens == 0) 222 goto err; 223 openparens--; 224 p++; 225 continue; 226 } 227 228 if (*p == '#') { 229 while (p < end && *p != '\n') 230 p++; 231 continue; 232 } 233 234 start = p; 235 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#') 236 p++; 237 238 if (p == start) 239 goto err; 240 241 id = calloc(1, p - start + 1); 242 if (!id) 243 goto err; 244 memcpy(id, start, p - start); 245 if (debug) 246 printf(" %s", id); 247 cls = hashtab_search(policydb->p_classes.table, id); 248 if (!cls) { 249 if (warn) 250 fprintf(stderr, "Warning! Class %s used in neverallow undefined in policy being checked.\n", id); 251 continue; 252 } 253 254 node = calloc(1, sizeof *node); 255 if (!node) 256 goto err; 257 node->tclass = cls->s.value; 258 node->next = classperms; 259 classperms = node; 260 free(id); 261 id = NULL; 262 } while (p < end && openparens); 263 264 if (p == end) 265 goto err; 266 267 if (warn && !classperms) 268 fprintf(stderr, "Warning! Empty class set\n"); 269 270 do { 271 while (p < end && isspace(*p)) 272 p++; 273 274 if (p == end) 275 goto err; 276 277 if (*p == '~') { 278 if (debug) 279 printf(" ~"); 280 complement = true; 281 p++; 282 while (p < end && isspace(*p)) 283 p++; 284 if (p == end) 285 goto err; 286 } 287 288 if (*p == '{') { 289 if (debug && !openparens) 290 printf(" {"); 291 openparens++; 292 p++; 293 continue; 294 } 295 296 if (*p == '}') { 297 if (debug && openparens == 1) 298 printf(" }"); 299 if (openparens == 0) 300 goto err; 301 openparens--; 302 p++; 303 continue; 304 } 305 306 if (*p == '#') { 307 while (p < end && *p != '\n') 308 p++; 309 continue; 310 } 311 312 start = p; 313 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#') 314 p++; 315 316 if (p == start) 317 goto err; 318 319 id = calloc(1, p - start + 1); 320 if (!id) 321 goto err; 322 memcpy(id, start, p - start); 323 if (debug) 324 printf(" %s", id); 325 326 if (!strcmp(id, "*")) { 327 for (node = classperms; node; node = node->next) 328 node->data = ~0; 329 free(id); 330 id = NULL; 331 continue; 332 } 333 334 for (node = classperms; node; node = node->next) { 335 cls = policydb->class_val_to_struct[node->tclass-1]; 336 perm = hashtab_search(cls->permissions.table, id); 337 if (cls->comdatum && !perm) 338 perm = hashtab_search(cls->comdatum->permissions.table, id); 339 if (!perm) { 340 if (warn) 341 fprintf(stderr, "Warning! Permission %s used in neverallow undefined in class %s in policy being checked.\n", id, policydb->p_class_val_to_name[node->tclass-1]); 342 continue; 343 } 344 node->data |= 1U << (perm->s.value - 1); 345 } 346 free(id); 347 id = NULL; 348 } while (p < end && openparens); 349 350 if (p == end) 351 goto err; 352 353 if (complement) { 354 for (node = classperms; node; node = node->next) 355 node->data = ~node->data; 356 } 357 358 if (warn) { 359 for (node = classperms; node; node = node->next) 360 if (!node->data) 361 fprintf(stderr, "Warning! Empty permission set\n"); 362 } 363 364 *perms = classperms; 365 *ptr = p; 366 return 0; 367 err: 368 // free classperms memory 369 for (node = classperms; node; ) { 370 class_perm_node_t *freeptr = node; 371 node = node->next; 372 free(freeptr); 373 } 374 return -1; 375 } 376 377 static int check_neverallows(policydb_t *policydb, char *text, char *end) 378 { 379 const char *keyword = "neverallow"; 380 size_t keyword_size = strlen(keyword), len; 381 struct avrule *neverallows = NULL, *avrule = NULL; 382 char *p, *start; 383 int result; 384 385 p = text; 386 while (p < end) { 387 while (p < end && isspace(*p)) 388 p++; 389 390 if (*p == '#') { 391 while (p < end && *p != '\n') 392 p++; 393 continue; 394 } 395 396 start = p; 397 while (p < end && !isspace(*p)) 398 p++; 399 400 len = p - start; 401 if (len != keyword_size || strncmp(start, keyword, keyword_size)) 402 continue; 403 404 if (debug) 405 printf("neverallow"); 406 407 avrule = calloc(1, sizeof *avrule); 408 if (!avrule) 409 goto err; 410 411 avrule->specified = AVRULE_NEVERALLOW; 412 413 if (read_typeset(policydb, &p, end, &avrule->stypes, &avrule->flags)) 414 goto err; 415 416 if (read_typeset(policydb, &p, end, &avrule->ttypes, &avrule->flags)) 417 goto err; 418 419 if (read_classperms(policydb, &p, end, &avrule->perms)) 420 goto err; 421 422 while (p < end && *p != ';') 423 p++; 424 425 if (p == end || *p != ';') 426 goto err; 427 428 if (debug) 429 printf(";\n"); 430 431 avrule->next = neverallows; 432 neverallows = avrule; 433 } 434 435 if (!neverallows) 436 goto err; 437 438 result = check_assertions(NULL, policydb, neverallows); 439 avrule_list_destroy(neverallows); 440 return result; 441 err: 442 if (errno == ENOMEM) { 443 fprintf(stderr, "Out of memory while parsing neverallow rules\n"); 444 } else 445 fprintf(stderr, "Error while parsing neverallow rules\n"); 446 447 avrule_list_destroy(neverallows); 448 if (avrule != neverallows) 449 avrule_destroy(avrule); 450 451 return -1; 452 } 453 454 static int check_neverallows_file(policydb_t *policydb, const char *filename) 455 { 456 int fd; 457 struct stat sb; 458 char *text, *end; 459 460 fd = open(filename, O_RDONLY); 461 if (fd < 0) { 462 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); 463 return -1; 464 } 465 if (fstat(fd, &sb) < 0) { 466 fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno)); 467 close(fd); 468 return -1; 469 } 470 text = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 471 end = text + sb.st_size; 472 if (text == MAP_FAILED) { 473 fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno)); 474 close(fd); 475 return -1; 476 } 477 close(fd); 478 return check_neverallows(policydb, text, end); 479 } 480 481 static int check_neverallows_string(policydb_t *policydb, char *string, size_t len) 482 { 483 char *text, *end; 484 text = string; 485 end = text + len; 486 return check_neverallows(policydb, text, end); 487 } 488 489 int neverallow_func (int argc, char **argv, policydb_t *policydb) { 490 char *rules = 0, *file = 0; 491 char ch; 492 493 struct option neverallow_options[] = { 494 {"debug", no_argument, NULL, 'd'}, 495 {"file_input", required_argument, NULL, 'f'}, 496 {"neverallow", required_argument, NULL, 'n'}, 497 {"warn", no_argument, NULL, 'w'}, 498 {NULL, 0, NULL, 0} 499 }; 500 501 while ((ch = getopt_long(argc, argv, "df:n:w", neverallow_options, NULL)) != -1) { 502 switch (ch) { 503 case 'd': 504 debug = 1; 505 break; 506 case 'f': 507 file = optarg; 508 break; 509 case 'n': 510 rules = optarg; 511 break; 512 case 'w': 513 warn = 1; 514 break; 515 default: 516 USAGE_ERROR = true; 517 return -1; 518 } 519 } 520 521 if (!(rules || file) || (rules && file)){ 522 USAGE_ERROR = true; 523 return -1; 524 } 525 if (file) { 526 return check_neverallows_file(policydb, file); 527 } else { 528 return check_neverallows_string(policydb, rules, strlen(rules)); 529 } 530 } 531