Home | History | Annotate | Download | only in sepolicy-analyze
      1 #include <getopt.h>
      2 #include <sepol/policydb/expand.h>
      3 
      4 #include "typecmp.h"
      5 
      6 void typecmp_usage() {
      7     fprintf(stderr, "\ttypecmp [-d|--diff] [-e|--equiv]\n");
      8 }
      9 
     10 static int insert_type_rule(avtab_key_t * k, avtab_datum_t * d,
     11                             struct avtab_node *type_rules)
     12 {
     13     struct avtab_node *p, *c, *n;
     14 
     15     for (p = type_rules, c = type_rules->next; c; p = c, c = c->next) {
     16         /*
     17          * Find the insertion point, keeping the list
     18          * ordered by source type, then target type, then
     19          * target class.
     20          */
     21         if (k->source_type < c->key.source_type)
     22             break;
     23         if (k->source_type == c->key.source_type &&
     24             k->target_type < c->key.target_type)
     25             break;
     26         if (k->source_type == c->key.source_type &&
     27             k->target_type == c->key.target_type &&
     28             k->target_class <= c->key.target_class)
     29             break;
     30     }
     31 
     32     if (c &&
     33         k->source_type == c->key.source_type &&
     34         k->target_type == c->key.target_type &&
     35         k->target_class == c->key.target_class) {
     36         c->datum.data |= d->data;
     37         return 0;
     38     }
     39 
     40     /* Insert the rule */
     41     n = malloc(sizeof(struct avtab_node));
     42     if (!n) {
     43         fprintf(stderr, "out of memory\n");
     44         exit(1);
     45     }
     46 
     47     n->key = *k;
     48     n->datum = *d;
     49     n->next = p->next;
     50     p->next = n;
     51     return 0;
     52 }
     53 
     54 static int create_type_rules_helper(avtab_key_t * k, avtab_datum_t * d,
     55                                     void *args)
     56 {
     57     struct avtab_node *type_rules = args;
     58     avtab_key_t key;
     59 
     60     /*
     61      * Insert the rule into the list for
     62      * the source type.  The source type value
     63      * is cleared as we want to compare against other type
     64      * rules with different source types.
     65      */
     66     key = *k;
     67     key.source_type = 0;
     68     if (k->source_type == k->target_type) {
     69         /* Clear target type as well; this is a self rule. */
     70         key.target_type = 0;
     71     }
     72     if (insert_type_rule(&key, d, &type_rules[k->source_type - 1]))
     73         return -1;
     74 
     75     if (k->source_type == k->target_type)
     76         return 0;
     77 
     78     /*
     79      * If the target type differs, then we also
     80      * insert the rule into the list for the target
     81      * type.  We clear the target type value so that
     82      * we can compare against other type rules with
     83      * different target types.
     84      */
     85     key = *k;
     86     key.target_type = 0;
     87     if (insert_type_rule(&key, d, &type_rules[k->target_type - 1]))
     88         return -1;
     89 
     90     return 0;
     91 }
     92 
     93 static int create_type_rules(avtab_key_t * k, avtab_datum_t * d, void *args)
     94 {
     95     if (k->specified & AVTAB_ALLOWED)
     96         return create_type_rules_helper(k, d, args);
     97     return 0;
     98 }
     99 
    100 static int create_type_rules_cond(avtab_key_t * k, avtab_datum_t * d,
    101                                   void *args)
    102 {
    103     if ((k->specified & (AVTAB_ALLOWED|AVTAB_ENABLED)) ==
    104         (AVTAB_ALLOWED|AVTAB_ENABLED))
    105         return create_type_rules_helper(k, d, args);
    106     return 0;
    107 }
    108 
    109 static void free_type_rules(struct avtab_node *l)
    110 {
    111     struct avtab_node *tmp;
    112 
    113     while (l) {
    114         tmp = l;
    115         l = l->next;
    116         free(tmp);
    117     }
    118 }
    119 
    120 static int find_match(policydb_t *policydb, struct avtab_node *l1,
    121                       int idx1, struct avtab_node *l2, int idx2)
    122 {
    123     struct avtab_node *c;
    124     uint32_t perms1, perms2;
    125 
    126     for (c = l2; c; c = c->next) {
    127         if (l1->key.source_type < c->key.source_type)
    128             break;
    129         if (l1->key.source_type == c->key.source_type &&
    130             l1->key.target_type < c->key.target_type)
    131             break;
    132         if (l1->key.source_type == c->key.source_type &&
    133             l1->key.target_type == c->key.target_type &&
    134             l1->key.target_class <= c->key.target_class)
    135             break;
    136     }
    137 
    138     if (c &&
    139         l1->key.source_type == c->key.source_type &&
    140         l1->key.target_type == c->key.target_type &&
    141         l1->key.target_class == c->key.target_class) {
    142         perms1 = l1->datum.data & ~c->datum.data;
    143         perms2 = c->datum.data & ~l1->datum.data;
    144         if (perms1 || perms2) {
    145             if (perms1)
    146                 display_allow(policydb, &l1->key, idx1, perms1);
    147             if (perms2)
    148                 display_allow(policydb, &c->key, idx2, perms2);
    149             printf("\n");
    150             return 1;
    151         }
    152     }
    153 
    154     return 0;
    155 }
    156 
    157 static int analyze_types(policydb_t * policydb, char diff, char equiv)
    158 {
    159     avtab_t exp_avtab, exp_cond_avtab;
    160     struct avtab_node *type_rules, *l1, *l2;
    161     struct type_datum *type;
    162     size_t i, j;
    163 
    164     /*
    165      * Create a list of access vector rules for each type
    166      * from the access vector table.
    167      */
    168     type_rules = malloc(sizeof(struct avtab_node) * policydb->p_types.nprim);
    169     if (!type_rules) {
    170         fprintf(stderr, "out of memory\n");
    171         exit(1);
    172     }
    173     memset(type_rules, 0, sizeof(struct avtab_node) * policydb->p_types.nprim);
    174 
    175     if (avtab_init(&exp_avtab) || avtab_init(&exp_cond_avtab)) {
    176         fputs("out of memory\n", stderr);
    177         return -1;
    178     }
    179 
    180     if (expand_avtab(policydb, &policydb->te_avtab, &exp_avtab)) {
    181         fputs("out of memory\n", stderr);
    182         avtab_destroy(&exp_avtab);
    183         return -1;
    184     }
    185 
    186     if (expand_avtab(policydb, &policydb->te_cond_avtab, &exp_cond_avtab)) {
    187         fputs("out of memory\n", stderr);
    188         avtab_destroy(&exp_avtab); /*  */
    189         return -1;
    190     }
    191 
    192     if (avtab_map(&exp_avtab, create_type_rules, type_rules))
    193         exit(1);
    194 
    195     if (avtab_map(&exp_cond_avtab, create_type_rules_cond, type_rules))
    196         exit(1);
    197 
    198     avtab_destroy(&exp_avtab);
    199     avtab_destroy(&exp_cond_avtab);
    200 
    201     /*
    202      * Compare the type lists and identify similar types.
    203      */
    204     for (i = 0; i < policydb->p_types.nprim - 1; i++) {
    205         if (!type_rules[i].next)
    206             continue;
    207         type = policydb->type_val_to_struct[i];
    208         if (type->flavor) {
    209             free_type_rules(type_rules[i].next);
    210             type_rules[i].next = NULL;
    211             continue;
    212         }
    213         for (j = i + 1; j < policydb->p_types.nprim; j++) {
    214             type = policydb->type_val_to_struct[j];
    215             if (type->flavor) {
    216                 free_type_rules(type_rules[j].next);
    217                 type_rules[j].next = NULL;
    218                 continue;
    219             }
    220             for (l1 = type_rules[i].next, l2 = type_rules[j].next;
    221                  l1 && l2; l1 = l1->next, l2 = l2->next) {
    222                 if (l1->key.source_type != l2->key.source_type)
    223                     break;
    224                 if (l1->key.target_type != l2->key.target_type)
    225                     break;
    226                 if (l1->key.target_class != l2->key.target_class
    227                     || l1->datum.data != l2->datum.data)
    228                     break;
    229             }
    230             if (l1 || l2) {
    231                 if (diff) {
    232                     printf
    233                         ("Types %s and %s differ, starting with:\n",
    234                          policydb->p_type_val_to_name[i],
    235                          policydb->p_type_val_to_name[j]);
    236 
    237                     if (l1 && l2) {
    238                         if (find_match(policydb, l1, i, l2, j))
    239                             continue;
    240                         if (find_match(policydb, l2, j, l1, i))
    241                             continue;
    242                     }
    243                     if (l1)
    244                         display_allow(policydb, &l1->key, i, l1->datum.data);
    245                     if (l2)
    246                         display_allow(policydb, &l2->key, j, l2->datum.data);
    247                     printf("\n");
    248                 }
    249                 continue;
    250             }
    251             free_type_rules(type_rules[j].next);
    252             type_rules[j].next = NULL;
    253             if (equiv) {
    254                 printf("Types %s and %s are equivalent.\n",
    255                        policydb->p_type_val_to_name[i],
    256                        policydb->p_type_val_to_name[j]);
    257             }
    258         }
    259         free_type_rules(type_rules[i].next);
    260         type_rules[i].next = NULL;
    261     }
    262 
    263     free(type_rules);
    264     return 0;
    265 }
    266 
    267 int typecmp_func (int argc, char **argv, policydb_t *policydb) {
    268     char ch, diff = 0, equiv = 0;
    269 
    270     struct option typecmp_options[] = {
    271         {"diff", no_argument, NULL, 'd'},
    272         {"equiv", no_argument, NULL, 'e'},
    273         {NULL, 0, NULL, 0}
    274     };
    275 
    276     while ((ch = getopt_long(argc, argv, "de", typecmp_options, NULL)) != -1) {
    277         switch (ch) {
    278         case 'd':
    279             diff = 1;
    280             break;
    281         case 'e':
    282             equiv = 1;
    283             break;
    284         default:
    285             USAGE_ERROR = true;
    286             return -1;
    287         }
    288     }
    289 
    290     if (!(diff || equiv)) {
    291         USAGE_ERROR = true;
    292         return -1;
    293     }
    294     return analyze_types(policydb, diff, equiv);
    295 }
    296