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 13static int debug; 14static int warn; 15 16void neverallow_usage() { 17 fprintf(stderr, "\tneverallow [-w|--warn] [-d|--debug] [-n|--neverallows <neverallow-rules>] | [-f|--file <neverallow-file>]\n"); 18} 19 20static 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; 178err: 179 return -1; 180} 181 182static 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; 367err: 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 377static 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; 382 char *p, *start; 383 384 p = text; 385 while (p < end) { 386 while (p < end && isspace(*p)) 387 p++; 388 389 if (*p == '#') { 390 while (p < end && *p != '\n') 391 p++; 392 continue; 393 } 394 395 start = p; 396 while (p < end && !isspace(*p)) 397 p++; 398 399 len = p - start; 400 if (len != keyword_size || strncmp(start, keyword, keyword_size)) 401 continue; 402 403 if (debug) 404 printf("neverallow"); 405 406 avrule = calloc(1, sizeof *avrule); 407 if (!avrule) 408 goto err; 409 410 avrule->specified = AVRULE_NEVERALLOW; 411 412 if (read_typeset(policydb, &p, end, &avrule->stypes, &avrule->flags)) 413 goto err; 414 415 if (read_typeset(policydb, &p, end, &avrule->ttypes, &avrule->flags)) 416 goto err; 417 418 if (read_classperms(policydb, &p, end, &avrule->perms)) 419 goto err; 420 421 while (p < end && *p != ';') 422 p++; 423 424 if (p == end || *p != ';') 425 goto err; 426 427 if (debug) 428 printf(";\n"); 429 430 avrule->next = neverallows; 431 neverallows = avrule; 432 } 433 434 if (!neverallows) 435 goto err; 436 437 return check_assertions(NULL, policydb, neverallows); 438err: 439 if (errno == ENOMEM) { 440 fprintf(stderr, "Out of memory while parsing neverallow rules\n"); 441 } else 442 fprintf(stderr, "Error while parsing neverallow rules\n"); 443 return -1; 444} 445 446static int check_neverallows_file(policydb_t *policydb, const char *filename) 447{ 448 int fd; 449 struct stat sb; 450 char *text, *end; 451 452 fd = open(filename, O_RDONLY); 453 if (fd < 0) { 454 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); 455 return -1; 456 } 457 if (fstat(fd, &sb) < 0) { 458 fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno)); 459 close(fd); 460 return -1; 461 } 462 text = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 463 end = text + sb.st_size; 464 if (text == MAP_FAILED) { 465 fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno)); 466 close(fd); 467 return -1; 468 } 469 close(fd); 470 return check_neverallows(policydb, text, end); 471} 472 473static int check_neverallows_string(policydb_t *policydb, char *string, size_t len) 474{ 475 char *text, *end; 476 text = string; 477 end = text + len; 478 return check_neverallows(policydb, text, end); 479} 480 481int neverallow_func (int argc, char **argv, policydb_t *policydb) { 482 char *rules = 0, *file = 0; 483 char ch; 484 485 struct option neverallow_options[] = { 486 {"debug", no_argument, NULL, 'd'}, 487 {"file_input", required_argument, NULL, 'f'}, 488 {"neverallow", required_argument, NULL, 'n'}, 489 {"warn", no_argument, NULL, 'w'}, 490 {NULL, 0, NULL, 0} 491 }; 492 493 while ((ch = getopt_long(argc, argv, "df:n:w", neverallow_options, NULL)) != -1) { 494 switch (ch) { 495 case 'd': 496 debug = 1; 497 break; 498 case 'f': 499 file = optarg; 500 break; 501 case 'n': 502 rules = optarg; 503 break; 504 case 'w': 505 warn = 1; 506 break; 507 default: 508 USAGE_ERROR = true; 509 return -1; 510 } 511 } 512 513 if (!(rules || file) || (rules && file)){ 514 USAGE_ERROR = true; 515 return -1; 516 } 517 if (file) { 518 return check_neverallows_file(policydb, file); 519 } else { 520 return check_neverallows_string(policydb, rules, strlen(rules)); 521 } 522} 523