1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <sys/types.h>
6 #include <unistd.h>
7
8 #include <arpa/inet.h>
9 #include <netinet/in.h>
10 #ifndef IPPROTO_DCCP
11 #define IPPROTO_DCCP 33
12 #endif
13
14 #include <sepol/policydb/ebitmap.h>
15 #include <sepol/policydb/hashtab.h>
16 #include <sepol/policydb/symtab.h>
17
18 #include "kernel_to_common.h"
19
20
sepol_log_err(const char * fmt,...)21 void sepol_log_err(const char *fmt, ...)
22 {
23 va_list argptr;
24 va_start(argptr, fmt);
25 if (vfprintf(stderr, fmt, argptr) < 0) {
26 _exit(EXIT_FAILURE);
27 }
28 va_end(argptr);
29 if (fprintf(stderr, "\n") < 0) {
30 _exit(EXIT_FAILURE);
31 }
32 }
33
sepol_indent(FILE * out,int indent)34 void sepol_indent(FILE *out, int indent)
35 {
36 if (fprintf(out, "%*s", indent * 4, "") < 0) {
37 sepol_log_err("Failed to write to output");
38 }
39 }
40
sepol_printf(FILE * out,const char * fmt,...)41 void sepol_printf(FILE *out, const char *fmt, ...)
42 {
43 va_list argptr;
44 va_start(argptr, fmt);
45 if (vfprintf(out, fmt, argptr) < 0) {
46 sepol_log_err("Failed to write to output");
47 }
48 va_end(argptr);
49 }
50
51 __attribute__ ((format(printf, 1, 0)))
create_str_helper(const char * fmt,int num,va_list vargs)52 static char *create_str_helper(const char *fmt, int num, va_list vargs)
53 {
54 va_list vargs2;
55 char *str = NULL;
56 char *s;
57 size_t len;
58 int i, rc;
59
60 va_copy(vargs2, vargs);
61
62 len = strlen(fmt) + 1; /* +1 for '\0' */
63
64 for (i=0; i<num; i++) {
65 s = va_arg(vargs, char *);
66 len += strlen(s) - 2; /* -2 for each %s in fmt */
67 }
68
69 str = malloc(len);
70 if (!str) {
71 sepol_log_err("Out of memory");
72 goto exit;
73 }
74
75 rc = vsnprintf(str, len, fmt, vargs2);
76 if (rc < 0 || rc >= (int)len) {
77 goto exit;
78 }
79
80 return str;
81
82 exit:
83 free(str);
84 return NULL;
85 }
86
create_str(const char * fmt,int num,...)87 char *create_str(const char *fmt, int num, ...)
88 {
89 char *str = NULL;
90 va_list vargs;
91
92 va_start(vargs, num);
93 str = create_str_helper(fmt, num, vargs);
94 va_end(vargs);
95
96 return str;
97 }
98
strs_init(struct strs ** strs,size_t size)99 int strs_init(struct strs **strs, size_t size)
100 {
101 struct strs *new;
102
103 *strs = NULL;
104
105 new = malloc(sizeof(struct strs));
106 if (!new) {
107 sepol_log_err("Out of memory");
108 return -1;
109 }
110
111 new->list = calloc(sizeof(char *), size);
112 if (!new->list) {
113 sepol_log_err("Out of memory");
114 free(new);
115 return -1;
116 }
117
118 new->num = 0;
119 new->size = size;
120
121 *strs = new;
122
123 return 0;
124 }
125
strs_destroy(struct strs ** strs)126 void strs_destroy(struct strs **strs)
127 {
128 if (!strs || !*strs) {
129 return;
130 }
131
132 free((*strs)->list);
133 (*strs)->list = NULL;
134 (*strs)->num = 0;
135 (*strs)->size = 0;
136 free(*strs);
137 *strs = NULL;
138 }
139
strs_free_all(struct strs * strs)140 void strs_free_all(struct strs *strs)
141 {
142 if (!strs) {
143 return;
144 }
145
146 while (strs->num > 0) {
147 strs->num--;
148 free(strs->list[strs->num]);
149 }
150 }
151
strs_add(struct strs * strs,char * s)152 int strs_add(struct strs *strs, char *s)
153 {
154 if (strs->num + 1 > strs->size) {
155 char **new;
156 unsigned i = strs->size;
157 strs->size *= 2;
158 new = realloc(strs->list, sizeof(char *)*strs->size);
159 if (!new) {
160 sepol_log_err("Out of memory");
161 return -1;
162 }
163 strs->list = new;
164 memset(&strs->list[i], 0, sizeof(char *)*(strs->size-i));
165 }
166
167 strs->list[strs->num] = s;
168 strs->num++;
169
170 return 0;
171 }
172
strs_create_and_add(struct strs * strs,const char * fmt,int num,...)173 int strs_create_and_add(struct strs *strs, const char *fmt, int num, ...)
174 {
175 char *str;
176 va_list vargs;
177 int rc;
178
179 va_start(vargs, num);
180 str = create_str_helper(fmt, num, vargs);
181 va_end(vargs);
182
183 if (!str) {
184 rc = -1;
185 goto exit;
186 }
187
188 rc = strs_add(strs, str);
189 if (rc != 0) {
190 free(str);
191 goto exit;
192 }
193
194 return 0;
195
196 exit:
197 return rc;
198 }
199
strs_remove_last(struct strs * strs)200 char *strs_remove_last(struct strs *strs)
201 {
202 if (strs->num == 0) {
203 return NULL;
204 }
205 strs->num--;
206 return strs->list[strs->num];
207 }
208
strs_add_at_index(struct strs * strs,char * s,unsigned index)209 int strs_add_at_index(struct strs *strs, char *s, unsigned index)
210 {
211 if (index >= strs->size) {
212 char **new;
213 unsigned i = strs->size;
214 while (index >= strs->size) {
215 strs->size *= 2;
216 }
217 new = realloc(strs->list, sizeof(char *)*strs->size);
218 if (!new) {
219 sepol_log_err("Out of memory");
220 return -1;
221 }
222 strs->list = new;
223 memset(&strs->list[i], 0, sizeof(char *)*(strs->size - i));
224 }
225
226 strs->list[index] = s;
227 if (index >= strs->num) {
228 strs->num = index+1;
229 }
230
231 return 0;
232 }
233
strs_read_at_index(struct strs * strs,unsigned index)234 char *strs_read_at_index(struct strs *strs, unsigned index)
235 {
236 if (index >= strs->num) {
237 return NULL;
238 }
239
240 return strs->list[index];
241 }
242
strs_cmp(const void * a,const void * b)243 static int strs_cmp(const void *a, const void *b)
244 {
245 char *const *aa = a;
246 char *const *bb = b;
247 return strcmp(*aa,*bb);
248 }
249
strs_sort(struct strs * strs)250 void strs_sort(struct strs *strs)
251 {
252 if (strs->num == 0) {
253 return;
254 }
255 qsort(strs->list, strs->num, sizeof(char *), strs_cmp);
256 }
257
strs_num_items(struct strs * strs)258 unsigned strs_num_items(struct strs *strs)
259 {
260 return strs->num;
261 }
262
strs_len_items(struct strs * strs)263 size_t strs_len_items(struct strs *strs)
264 {
265 unsigned i;
266 size_t len = 0;
267
268 for (i=0; i<strs->num; i++) {
269 if (!strs->list[i]) continue;
270 len += strlen(strs->list[i]);
271 }
272
273 return len;
274 }
275
strs_to_str(struct strs * strs)276 char *strs_to_str(struct strs *strs)
277 {
278 char *str = NULL;
279 size_t len = 0;
280 char *p;
281 unsigned i;
282 int rc;
283
284 if (strs->num == 0) {
285 goto exit;
286 }
287
288 /* strs->num added because either ' ' or '\0' follows each item */
289 len = strs_len_items(strs) + strs->num;
290 str = malloc(len);
291 if (!str) {
292 sepol_log_err("Out of memory");
293 goto exit;
294 }
295
296 p = str;
297 for (i=0; i<strs->num; i++) {
298 if (!strs->list[i]) continue;
299 len = strlen(strs->list[i]);
300 rc = snprintf(p, len+1, "%s", strs->list[i]);
301 if (rc < 0 || rc > (int)len) {
302 free(str);
303 str = NULL;
304 goto exit;
305 }
306 p += len;
307 if (i < strs->num - 1) {
308 *p++ = ' ';
309 }
310 }
311
312 *p = '\0';
313
314 exit:
315 return str;
316 }
317
strs_write_each(struct strs * strs,FILE * out)318 void strs_write_each(struct strs *strs, FILE *out)
319 {
320 unsigned i;
321
322 for (i=0; i<strs->num; i++) {
323 if (!strs->list[i]) {
324 continue;
325 }
326 sepol_printf(out, "%s\n",strs->list[i]);
327 }
328 }
329
strs_write_each_indented(struct strs * strs,FILE * out,int indent)330 void strs_write_each_indented(struct strs *strs, FILE *out, int indent)
331 {
332 unsigned i;
333
334 for (i=0; i<strs->num; i++) {
335 if (!strs->list[i]) {
336 continue;
337 }
338 sepol_indent(out, indent);
339 sepol_printf(out, "%s\n",strs->list[i]);
340 }
341 }
342
hashtab_ordered_to_strs(char * key,void * data,void * args)343 int hashtab_ordered_to_strs(char *key, void *data, void *args)
344 {
345 struct strs *strs = (struct strs *)args;
346 symtab_datum_t *datum = data;
347
348 return strs_add_at_index(strs, key, datum->value-1);
349 }
350
ebitmap_to_strs(struct ebitmap * map,struct strs * strs,char ** val_to_name)351 int ebitmap_to_strs(struct ebitmap *map, struct strs *strs, char **val_to_name)
352 {
353 struct ebitmap_node *node;
354 uint32_t i;
355 int rc;
356
357 ebitmap_for_each_bit(map, node, i) {
358 if (!ebitmap_get_bit(map, i)) continue;
359
360 rc = strs_add(strs, val_to_name[i]);
361 if (rc != 0) {
362 return -1;
363 }
364 }
365
366 return 0;
367 }
368
ebitmap_to_str(struct ebitmap * map,char ** val_to_name,int sort)369 char *ebitmap_to_str(struct ebitmap *map, char **val_to_name, int sort)
370 {
371 struct strs *strs;
372 char *str = NULL;
373 int rc;
374
375 rc = strs_init(&strs, 32);
376 if (rc != 0) {
377 goto exit;
378 }
379
380 rc = ebitmap_to_strs(map, strs, val_to_name);
381 if (rc != 0) {
382 goto exit;
383 }
384
385 if (sort) {
386 strs_sort(strs);
387 }
388
389 str = strs_to_str(strs);
390
391 exit:
392 strs_destroy(&strs);
393
394 return str;
395 }
396
stack_init(struct strs ** stack)397 int stack_init(struct strs **stack)
398 {
399 return strs_init(stack, STACK_SIZE);
400 }
401
stack_destroy(struct strs ** stack)402 void stack_destroy(struct strs **stack)
403 {
404 return strs_destroy(stack);
405 }
406
stack_push(struct strs * stack,char * s)407 int stack_push(struct strs *stack, char *s)
408 {
409 return strs_add(stack, s);
410 }
411
stack_pop(struct strs * stack)412 char *stack_pop(struct strs *stack)
413 {
414 return strs_remove_last(stack);
415 }
416
stack_empty(struct strs * stack)417 int stack_empty(struct strs *stack)
418 {
419 return strs_num_items(stack) == 0;
420 }
421
compare_ranges(uint64_t l1,uint64_t h1,uint64_t l2,uint64_t h2)422 static int compare_ranges(uint64_t l1, uint64_t h1, uint64_t l2, uint64_t h2)
423 {
424 uint64_t d1, d2;
425
426 d1 = h1-l1;
427 d2 = h2-l2;
428
429 if (d1 < d2) {
430 return -1;
431 } else if (d1 > d2) {
432 return 1;
433 } else {
434 if (l1 < l2) {
435 return -1;
436 } else if (l1 > l2) {
437 return 1;
438 }
439 }
440
441 return 0;
442 }
443
fsuse_data_cmp(const void * a,const void * b)444 static int fsuse_data_cmp(const void *a, const void *b)
445 {
446 struct ocontext *const *aa = a;
447 struct ocontext *const *bb = b;
448
449 if ((*aa)->v.behavior != (*bb)->v.behavior) {
450 if ((*aa)->v.behavior < (*bb)->v.behavior) {
451 return -1;
452 } else {
453 return 1;
454 }
455 }
456
457 return strcmp((*aa)->u.name, (*bb)->u.name);
458 }
459
portcon_data_cmp(const void * a,const void * b)460 static int portcon_data_cmp(const void *a, const void *b)
461 {
462 struct ocontext *const *aa = a;
463 struct ocontext *const *bb = b;
464 int rc;
465
466 rc = compare_ranges((*aa)->u.port.low_port, (*aa)->u.port.high_port,
467 (*bb)->u.port.low_port, (*bb)->u.port.high_port);
468 if (rc == 0) {
469 if ((*aa)->u.port.protocol == (*bb)->u.port.protocol) {
470 rc = 0;
471 } else if ((*aa)->u.port.protocol == IPPROTO_TCP) {
472 rc = -1;
473 } else {
474 rc = 1;
475 }
476 }
477
478 return rc;
479 }
480
netif_data_cmp(const void * a,const void * b)481 static int netif_data_cmp(const void *a, const void *b)
482 {
483 struct ocontext *const *aa = a;
484 struct ocontext *const *bb = b;
485
486 return strcmp((*aa)->u.name, (*bb)->u.name);
487 }
488
node_data_cmp(const void * a,const void * b)489 static int node_data_cmp(const void *a, const void *b)
490 {
491 struct ocontext *const *aa = a;
492 struct ocontext *const *bb = b;
493 int rc;
494
495 rc = memcmp(&(*aa)->u.node.mask, &(*bb)->u.node.mask, sizeof((*aa)->u.node.mask));
496 if (rc > 0) {
497 return -1;
498 } else if (rc < 0) {
499 return 1;
500 }
501
502 return memcmp(&(*aa)->u.node.addr, &(*bb)->u.node.addr, sizeof((*aa)->u.node.addr));
503 }
504
node6_data_cmp(const void * a,const void * b)505 static int node6_data_cmp(const void *a, const void *b)
506 {
507 struct ocontext *const *aa = a;
508 struct ocontext *const *bb = b;
509 int rc;
510
511 rc = memcmp(&(*aa)->u.node6.mask, &(*bb)->u.node6.mask, sizeof((*aa)->u.node6.mask));
512 if (rc > 0) {
513 return -1;
514 } else if (rc < 0) {
515 return 1;
516 }
517
518 return memcmp(&(*aa)->u.node6.addr, &(*bb)->u.node6.addr, sizeof((*aa)->u.node6.addr));
519 }
520
pirq_data_cmp(const void * a,const void * b)521 static int pirq_data_cmp(const void *a, const void *b)
522 {
523 struct ocontext *const *aa = a;
524 struct ocontext *const *bb = b;
525
526 if ((*aa)->u.pirq < (*bb)->u.pirq) {
527 return -1;
528 } else if ((*aa)->u.pirq > (*bb)->u.pirq) {
529 return 1;
530 }
531
532 return 0;
533 }
534
ioport_data_cmp(const void * a,const void * b)535 static int ioport_data_cmp(const void *a, const void *b)
536 {
537 struct ocontext *const *aa = a;
538 struct ocontext *const *bb = b;
539
540 return compare_ranges((*aa)->u.ioport.low_ioport, (*aa)->u.ioport.high_ioport,
541 (*bb)->u.ioport.low_ioport, (*bb)->u.ioport.high_ioport);
542 }
543
iomem_data_cmp(const void * a,const void * b)544 static int iomem_data_cmp(const void *a, const void *b)
545 {
546 struct ocontext *const *aa = a;
547 struct ocontext *const *bb = b;
548
549 return compare_ranges((*aa)->u.iomem.low_iomem, (*aa)->u.iomem.high_iomem,
550 (*bb)->u.iomem.low_iomem, (*bb)->u.iomem.high_iomem);
551 }
552
pcid_data_cmp(const void * a,const void * b)553 static int pcid_data_cmp(const void *a, const void *b)
554 {
555 struct ocontext *const *aa = a;
556 struct ocontext *const *bb = b;
557
558 if ((*aa)->u.device < (*bb)->u.device) {
559 return -1;
560 } else if ((*aa)->u.device > (*bb)->u.device) {
561 return 1;
562 }
563
564 return 0;
565 }
566
dtree_data_cmp(const void * a,const void * b)567 static int dtree_data_cmp(const void *a, const void *b)
568 {
569 struct ocontext *const *aa = a;
570 struct ocontext *const *bb = b;
571
572 return strcmp((*aa)->u.name, (*bb)->u.name);
573 }
574
sort_ocontext_data(struct ocontext ** ocons,int (* cmp)(const void *,const void *))575 static int sort_ocontext_data(struct ocontext **ocons, int (*cmp)(const void *, const void *))
576 {
577 struct ocontext *ocon;
578 struct ocontext **data;
579 unsigned i, num;
580
581 num = 0;
582 for (ocon = *ocons; ocon != NULL; ocon = ocon->next) {
583 num++;
584 }
585
586 if (num == 0) {
587 return 0;
588 }
589
590 data = calloc(sizeof(*data), num);
591 if (!data) {
592 sepol_log_err("Out of memory\n");
593 return -1;
594 }
595
596 i = 0;
597 for (ocon = *ocons; ocon != NULL; ocon = ocon->next) {
598 data[i] = ocon;
599 i++;
600 }
601
602 qsort(data, num, sizeof(*data), cmp);
603
604 *ocons = data[0];
605 for (i=1; i < num; i++) {
606 data[i-1]->next = data[i];
607 }
608 data[num-1]->next = NULL;
609
610 free(data);
611
612 return 0;
613 }
614
sort_ocontexts(struct policydb * pdb)615 int sort_ocontexts(struct policydb *pdb)
616 {
617 int rc = 0;
618
619 if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
620 rc = sort_ocontext_data(&pdb->ocontexts[5], fsuse_data_cmp);
621 if (rc != 0) {
622 goto exit;
623 }
624
625 rc = sort_ocontext_data(&pdb->ocontexts[2], portcon_data_cmp);
626 if (rc != 0) {
627 goto exit;
628 }
629
630 rc = sort_ocontext_data(&pdb->ocontexts[3], netif_data_cmp);
631 if (rc != 0) {
632 goto exit;
633 }
634
635 rc = sort_ocontext_data(&pdb->ocontexts[4], node_data_cmp);
636 if (rc != 0) {
637 goto exit;
638 }
639
640 rc = sort_ocontext_data(&pdb->ocontexts[6], node6_data_cmp);
641 if (rc != 0) {
642 goto exit;
643 }
644 } else if (pdb->target_platform == SEPOL_TARGET_XEN) {
645 rc = sort_ocontext_data(&pdb->ocontexts[1], pirq_data_cmp);
646 if (rc != 0) {
647 goto exit;
648 }
649
650 rc = sort_ocontext_data(&pdb->ocontexts[2], ioport_data_cmp);
651 if (rc != 0) {
652 goto exit;
653 }
654
655 rc = sort_ocontext_data(&pdb->ocontexts[3], iomem_data_cmp);
656 if (rc != 0) {
657 goto exit;
658 }
659
660 rc = sort_ocontext_data(&pdb->ocontexts[4], pcid_data_cmp);
661 if (rc != 0) {
662 goto exit;
663 }
664
665 rc = sort_ocontext_data(&pdb->ocontexts[5], dtree_data_cmp);
666 if (rc != 0) {
667 goto exit;
668 }
669 }
670
671 exit:
672 if (rc != 0) {
673 sepol_log_err("Error sorting ocontexts\n");
674 }
675
676 return rc;
677 }
678