1 #include <getopt.h>
2 #include <sepol/policydb/expand.h>
3 
4 #include "typecmp.h"
5 
typecmp_usage()6 void typecmp_usage() {
7     fprintf(stderr, "\ttypecmp [-d|--diff] [-e|--equiv]\n");
8 }
9 
insert_type_rule(avtab_key_t * k,avtab_datum_t * d,struct avtab_node * type_rules)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 
create_type_rules_helper(avtab_key_t * k,avtab_datum_t * d,void * args)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 
create_type_rules(avtab_key_t * k,avtab_datum_t * d,void * args)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 
create_type_rules_cond(avtab_key_t * k,avtab_datum_t * d,void * args)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 
free_type_rules(struct avtab_node * l)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 
find_match(policydb_t * policydb,struct avtab_node * l1,int idx1,struct avtab_node * l2,int idx2)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 
analyze_types(policydb_t * policydb,char diff,char equiv)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 
typecmp_func(int argc,char ** argv,policydb_t * policydb)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