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 if (warn && ebitmap_length(&typeset->types) == 0 && !(*flags)) 177 fprintf(stderr, "Warning! Empty type set\n"); 178 179 *ptr = p; 180 return 0; 181err: 182 return -1; 183} 184 185static int read_classperms(policydb_t *policydb, char **ptr, char *end, 186 class_perm_node_t **perms) 187{ 188 char *p = *ptr; 189 unsigned openparens = 0; 190 char *id, *start; 191 class_datum_t *cls = NULL; 192 perm_datum_t *perm = NULL; 193 class_perm_node_t *classperms = NULL, *node = NULL; 194 bool complement = false; 195 196 while (p < end && isspace(*p)) 197 p++; 198 199 if (p == end || *p != ':') 200 goto err; 201 p++; 202 203 if (debug) 204 printf(" :"); 205 206 do { 207 while (p < end && isspace(*p)) 208 p++; 209 210 if (p == end) 211 goto err; 212 213 if (*p == '{') { 214 if (debug && !openparens) 215 printf(" {"); 216 openparens++; 217 p++; 218 continue; 219 } 220 221 if (*p == '}') { 222 if (debug && openparens == 1) 223 printf(" }"); 224 if (openparens == 0) 225 goto err; 226 openparens--; 227 p++; 228 continue; 229 } 230 231 if (*p == '#') { 232 while (p < end && *p != '\n') 233 p++; 234 continue; 235 } 236 237 start = p; 238 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#') 239 p++; 240 241 if (p == start) 242 goto err; 243 244 id = calloc(1, p - start + 1); 245 if (!id) 246 goto err; 247 memcpy(id, start, p - start); 248 if (debug) 249 printf(" %s", id); 250 cls = hashtab_search(policydb->p_classes.table, id); 251 if (!cls) { 252 if (warn) 253 fprintf(stderr, "Warning! Class %s used in neverallow undefined in policy being checked.\n", id); 254 continue; 255 } 256 257 node = calloc(1, sizeof *node); 258 if (!node) 259 goto err; 260 node->tclass = cls->s.value; 261 node->next = classperms; 262 classperms = node; 263 free(id); 264 } while (p < end && openparens); 265 266 if (p == end) 267 goto err; 268 269 if (warn && !classperms) 270 fprintf(stderr, "Warning! Empty class set\n"); 271 272 do { 273 while (p < end && isspace(*p)) 274 p++; 275 276 if (p == end) 277 goto err; 278 279 if (*p == '~') { 280 if (debug) 281 printf(" ~"); 282 complement = true; 283 p++; 284 while (p < end && isspace(*p)) 285 p++; 286 if (p == end) 287 goto err; 288 } 289 290 if (*p == '{') { 291 if (debug && !openparens) 292 printf(" {"); 293 openparens++; 294 p++; 295 continue; 296 } 297 298 if (*p == '}') { 299 if (debug && openparens == 1) 300 printf(" }"); 301 if (openparens == 0) 302 goto err; 303 openparens--; 304 p++; 305 continue; 306 } 307 308 if (*p == '#') { 309 while (p < end && *p != '\n') 310 p++; 311 continue; 312 } 313 314 start = p; 315 while (p < end && !isspace(*p) && *p != '{' && *p != '}' && *p != ';' && *p != '#') 316 p++; 317 318 if (p == start) 319 goto err; 320 321 id = calloc(1, p - start + 1); 322 if (!id) 323 goto err; 324 memcpy(id, start, p - start); 325 if (debug) 326 printf(" %s", id); 327 328 if (!strcmp(id, "*")) { 329 for (node = classperms; node; node = node->next) 330 node->data = ~0; 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 } while (p < end && openparens); 348 349 if (p == end) 350 goto err; 351 352 if (complement) { 353 for (node = classperms; node; node = node->next) 354 node->data = ~node->data; 355 } 356 357 if (warn) { 358 for (node = classperms; node; node = node->next) 359 if (!node->data) 360 fprintf(stderr, "Warning! Empty permission set\n"); 361 } 362 363 *perms = classperms; 364 *ptr = p; 365 return 0; 366err: 367 return -1; 368} 369 370static int check_neverallows(policydb_t *policydb, char *text, char *end) 371{ 372 const char *keyword = "neverallow"; 373 size_t keyword_size = strlen(keyword), len; 374 struct avrule *neverallows = NULL, *avrule; 375 char *p, *start; 376 377 p = text; 378 while (p < end) { 379 while (p < end && isspace(*p)) 380 p++; 381 382 if (*p == '#') { 383 while (p < end && *p != '\n') 384 p++; 385 continue; 386 } 387 388 start = p; 389 while (p < end && !isspace(*p)) 390 p++; 391 392 len = p - start; 393 if (len != keyword_size || strncmp(start, keyword, keyword_size)) 394 continue; 395 396 if (debug) 397 printf("neverallow"); 398 399 avrule = calloc(1, sizeof *avrule); 400 if (!avrule) 401 goto err; 402 403 avrule->specified = AVRULE_NEVERALLOW; 404 405 if (read_typeset(policydb, &p, end, &avrule->stypes, &avrule->flags)) 406 goto err; 407 408 if (read_typeset(policydb, &p, end, &avrule->ttypes, &avrule->flags)) 409 goto err; 410 411 if (read_classperms(policydb, &p, end, &avrule->perms)) 412 goto err; 413 414 while (p < end && *p != ';') 415 p++; 416 417 if (p == end || *p != ';') 418 goto err; 419 420 if (debug) 421 printf(";\n"); 422 423 avrule->next = neverallows; 424 neverallows = avrule; 425 } 426 427 if (!neverallows) 428 goto err; 429 430 return check_assertions(NULL, policydb, neverallows); 431err: 432 if (errno == ENOMEM) { 433 fprintf(stderr, "Out of memory while parsing neverallow rules\n"); 434 } else 435 fprintf(stderr, "Error while parsing neverallow rules\n"); 436 return -1; 437} 438 439static int check_neverallows_file(policydb_t *policydb, const char *filename) 440{ 441 int fd; 442 struct stat sb; 443 char *text, *end; 444 445 fd = open(filename, O_RDONLY); 446 if (fd < 0) { 447 fprintf(stderr, "Could not open %s: %s\n", filename, strerror(errno)); 448 return -1; 449 } 450 if (fstat(fd, &sb) < 0) { 451 fprintf(stderr, "Can't stat '%s': %s\n", filename, strerror(errno)); 452 close(fd); 453 return -1; 454 } 455 text = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 456 end = text + sb.st_size; 457 if (text == MAP_FAILED) { 458 fprintf(stderr, "Can't mmap '%s': %s\n", filename, strerror(errno)); 459 close(fd); 460 return -1; 461 } 462 close(fd); 463 return check_neverallows(policydb, text, end); 464} 465 466static int check_neverallows_string(policydb_t *policydb, char *string, size_t len) 467{ 468 char *text, *end; 469 text = string; 470 end = text + len; 471 return check_neverallows(policydb, text, end); 472} 473 474int neverallow_func (int argc, char **argv, policydb_t *policydb) { 475 char *rules = 0, *file = 0; 476 char ch; 477 478 struct option neverallow_options[] = { 479 {"debug", no_argument, NULL, 'd'}, 480 {"file_input", required_argument, NULL, 'f'}, 481 {"neverallow", required_argument, NULL, 'n'}, 482 {"warn", no_argument, NULL, 'w'}, 483 {NULL, 0, NULL, 0} 484 }; 485 486 while ((ch = getopt_long(argc, argv, "df:n:w", neverallow_options, NULL)) != -1) { 487 switch (ch) { 488 case 'd': 489 debug = 1; 490 break; 491 case 'f': 492 file = optarg; 493 break; 494 case 'n': 495 rules = optarg; 496 break; 497 case 'w': 498 warn = 1; 499 break; 500 default: 501 USAGE_ERROR = true; 502 return -1; 503 } 504 } 505 506 if (!(rules || file) || (rules && file)){ 507 USAGE_ERROR = true; 508 return -1; 509 } 510 if (file) { 511 return check_neverallows_file(policydb, file); 512 } else { 513 return check_neverallows_string(policydb, rules, strlen(rules)); 514 } 515} 516