Home | History | Annotate | Download | only in sepolicy-analyze
      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     if (warn && ebitmap_length(&typeset->types) == 0 && !(*flags))
    177         fprintf(stderr, "Warning!  Empty type set\n");
    178 
    179     *ptr = p;
    180     return 0;
    181 err:
    182     return -1;
    183 }
    184 
    185 static 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;
    366 err:
    367     return -1;
    368 }
    369 
    370 static 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);
    431 err:
    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 
    439 static 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 
    466 static 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 
    474 int 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